Compare commits

..

116 Commits

Author SHA1 Message Date
Imran
f00758cd83 Merge pull request #1774 from ImranR98/dev
- Fix bug introduced in v1.1.16: APKPure fails to find universal APKs
- Fix bugs found in APKPure URL matching
2024-08-06 11:47:56 -04:00
Imran
25bd61f289 Merge pull request #1773 from Kevinr99089/main
Updating certain words (French File)
2024-08-06 11:46:46 -04:00
Imran Remtulla
25d19d22cf Increment version 2024-08-06 11:46:25 -04:00
Imran Remtulla
9ffb91266f Re-order some sources 2024-08-06 11:45:49 -04:00
Imran Remtulla
8d921cfbf1 Fix bugs in APKPure URL matching 2024-08-06 11:45:01 -04:00
Imran Remtulla
3ed6b168e1 Fix bug from previous version: APKPure fails to find universal APKs 2024-08-06 11:36:39 -04:00
Kévin
4a45c900c3 Some minor corrections
- A job well done is the key (of I don't know what, but it's the key...)
2024-08-06 01:50:03 +02:00
Imran
7e9e6958a3 Merge pull request #1771 from Kevinr99089/main
French translation completely revised
2024-08-05 18:01:02 -04:00
Kévin
9de082f684 Last modification before PR 2024-08-05 23:38:41 +02:00
Kévin
b40afc7329 Add files via upload 2024-08-05 23:32:32 +02:00
Imran
4fb3da45e9 Merge pull request #1770 from ImranR98/dev
- APKPure: Filter releases by available architecture (#598)
- Use a more obvious icon (magnifying glass) for the "filter apps" button (#1762)
2024-08-05 16:33:29 -04:00
Imran Remtulla
1f8e051ed6 Merge remote-tracking branch 'origin/main' into dev 2024-08-05 16:31:15 -04:00
Imran Remtulla
adc4e7c2b4 Fix error after fgbg package update in previous commit 2024-08-05 16:30:12 -04:00
Imran Remtulla
325d2f48dc More consistent tagline 2024-08-05 16:25:02 -04:00
Imran Remtulla
aa00f42a23 Update packages, increment version 2024-08-05 16:24:30 -04:00
Imran Remtulla
62dbffab52 Use a more obvious icon (magnifying glass) for the "filter apps" button (#1762) 2024-08-05 16:21:42 -04:00
Imran Remtulla
fd38444836 Improvement on previous commit 2024-08-05 16:08:12 -04:00
Imran Remtulla
71cc49a30f APKPure: Filter releases by available architecture (#598) 2024-08-05 15:53:44 -04:00
Imran
e4187c8e17 Merge pull request #1755 from ImranR98/dev
Update GitLab for new uploads URL scheme (#1742), Ability to share selective exports (#1752)
2024-07-28 17:28:53 -04:00
Imran Remtulla
15ae98d426 Update Flutter + packages, increment version 2024-07-28 17:27:18 -04:00
Imran Remtulla
7b4fa2269e Merge remote-tracking branch 'origin/main' into dev 2024-07-28 17:25:02 -04:00
Imran
656e14793d Merge pull request #1748 from asandikci/main
translate: update turkish
2024-07-28 17:24:41 -04:00
Imran
d23381147b Merge pull request #1746 from bluefly000/japanese-translation
Update ja.json
2024-07-28 17:24:33 -04:00
Imran
cfe184c6d5 Merge pull request #1749 from VladWinner/main
Change the font (support for more languages)
2024-07-28 17:20:21 -04:00
Imran Remtulla
9c16f24a08 Ability to share selective exports (#1752) 2024-07-28 17:18:36 -04:00
Imran Remtulla
ce200403e0 Update GitLab for new uploads URL scheme (#1742) 2024-07-28 16:41:01 -04:00
Vlad Loktionov
caca84f84d Change the font (support for more languages) 2024-07-26 01:18:14 +03:00
Aliberk Sandıkçı
ac2d7b9639 translate: update turkish 2024-07-24 20:02:57 +03:00
bluefly000
78069a9b26 Update ja.json 2024-07-24 14:35:05 +09:00
Imran
3e23fffaea Merge pull request #1725 from ImranR98/dev
- Attempt bugfix for error when on VPN (#1120)
- Translation fixes (#1699)
- GitHub search bugfix (#1705)
- Fix missing trailing slash for path-less URLs (#1715)
- Rename Codeberg to Forgejo (#1722)
- Rename "Version String Extraction" to "Trim Version String" for non-HTML Sources (#1723)
2024-07-14 20:56:22 -04:00
Imran Remtulla
624b9fb6dc Update packages, increment version 2024-07-14 20:50:48 -04:00
Imran Remtulla
fbd6189721 GitHub search bugfix (#1705) 2024-07-14 20:42:20 -04:00
Imran Remtulla
6a44fe227c Fix missing trailing slash for path-less URLs (#1715) 2024-07-14 20:27:42 -04:00
Imran Remtulla
d1cb2688c6 Rename "Version String Extraction" to "Trim Version String" for non-HTML Sources (#1723)
Rename Codeberg to Forgejo (#1722)
2024-07-14 20:20:41 -04:00
Imran
b43b2f9740 Merge pull request #1720 from Erudaro/main
Update bs.json
2024-07-14 02:08:43 -04:00
Imran
6288a9cb8d Merge pull request #1710 from DwainZwerg/for-eXense-auth-Update-ru.json-see-#1703](https/github.com/ImranR98/Obtainium/issues/1703)
for eXense-auth: Update ru.json (issue#1703)
2024-07-14 02:08:31 -04:00
Erudaro
18c6f75054 Update bs.json 2024-07-13 23:56:33 +00:00
DwainZwerg
1f8d187b84 Update ru.json
see [#1703](https://github.com/ImranR98/Obtainium/issues/1703)
2024-07-07 12:13:07 +02:00
Imran Remtulla
77618ad1ff Merge remote-tracking branch 'origin/main' into dev 2024-06-30 13:02:43 -04:00
Imran
75efd335e9 Update release.yml 2024-06-30 12:56:28 -04:00
Imran
c4438de200 Update release.yml 2024-06-30 12:55:38 -04:00
Imran Remtulla
e3c9a227d3 Translation fixes 2024-06-29 17:04:34 -04:00
Imran Remtulla
548f859349 Merge remote-tracking branch 'origin/main' into dev 2024-06-29 16:49:16 -04:00
Imran Remtulla
db413badec Attempt bugfix for error when on VPN (#1120) 2024-06-29 16:48:59 -04:00
Imran
dfac3af3f5 Merge pull request #1698 from ImranR98/dev
Bugfix for files with vague 'content-disposition' header (#1697)
2024-06-29 03:03:36 -04:00
Imran Remtulla
5eceaeecde Increment version, run dart fix 2024-06-29 03:02:56 -04:00
Imran Remtulla
62c23004f7 Bugfix for files with vague 'content-disposition' header (#1697) 2024-06-29 03:01:48 -04:00
Imran
cd153e7d11 Merge pull request #1696 from ImranR98/dev
- Bugfix: Pull to refresh not working with few apps (#1680)
- Add third-party F-Droid repo search to main search menu (#1681)
- Added autocomplete for F-Droid repos (#1681)
- Bugfix: Missing request headers for direct APK link apps (#1688)
- Release asset download confirmation even for single choice (#1694)
- Add a less obvious touch target to highlights (#1694)
2024-06-28 23:03:14 -04:00
Imran Remtulla
3b494511d7 Merge remote-tracking branch 'origin/main' into dev 2024-06-28 22:54:15 -04:00
Imran
6c806a44d4 Merge pull request #1676 from abc0922001/patch-1
add Traditional Chinese translation
2024-06-28 22:54:01 -04:00
Imran
c5bac43bfd Merge pull request #1673 from AntoninDelFabbro/patch-1
(following d8c805a + #1670) Undone a mistake
2024-06-28 22:53:52 -04:00
Imran
1636281d6d Merge pull request #1674 from catsnote/main
Improved Danish Translation
2024-06-28 22:53:46 -04:00
Imran
0f4feb2da6 Merge pull request #1682 from CertainBot/patch-4
Update es.json
2024-06-28 22:53:23 -04:00
Imran Remtulla
c32f34c116 Update packages, increment version 2024-06-28 22:52:24 -04:00
Imran Remtulla
d391c5cfc2 Bugfix: Missing request headers for direct APK link apps (#1688) 2024-06-28 22:50:43 -04:00
Imran Remtulla
bb45a157b3 Add a less obvious touch target to highlights (#1694) 2024-06-28 22:29:34 -04:00
Imran Remtulla
c90a571f89 Release asset download confirmation even for single choice (#1694) 2024-06-28 22:12:45 -04:00
Imran Remtulla
1278407c90 Slight spacing change 2024-06-28 22:04:21 -04:00
Imran Remtulla
dff1b4cf39 Bugfixes for F-Droid repo search (#1681) 2024-06-28 21:55:13 -04:00
Imran Remtulla
105e70a814 F-Droid repo search bugfix (#1681) 2024-06-28 21:28:02 -04:00
Imran Remtulla
2938cea419 Added autocomplete for F-Droid repos (#1681) 2024-06-28 21:03:53 -04:00
Imran Remtulla
9b6b7780d8 Fix F-Droid repo search bugs (#1681) 2024-06-28 20:11:43 -04:00
Imran Remtulla
f53a4f3827 Add third-party F-Droid repo search to main search menu (#1681) 2024-06-28 19:10:45 -04:00
Imran Remtulla
9b0d672553 Bugfix: Pull to refresh not working with few apps (#1680) 2024-06-28 18:51:02 -04:00
CertainBot
9d14145ac2 Update es.json
- English: corrected a few typos and wrong translations
- Español: corregidas faltas y errores de traducción
2024-06-19 19:31:58 +00:00
abc0922001
9948797b25 Create zh-TW.json
add Traditional Chinese translation
2024-06-17 13:08:26 +08:00
cat
a80d9e3623 Improved assets/translations/da.json 2024-06-16 20:22:03 +02:00
Antonin Del Fabbro
37ecb057f9 Undone a mistake 2024-06-15 22:19:42 +02:00
Imran
06cbe74c6c Merge pull request #1672 from ImranR98/dev
- Add release date extraction for track-only GitLab and Codeberg apps (#1664)
- Add a scrollbar to the apps page
2024-06-15 02:00:30 -04:00
Imran Remtulla
f5769b85fe Add release date extraction for track-only GitLab and Codeberg apps (#1664) 2024-06-15 01:58:07 -04:00
Imran Remtulla
875868af47 Added DA to the language menu 2024-06-15 01:21:31 -04:00
Imran Remtulla
24ea15d600 Merge remote-tracking branch 'origin/main' into dev 2024-06-15 01:20:23 -04:00
Imran
87cdc3dcef Merge pull request #1657 from Grooty12/main
Add da.json
2024-06-15 01:20:01 -04:00
Imran
c2f976d7f4 Merge pull request #1670 from AntoninDelFabbro/patch-1
Reworked french translation
2024-06-15 01:19:50 -04:00
Imran Remtulla
ebc46bfd3f Update Flutter submodule 2024-06-15 01:19:33 -04:00
Imran Remtulla
e674f7e89d Merge remote-tracking branch 'origin/main' into dev 2024-06-15 01:19:13 -04:00
Imran Remtulla
86d29b163c Update packages, increment version 2024-06-15 01:19:06 -04:00
Imran Remtulla
a849919799 Add a scrollbar to the apps page 2024-06-15 01:18:50 -04:00
Antonin Del Fabbro
d8c805a6b3 Reworked french translation 2024-06-12 23:07:57 +02:00
Antonin Del Fabbro
8acbd3ef78 "Material You" shouldn't be translated 2024-06-12 20:43:50 +02:00
Rasmus Rosendahl-Kaa
b81088d767 Add danish translation 2024-06-05 14:33:22 +02:00
Imran
7071e34a74 Merge pull request #1643 from ImranR98/dev
- Bugfix: Include GitLab token in APK request (#1622)
- Bugfix: Don't trim trailing slashes when parsing links (#1625)
- Improve contrast of placeholder icon in dark mode (#1637) 
- Improve app loading times
- Revert a previous change to background downloads
- Add a "clear logs" button
2024-05-24 16:27:18 -04:00
Imran Remtulla
6a73ade359 Add a "clear logs" button 2024-05-23 21:18:13 -04:00
Imran Remtulla
6c5e5043a4 Improve icon loading after last commit 2024-05-23 21:02:50 -04:00
Imran Remtulla
5edaf1306d Update packages + Flutter, increment version 2024-05-23 20:17:44 -04:00
Imran Remtulla
5bf7fdb94e Revert a previous change related to BG downloads (did not work as intended) 2024-05-23 20:15:25 -04:00
Imran Remtulla
7808bc5ccb Improve loading time/stability (at the cost of icon flickering) 2024-05-23 20:02:43 -04:00
Imran Remtulla
06a079e452 Attempt to improve load times again + link parsing bugfix (#1625) 2024-05-23 19:35:52 -04:00
Imran Remtulla
de509737e6 Include GitLab token in APK request (#1622) 2024-05-22 19:51:35 -04:00
Imran Remtulla
08a3ba8d13 Merge remote-tracking branch 'origin/main' into dev 2024-05-22 19:37:30 -04:00
Imran
2b27902d5f Merge pull request #1633 from teaminh/main
Update vi.json
2024-05-22 19:37:16 -04:00
Imran Remtulla
62185127c2 Merge remote-tracking branch 'origin/main' into dev 2024-05-22 19:36:53 -04:00
Imran Remtulla
9c46e3f88c Attempt to improve app load time
Slight icon opacity tweak (#1637)
2024-05-22 19:35:51 -04:00
teaminh
daa4de921d Update vi.json 2024-05-19 12:20:28 +07:00
teaminh
bc977e2a5a Update vi.json 2024-05-19 12:09:36 +07:00
Imran
1e3815ca20 Merge pull request #1631 from ImranR98/dev
- Don't use partial downloads for BG tasks (more reliable)
- More accurate error reports for Huawei AppGallery fails
- Various bugfixes
- Update Flutter
2024-05-17 22:35:12 -04:00
Imran Remtulla
0e2fa96b9f More accurate error reports for Huawei AppGallery fails 2024-05-17 16:17:51 -04:00
Imran Remtulla
389aebe54e Various bugfixes 2024-05-17 15:56:41 -04:00
Imran Remtulla
fbfeaf2a91 Update Flutter, packages, increment version 2024-05-16 22:31:21 -04:00
Imran Remtulla
485812d076 Merge remote-tracking branch 'origin/main' into dev 2024-05-16 22:21:58 -04:00
Imran Remtulla
68e98ec719 Don't use partial downloads for BG tasks (more reliable) 2024-05-16 22:21:52 -04:00
Imran
cbe41de734 Merge pull request #1620 from mxhdee/main
Update fa.json
2024-05-16 22:11:23 -04:00
Mxhdee
abb8641105 Update fa.json 2024-05-13 18:46:01 -04:00
Imran
dbcb4b3c09 Merge pull request #1619 from ImranR98/dev
- Bugfix: Get initial data on config import
- Bugfix: Include overrideSource in exported config
2024-05-12 20:47:51 -04:00
Imran Remtulla
b231c756e6 Increment version, update packages 2024-05-12 20:47:06 -04:00
Imran Remtulla
3cb3f7fdd4 Merge remote-tracking branch 'origin/main' into dev 2024-05-12 20:45:34 -04:00
Imran
9837e8e325 Merge pull request #1608 from ArcticFoxPro/main
Update zh.json
2024-05-12 20:45:21 -04:00
Imran
73d4814f18 Merge pull request #1616 from KoolTechTricks/patch-1
Update ru.json
2024-05-12 20:45:04 -04:00
Imran
0a9219c314 Merge pull request #1618 from GitGitro/main
Enable per-app language, closes #1430
2024-05-12 20:44:55 -04:00
Imran Remtulla
56c5a73d9a Bugfix: Get initial data on config import 2024-05-12 20:41:53 -04:00
Imran Remtulla
a30e063246 Bugfix: Include overrideSource in exported config 2024-05-12 20:12:02 -04:00
GitGitro
bd26b6514a Enable per-app language, closes #1430 2024-05-12 18:07:35 +02:00
Kool Tech Tricks
3ea8c7e888 Update ru.json
Fix incorrect machine translated strings
2024-05-11 21:26:42 +05:00
有鲫雪狐
5f2ec5ce6f Update zh.json 2024-05-07 08:12:17 +08:00
ArcticFoxPro
783ce9d555 Update zh.json
`trackOnlyInBrackets`、`searchableInBrackets`:更正半角标点为全角
`enableBackgroundUpdates`:改为“启用全局后台更新”突出全局性
`exemptFromBackgroundUpdates`:“仅此应用生效,即使已启用全局后台更新”更明确了选项条件
`shizukuPretendToBeGooglePlay`:Google Play 不是确定的字符串,在这里指代了 Play Store 实体,无需双引号。
`useLatestAssetDateAsReleaseDate`:英文 Latest 通常在简体中文对应“最新”而非“最近”。
2024-05-06 19:12:38 +08:00
ArcticFoxPro
a719b2475b Update zh.json 2024-05-06 13:21:08 +08:00
50 changed files with 2182 additions and 859 deletions

View File

@@ -6,6 +6,9 @@ on:
beta: beta:
type: boolean type: boolean
description: Is beta? description: Is beta?
draft:
type: boolean
description: Is draft?
jobs: jobs:
build: build:
@@ -35,13 +38,7 @@ jobs:
- name: Check submodule - name: Check submodule
id: check_submodule id: check_submodule
run: | run: |
SUBMODULE_COMMIT_LONG="$(git submodule status | head -1 | tail -c +2 | awk '{print $1}')" git checkout ${{ inputs.checkout }}
FLUTTER_COMMIT_SHORT="$(flutter --version | head -2 | tail -1 | awk '{print $4}')"
echo "SUBMODULE_COMMIT_LONG=$SUBMODULE_COMMIT_LONG, FLUTTER_COMMIT_SHORT=$FLUTTER_COMMIT_SHORT"
if ! [[ "$SUBMODULE_COMMIT_LONG" =~ ^$FLUTTER_COMMIT_SHORT ]]; then
echo "Your submodule has not been updated!"
exit 1
fi
- name: Extract Version - name: Extract Version
id: extract_version id: extract_version
@@ -92,5 +89,6 @@ jobs:
token: ${{ secrets.GH_ACCESS_TOKEN }} token: ${{ secrets.GH_ACCESS_TOKEN }}
tag: "${{ steps.extract_version.outputs.tag }}" tag: "${{ steps.extract_version.outputs.tag }}"
prerelease: "${{ steps.extract_version.outputs.beta }}" prerelease: "${{ steps.extract_version.outputs.beta }}"
draft: "${{ inputs.draft }}"
artifacts: ./build/app/outputs/flutter-apk/*-release*.apk* artifacts: ./build/app/outputs/flutter-apk/*-release*.apk*
generateReleaseNotes: true generateReleaseNotes: true

View File

@@ -2,7 +2,7 @@
[![Ceasefire Now](https://badge.techforpalestine.org/default)](https://techforpalestine.org/learn-more) [![Ceasefire Now](https://badge.techforpalestine.org/default)](https://techforpalestine.org/learn-more)
Get Android App Updates Directly From the Source. 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. Obtainium allows you to install and update apps directly from their releases pages, and receive notifications when new releases are made available.
@@ -16,7 +16,7 @@ Currently supported App sources:
- Open Source - General: - Open Source - General:
- [GitHub](https://github.com/) - [GitHub](https://github.com/)
- [GitLab](https://gitlab.com/) - [GitLab](https://gitlab.com/)
- [Codeberg](https://codeberg.org/) - [Forgejo](https://forgejo.org/) ([Codeberg](https://codeberg.org/))
- [F-Droid](https://f-droid.org/) - [F-Droid](https://f-droid.org/)
- Third Party F-Droid Repos - Third Party F-Droid Repos
- [IzzyOnDroid](https://android.izzysoft.de/) - [IzzyOnDroid](https://android.izzysoft.de/)
@@ -25,9 +25,9 @@ Currently supported App sources:
- [APKPure](https://apkpure.net/) - [APKPure](https://apkpure.net/)
- [Aptoide](https://aptoide.com/) - [Aptoide](https://aptoide.com/)
- [Uptodown](https://uptodown.com/) - [Uptodown](https://uptodown.com/)
- [APKMirror](https://apkmirror.com/) (Track-Only)
- [Huawei AppGallery](https://appgallery.huawei.com/) - [Huawei AppGallery](https://appgallery.huawei.com/)
- Jenkins Jobs - Jenkins Jobs
- [APKMirror](https://apkmirror.com/) (Track-Only)
- Open Source - App-Specific: - Open Source - App-Specific:
- [Signal](https://signal.org/) - [Signal](https://signal.org/)
- [VLC](https://videolan.org/) - [VLC](https://videolan.org/)

View File

@@ -6,7 +6,8 @@
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:requestLegacyExternalStorage="true" android:requestLegacyExternalStorage="true"
android:usesCleartextTraffic="true"> android:usesCleartextTraffic="true"
android:localeConfig="@xml/locales_config">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
<locale android:name="bs"/>
<locale android:name="cs"/>
<locale android:name="de"/>
<locale android:name="en"/>
<locale android:name="es"/>
<locale android:name="fa"/>
<locale android:name="fr"/>
<locale android:name="hu"/>
<locale android:name="it"/>
<locale android:name="ja"/>
<locale android:name="nl"/>
<locale android:name="pl"/>
<locale android:name="pt"/>
<locale android:name="ru"/>
<locale android:name="sv"/>
<locale android:name="tr"/>
<locale android:name="uk"/>
<locale android:name="vi"/>
<locale android:name="zh"/>
</locale-config>

Binary file not shown.

Binary file not shown.

View File

@@ -24,7 +24,7 @@
"colour": "Boja", "colour": "Boja",
"standard": "Standard", "standard": "Standard",
"custom": "Custom", "custom": "Custom",
"useMaterialYou": "Use Material You", "useMaterialYou": "Koristi Material You temu",
"githubStarredRepos": "GitHub repo-i sa zvjezdicom", "githubStarredRepos": "GitHub repo-i sa zvjezdicom",
"uname": "Korisničko ime", "uname": "Korisničko ime",
"wrongArgNum": "Naveden je pogrešan broj argumenata", "wrongArgNum": "Naveden je pogrešan broj argumenata",
@@ -113,7 +113,7 @@
"dark": "Tamna", "dark": "Tamna",
"light": "Svijetla", "light": "Svijetla",
"followSystem": "Pratite sistem", "followSystem": "Pratite sistem",
"followSystemThemeExplanation": "Following system theme is possible only by using third-party applications", "followSystemThemeExplanation": "Praćenje sistemske teme je moguće jedino koristeći aplikacije treće strane",
"useBlackTheme": "Koristite čisto crnu tamnu temu", "useBlackTheme": "Koristite čisto crnu tamnu temu",
"appSortBy": "Aplikacije sortirane po", "appSortBy": "Aplikacije sortirane po",
"authorName": "Autor/Ime", "authorName": "Autor/Ime",
@@ -147,10 +147,10 @@
"noNewUpdates": "Nema novih ažuriranja.", "noNewUpdates": "Nema novih ažuriranja.",
"xHasAnUpdate": "{} ima ažuriranje.", "xHasAnUpdate": "{} ima ažuriranje.",
"appsUpdated": "Aplikacije su ažurirane", "appsUpdated": "Aplikacije su ažurirane",
"appsNotUpdated": "Failed to update applications", "appsNotUpdated": "Neuspješno ažuriranje aplikacija",
"appsUpdatedNotifDescription": "Obavještava korisnika da su u pozadini primijenjena ažuriranja na jednu ili više aplikacija", "appsUpdatedNotifDescription": "Obavještava korisnika da su u pozadini primijenjena ažuriranja na jednu ili više aplikacija",
"xWasUpdatedToY": "{} je ažuriran na {}.", "xWasUpdatedToY": "{} je ažuriran na {}.",
"xWasNotUpdatedToY": "Failed to update {} to {}.", "xWasNotUpdatedToY": "Neuspješno ažuriranje {} na {}.",
"errorCheckingUpdates": "Greška pri provjeri ažuriranja", "errorCheckingUpdates": "Greška pri provjeri ažuriranja",
"errorCheckingUpdatesNotifDescription": "Obavijest koja se prikazuje kada provjera sigurnosnog ažuriranja ne uspije", "errorCheckingUpdatesNotifDescription": "Obavijest koja se prikazuje kada provjera sigurnosnog ažuriranja ne uspije",
"appsRemoved": "Aplikacije su uklonjene", "appsRemoved": "Aplikacije su uklonjene",
@@ -191,7 +191,7 @@
"downloadingX": "Preuzimanje {}", "downloadingX": "Preuzimanje {}",
"downloadX": "Download {}", "downloadX": "Download {}",
"downloadedX": "Downloaded {}", "downloadedX": "Downloaded {}",
"releaseAsset": "Release Asset", "releaseAsset": "Fajlovi verzije",
"downloadNotifDescription": "Obavještava korisnika o napretku u preuzimanju aplikacije", "downloadNotifDescription": "Obavještava korisnika o napretku u preuzimanju aplikacije",
"noAPKFound": "APK nije pronađen", "noAPKFound": "APK nije pronađen",
"noVersionDetection": "Nema detekcije verzije", "noVersionDetection": "Nema detekcije verzije",
@@ -253,12 +253,14 @@
"verifyLatestTag": "Provjerite 'posljednu' ('latest') oznaku", "verifyLatestTag": "Provjerite 'posljednu' ('latest') oznaku",
"intermediateLinkRegex": "Filter za 'srednju' vezu za posjetu", "intermediateLinkRegex": "Filter za 'srednju' vezu za posjetu",
"filterByLinkText": "Filtriraj linkove prema tekstu linka", "filterByLinkText": "Filtriraj linkove prema tekstu linka",
"intermediateLinkNotFound": "Intermediate link nije nađen", "intermediateLinkNotFound": "Intermediate veza nije nađena",
"intermediateLink": "srednja karika", "intermediateLink": "Intermediate veza",
"exemptFromBackgroundUpdates": "Izuzmi iz ažuriranja u pozadini (ako su uključeni)", "exemptFromBackgroundUpdates": "Izuzmi iz ažuriranja u pozadini (ako su uključeni)",
"bgUpdatesOnWiFiOnly": "Isključite ažuriranje u pozadini kada niste na WiFi-ju", "bgUpdatesOnWiFiOnly": "Isključite ažuriranje u pozadini kada niste na WiFi-ju",
"autoSelectHighestVersionCode": "Automatski izaberite najveću (verziju) versionCode APK-a", "autoSelectHighestVersionCode": "Automatski izaberite najveću (verziju) versionCode APK-a",
"versionExtractionRegEx": "RegEx ekstrakcija verzije", "versionExtractionRegEx": "RegEx ekstrakcija verzije",
"trimVersionString": "Trim Version String With RegEx",
"matchGroupToUseForX": "Match Group to Use for \"{}\"",
"matchGroupToUse": "Podjesite grupu za upotebu", "matchGroupToUse": "Podjesite grupu za upotebu",
"highlightTouchTargets": "Istaknite manje vidljive touch mete", "highlightTouchTargets": "Istaknite manje vidljive touch mete",
"pickExportDir": "Izaberite datoteku za izvoz", "pickExportDir": "Izaberite datoteku za izvoz",
@@ -288,11 +290,11 @@
"supportFixedAPKURL": "Podržite fiksne APK URL-ove", "supportFixedAPKURL": "Podržite fiksne APK URL-ove",
"selectX": "Izaberite {}", "selectX": "Izaberite {}",
"parallelDownloads": "Dozvoli paralelna preuzimanja", "parallelDownloads": "Dozvoli paralelna preuzimanja",
"useShizuku": "Use Shizuku or Sui to install", "useShizuku": "Koristi Shizuku ili Sui za instaliranje",
"shizukuBinderNotFound": "Shizuku is not running", "shizukuBinderNotFound": "Shizuku nije pokrenut",
"shizukuOld": "Old Shizuku version (<11) - update it", "shizukuOld": "Stara Shizuku verzija (<11) - ažurirajte je",
"shizukuOldAndroidWithADB": "Shizuku running on Android < 8.1 with ADB - update Android or use Sui instead", "shizukuOldAndroidWithADB": "Shizuku pokrenut na Android-u < 8.1 pomoću ADB-a - ažurirajte Android ili koristite Sui",
"shizukuPretendToBeGooglePlay": "Set Google Play as the installation source (if Shizuku is used)", "shizukuPretendToBeGooglePlay": "Postavi Google Play kao izvor instalacije (samo ako je Shizuku u upotrebi)",
"useSystemFont": "Koristite sistemski font", "useSystemFont": "Koristite sistemski font",
"useVersionCodeAsOSVersion": "Koristite kod verzije aplikacije kao verziju koju je otkrio OS", "useVersionCodeAsOSVersion": "Koristite kod verzije aplikacije kao verziju koju je otkrio OS",
"requestHeader": "Zaglavlje zahtjeva", "requestHeader": "Zaglavlje zahtjeva",
@@ -305,13 +307,13 @@
"installed": "Instalirano", "installed": "Instalirano",
"latest": "Najnoviji", "latest": "Najnoviji",
"invertRegEx": "Obrni regularni izraz", "invertRegEx": "Obrni regularni izraz",
"note": "Note", "note": "Zabelješke",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "\"{}\" padajući meni se može koristiti da dosegnete vlastite/prilagođene instance bilo kojeg izvora.",
"badDownload": "The APK could not be parsed (incompatible or partial download)", "badDownload": "APK ne može biti raščlanjen (nekomaptibilno ili delimično preuzimanje)",
"beforeNewInstallsShareToAppVerifier": "Share new Apps with AppVerifier (if available)", "beforeNewInstallsShareToAppVerifier": "Dijeli nove aplikacije sa AppVerifier-om (ako je dostupno)",
"appVerifierInstructionToast": "Share to AppVerifier, then return here when ready.", "appVerifierInstructionToast": "Dijeli sa AppVerifier-om, zatim se vratite kada ste spremni.",
"wiki": "Help/Wiki", "wiki": "Pomoć/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)", "crowdsourcedConfigsLabel": "Konfiguracije aplikacije obezbeđene pomoću velikog broja ljudi (crowdsourcing) (koristite na svoju odgovornost)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Želite li ukloniti aplikaciju?", "one": "Želite li ukloniti aplikaciju?",
"other": "Želite li ukloniti aplikacije?" "other": "Želite li ukloniti aplikacije?"
@@ -370,6 +372,6 @@
}, },
"apk": { "apk": {
"one": "{} APK", "one": "{} APK",
"other": "{} APKs" "other": "{} APK-a"
} }
} }

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Deaktivovat aktualizace na pozadí, pokud není k dispozici Wi-Fi", "bgUpdatesOnWiFiOnly": "Deaktivovat aktualizace na pozadí, pokud není k dispozici Wi-Fi",
"autoSelectHighestVersionCode": "Automaticky vybrat nejvyšší verzi APK", "autoSelectHighestVersionCode": "Automaticky vybrat nejvyšší verzi APK",
"versionExtractionRegEx": "Extrakce verze pomocí RegEx", "versionExtractionRegEx": "Extrakce verze pomocí RegEx",
"trimVersionString": "Oříznutí řetězce verze pomocí příkazu RegEx",
"matchGroupToUseForX": "Skupina shody, která se použije pro \"{}\"",
"matchGroupToUse": "Odpovídá použité skupině", "matchGroupToUse": "Odpovídá použité skupině",
"highlightTouchTargets": "Zvýraznit méně zjevné cíle dotyku", "highlightTouchTargets": "Zvýraznit méně zjevné cíle dotyku",
"pickExportDir": "Vybrat adresář pro export", "pickExportDir": "Vybrat adresář pro export",

377
assets/translations/da.json Normal file
View File

@@ -0,0 +1,377 @@
{
"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",
"cantInstallOlderVersion": "Kan ikke installere en ældre version af en app",
"appIdMismatch": "Hentet pakke-ID matcher ikke eksisterende app-ID",
"functionNotImplemented": "Denne klasse har ikke implementeret denne funktion",
"placeholder": "Pladsholder",
"someErrors": "Nogle fejl opstod",
"unexpectedError": "Uventet fejl",
"ok": "Okay",
"and": "og",
"githubPATLabel": "GitHub Personlig Adgangstoken (øger hastighedsgrænse)",
"includePrereleases": "Inkluder forudgivelser",
"fallbackToOlderReleases": "Fallback til ældre udgivelser",
"filterReleaseTitlesByRegEx": "Filtrer udgivelsestitler efter regulært udtryk",
"invalidRegEx": "Ugyldigt regulært udtryk",
"noDescription": "Ingen beskrivelse",
"cancel": "Annuller",
"continue": "Fortsæt",
"requiredInBrackets": "(Påkrævet)",
"dropdownNoOptsError": "FEJL: RULLEMENU SKAL HAVE MINDST ÉT TILVALG",
"colour": "Farve",
"standard": "Standard",
"custom": "Brugerdefineret",
"useMaterialYou": "Brug Material You",
"githubStarredRepos": "Stjernemarkeret GitHub-repos",
"uname": "Brugernavn",
"wrongArgNum": "Forkert antal argumenter angivet",
"xIsTrackOnly": "{} kan kun følges",
"source": "Kilde",
"app": "App",
"appsFromSourceAreTrackOnly": "Apps fra denne kilde er 'Følg Kun'.",
"youPickedTrackOnly": "Du har valgt 'Følg Kun'-indstillingen.",
"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?",
"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 {}",
"supportedSources": "Understøttede kilder",
"trackOnlyInBrackets": "(Følg Kun)",
"searchableInBrackets": "(Kan Søges)",
"appsString": "Apps",
"noApps": "Ingen apps",
"noAppsForFilter": "Ingen apps til filter",
"byX": "Af {}",
"percentProgress": "Fremskridt: {}%",
"pleaseWait": "Vent venligst",
"updateAvailable": "Opdatering tilgængelig",
"notInstalled": "Ikke installeret",
"pseudoVersion": "pseudo-version",
"selectAll": "Vælg alle",
"deselectX": "Fravælg {}",
"xWillBeRemovedButRemainInstalled": "{} fjernes fra Obtainium, men forbliver installeret på enheden.",
"removeSelectedAppsQuestion": "Fjern valgte apps?",
"removeSelectedApps": "Fjern valgte apps",
"updateX": "Opdater {}",
"installX": "Installer {}",
"markXTrackOnlyAsUpdated": "Markér {}\n(Følg Kun)\nsom opdateret",
"changeX": "Skift {}",
"installUpdateApps": "Installer/Opdater apps",
"installUpdateSelectedApps": "Installer/Opdater valgte apps",
"markXSelectedAppsAsUpdated": "Markér {} valgte apps som opdateret?",
"no": "Nej",
"yes": "Ja",
"markSelectedAppsUpdated": "Markér valgte apps som opdateret",
"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.",
"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",
"filter": "Filtrer",
"filterApps": "Filtrer Apps",
"appName": "Appnavn",
"author": "Udvikler",
"upToDateApps": "Opdaterede apps",
"nonInstalledApps": "Ikke-installerede apps",
"importExport": "Import/Eksport",
"settings": "Indstillinger",
"exportedTo": "Eksportér til {}",
"obtainiumExport": "Obtainium-eksport",
"invalidInput": "Ugyldigt input",
"importedX": "Importerede {}",
"obtainiumImport": "Obtainium-import",
"importFromURLList": "Importér fra URL-liste",
"searchQuery": "Søgning",
"appURLList": "Liste over app-URL'er",
"line": "Linje",
"searchX": "Søg {}",
"noResults": "Ingen resultater fundet",
"importX": "Importér {}",
"importedAppsIdDisclaimer": "Importerede apps vises muligvis forkert som \"Ikke installeret\".\nFor at løse dette, geninstaller dem via Obtainium.\nDette bør ikke påvirke app-data.\n\nPåvirker kun URL- og tredjepartsimportmetoder.",
"importErrors": "Importfejl",
"importedXOfYApps": "{} af {} app importeret.",
"followingURLsHadErrors": "Følgende URL'er havde fejl:",
"selectURL": "Vælg URL",
"selectURLs": "Vælg URL'er",
"pick": "Vælg",
"theme": "Tema",
"dark": "Mørk",
"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",
"appSortBy": "Sortér apps efter:",
"authorName": "Udvikler/Navn",
"nameAuthor": "Navn/Udvikler",
"asAdded": "Som tilføjet",
"appSortOrder": "Sorteringsrækkefølge for apps",
"ascending": "Stigende",
"descending": "Faldende",
"bgUpdateCheckInterval": "Kontrolinterval for baggrundsopdatering",
"neverManualOnly": "Aldrig - Kun manuelt",
"appearance": "Udseende",
"showWebInAppView": "Vis kildewebsiden i appvisning",
"pinUpdates": "Fastgør opdateringer til toppen af appvisning",
"updates": "Opdateringer",
"sourceSpecific": "Kildespecifik",
"appSource": "App-kilde",
"noLogs": "Ingen logs",
"appLogs": "App-logs",
"close": "Luk",
"share": "Del",
"appNotFound": "App ikke fundet",
"obtainiumExportHyphenatedLowercase": "obtainium-eksport",
"pickAnAPK": "Vælg en APK",
"appHasMoreThanOnePackage": "{} har mere end én pakke:",
"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",
"noNewUpdates": "Ingen nye opdateringer.",
"xHasAnUpdate": "{} har en opdatering.",
"appsUpdated": "Apps opdateret",
"appsNotUpdated": "Kunne ikke opdatere applikationerne",
"appsUpdatedNotifDescription": "Underretter brugeren om, at opdateringer til en eller flere apps blev udført i baggrunden",
"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",
"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",
"checkingForUpdates": "Tjekker for opdateringer",
"checkingForUpdatesNotifDescription": "Kortvarig meddelelse, der vises 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)",
"unknown": "Ukendt",
"none": "Ingen",
"never": "Aldrig",
"latestVersionX": "Seneste: {}",
"installedVersionX": "Installeret: {}",
"lastUpdateCheckX": "Sidste opdateringstjek: {}",
"remove": "Fjern",
"yesMarkUpdated": "Ja, markér som opdateret",
"fdroid": "F-Droid Officiel",
"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",
"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",
"noAPKFound": "Ingen APK fundet",
"noVersionDetection": "Ingen versionsregistrering",
"categorize": "Kategoriser",
"categories": "Kategorier",
"category": "Kategori",
"noCategory": "Ingen kategori",
"noCategories": "Ingen kategorier",
"deleteCategoriesQuestion": "Slet kategorier?",
"categoryDeleteWarning": "Alle apps i slettede kategorier indstilles til ukategoriseret.",
"addCategory": "Tilføj kategori",
"label": "Etiket",
"language": "Sprog",
"copiedToClipboard": "Kopieret til udklipsholder",
"storagePermissionDenied": "Lagringstilladelse nægtet",
"selectedCategorizeWarning": "Dette erstatter alle eksisterende kategoriindstillinger for de valgte apps.",
"filterAPKsByRegEx": "Filtrer APK'er efter regulært udtryk",
"removeFromObtainium": "Fjern fra Obtainium",
"uninstallFromDevice": "Afinstaller fra enhed",
"onlyWorksWithNonVersionDetectApps": "Virker kun for apps med versionsregistrering deaktiveret.",
"releaseDateAsVersion": "Brug udgivelsesdato som versionsstreng",
"releaseDateAsVersionExplanation": "Denne indstilling bør kun bruges til apps, hvor versionsregistrering ikke virker korrekt, men hvor en udgivelsesdato er tilgængelig.",
"changes": "Ændringer",
"releaseDate": "Udgivelsesdato",
"importFromURLsInFile": "Importér fra URL'er i fil (som OPML)",
"versionDetectionExplanation": "Afstem versionsstreng med versionen registreret fra OS",
"versionDetection": "Versionsregistrering",
"standardVersionDetection": "Standard versionsregistrering",
"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",
"dontShowTrackOnlyWarnings": "Vis ikke 'Følg Kun'-advarsler",
"dontShowAPKOriginWarnings": "Vis ikke advarsler om APK-oprindelse",
"moveNonInstalledAppsToBottom": "Flyt ikke-installerede apps til bunden af appvisning",
"gitlabPATLabel": "GitLab Personlig Adgangstoken",
"about": "Om",
"requiresCredentialsInSettings": "{} kræver yderligere legitimation (i Indstillinger)",
"checkOnStart": "Tjek for opdateringer ved opstart",
"tryInferAppIdFromCode": "Forsøg at udlede app-ID fra kildekode",
"removeOnExternalUninstall": "Fjern automatisk eksternt afinstallerede apps",
"pickHighestVersionCode": "Auto-vælg højeste versionKode af APK",
"checkUpdateOnDetailPage": "Tjek for opdateringer ved åbning af appens detaljeside",
"disablePageTransitions": "Deaktivér sideovergangsanimationer",
"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.",
"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",
"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.",
"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",
"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",
"highlightTouchTargets": "Fremhæv mindre åbenlyse berøringsmål",
"pickExportDir": "Vælg eksportmappe",
"autoExportOnChanges": "Auto-eksport 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",
"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",
"installing": "Installerer",
"skipUpdateNotifications": "Spring opdateringsmeddelelser over",
"updatesAvailableNotifChannel": "Opdateringer tilgængelige",
"appsUpdatedNotifChannel": "Apps opdateret",
"appsPossiblyUpdatedNotifChannel": "App-opdateringer forsøgt",
"errorCheckingUpdatesNotifChannel": "Fejl ved opdateringstjek",
"appsRemovedNotifChannel": "Apps fjernet",
"downloadingXNotifChannel": "Henter {}",
"completeAppInstallationNotifChannel": "Færdiggør app-installation",
"checkingForUpdatesNotifChannel": "Tjekker for opdateringer",
"onlyCheckInstalledOrTrackOnlyApps": "Tjek kun installeret og 'Følg Kun'-apps for opdateringer",
"supportFixedAPKURL": "Understøt fikserede APK-URL'er",
"selectX": "Vælg {}",
"parallelDownloads": "Tillad samtidige overførsler",
"useShizuku": "Brug Shizuku eller Sui til at installere",
"shizukuBinderNotFound": "Shizuku-tjeneste kører ikke",
"shizukuOld": "Forældet Shizuku-version (<11). Opdater den",
"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",
"useLatestAssetDateAsReleaseDate": "Brug seneste ressourceupload som udgivelsesdato",
"defaultPseudoVersioningMethod": "Standard pseudo-versioneringsmetode",
"partialAPKHash": "Delvis APK-hash",
"APKLinkHash": "Hash for APK-link",
"directAPKLink": "Direkte APK-link",
"pseudoVersionInUse": "En pseudo-version er i brug",
"installed": "Installeret",
"latest": "Seneste",
"invertRegEx": "Inverter regulært udtryk",
"note": "Bemærk",
"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.",
"wiki": "Hjælp/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourcede app-konfigurationer (brug på egen risiko)",
"removeAppQuestion": {
"one": "Fjern app?",
"other": "Fjern apps?"
},
"tooManyRequestsTryAgainInMinutes": {
"one": "For mange anmodninger (begrænset hastighed). Prøv igen om {} minut",
"other": "For mange anmodninger (begrænset hastighed). Prøv igen om {} minutter"
},
"bgUpdateGotErrorRetryInMinutes": {
"one": "Baggrundsopdateringstjek stødte på en {}. Planlægger et nyt tjek om {} minut",
"other": "Baggrundsopdateringstjek stødte på en {}. Planlægger et nyt tjek om {} minutter"
},
"bgCheckFoundUpdatesWillNotifyIfNeeded": {
"one": "Baggrundsopdateringstjek fandt {} opdatering. Underretter brugeren, hvis nødvendigt",
"other": "Baggrundsopdateringstjek fandt {} opdateringer. Underretter brugeren, hvis nødvendigt"
},
"apps": {
"one": "{} App",
"other": "{} Apps"
},
"url": {
"one": "{} URL",
"other": "{} URL'er"
},
"minute": {
"one": "{} Minut",
"other": "{} Minutter"
},
"hour": {
"one": "{} Time",
"other": "{} Timer"
},
"day": {
"one": "{} Dag",
"other": "{} Dage"
},
"clearedNLogsBeforeXAfterY": {
"one": "Ryddet {n} log (før = {before}, efter = {after})",
"other": "Ryddet {n} logs (før = {before}, efter = {after})"
},
"xAndNMoreUpdatesAvailable": {
"one": "{} og 1 anden app har opdateringer.",
"other": "{} og {} andre apps har opdateringer."
},
"xAndNMoreUpdatesInstalled": {
"one": "{} og 1 anden app blev opdateret.",
"other": "{} og {} andre apps blev opdateret."
},
"xAndNMoreUpdatesFailed": {
"one": "Kunne ikke opdatere {} og 1 anden app.",
"other": "Kunne ikke opdatere {} og {} andre apps."
},
"xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} og 1 anden app blev muligvis opdateret.",
"other": "{} og {} andre apps blev muligvis opdateret."
},
"apk": {
"one": "{} APK",
"other": "{} APK'er"
}
}

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Hintergrundaktualisierungen deaktivieren, wenn kein WLAN vorhanden ist", "bgUpdatesOnWiFiOnly": "Hintergrundaktualisierungen deaktivieren, wenn kein WLAN vorhanden ist",
"autoSelectHighestVersionCode": "Automatisch höchste APK-Version auswählen", "autoSelectHighestVersionCode": "Automatisch höchste APK-Version auswählen",
"versionExtractionRegEx": "Versions-Extraktion per RegEx", "versionExtractionRegEx": "Versions-Extraktion per RegEx",
"trimVersionString": "Trim Version String mit RegEx",
"matchGroupToUseForX": "Zu verwendende Abgleichsgruppe für \"{}\"",
"matchGroupToUse": "zu verwendende Gruppe abgleichen", "matchGroupToUse": "zu verwendende Gruppe abgleichen",
"highlightTouchTargets": "Weniger offensichtliche Touch-Ziele hervorheben", "highlightTouchTargets": "Weniger offensichtliche Touch-Ziele hervorheben",
"pickExportDir": "Export-Verzeichnis wählen", "pickExportDir": "Export-Verzeichnis wählen",
@@ -329,12 +331,12 @@
"other": "Die Hintergrundaktualisierungsprüfung fand {} Aktualisierungen benachrichtigt den Benutzer, falls erforderlich" "other": "Die Hintergrundaktualisierungsprüfung fand {} Aktualisierungen benachrichtigt den Benutzer, falls erforderlich"
}, },
"apps": { "apps": {
"eine": "{} App", "one": "{} App",
"andere": "{} Apps" "other": "{} Apps"
}, },
"url": { "url": {
"eine": "{} URL", "one": "{} URL",
"andere": "{} URLs" "other": "{} URLs"
}, },
"minute": { "minute": {
"one": "{} Minute", "one": "{} Minute",

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi", "bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK", "autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
"versionExtractionRegEx": "Version String Extraction RegEx", "versionExtractionRegEx": "Version String Extraction RegEx",
"trimVersionString": "Trim Version String With RegEx",
"matchGroupToUseForX": "Match Group to Use for \"{}\"",
"matchGroupToUse": "Match Group to Use for Version String Extraction RegEx", "matchGroupToUse": "Match Group to Use for Version String Extraction RegEx",
"highlightTouchTargets": "Highlight less obvious touch targets", "highlightTouchTargets": "Highlight less obvious touch targets",
"pickExportDir": "Pick Export Directory", "pickExportDir": "Pick Export Directory",

View File

@@ -21,15 +21,15 @@
"continue": "Continuar", "continue": "Continuar",
"requiredInBrackets": "(Requerido)", "requiredInBrackets": "(Requerido)",
"dropdownNoOptsError": "ERROR: EL DESPLEGABLE DEBE TENER AL MENOS UNA OPCIÓN", "dropdownNoOptsError": "ERROR: EL DESPLEGABLE DEBE TENER AL MENOS UNA OPCIÓN",
"colour": "Color", "colour": "color",
"standard": "Estándar", "standard": "Estándar",
"custom": "A medida", "custom": "A medida",
"useMaterialYou": "Use 'Material You'", "useMaterialYou": "Aplicar 'Material You'",
"githubStarredRepos": "Repositorios favoritos en GitHub", "githubStarredRepos": "repositorios favoritos en GitHub",
"uname": "Nombre de usuario", "uname": "Nombre de usuario",
"wrongArgNum": "Número de argumentos provistos inválido", "wrongArgNum": "Número de argumentos provistos inválido",
"xIsTrackOnly": "{} es de 'sólo seguimiento'", "xIsTrackOnly": "{} es de 'sólo seguimiento'",
"source": "Origen", "source": "origen",
"app": "Aplicación", "app": "Aplicación",
"appsFromSourceAreTrackOnly": "Las aplicaciones de este origen son solo para seguimiento.", "appsFromSourceAreTrackOnly": "Las aplicaciones de este origen son solo para seguimiento.",
"youPickedTrackOnly": "Debe seleccionar la opción de 'solo para seguimiento'.", "youPickedTrackOnly": "Debe seleccionar la opción de 'solo para seguimiento'.",
@@ -122,14 +122,14 @@
"appSortOrder": "Orden de Clasificación", "appSortOrder": "Orden de Clasificación",
"ascending": "Ascendente", "ascending": "Ascendente",
"descending": "Descendente", "descending": "Descendente",
"bgUpdateCheckInterval": "Comprobación actualizaciones en segundo plano", "bgUpdateCheckInterval": "Comprobar actualizaciones en segundo plano",
"neverManualOnly": "Nunca, solo manual", "neverManualOnly": "Nunca, solo manual",
"appearance": "Apariencia", "appearance": "Apariencia",
"showWebInAppView": "Mostrar vista de la web de origen", "showWebInAppView": "Mostrar vista de la web de origen",
"pinUpdates": "Anclar actualizaciones al principio", "pinUpdates": "Anclar actualizaciones al principio",
"updates": "Actualizaciones", "updates": "Actualizaciones",
"sourceSpecific": "Fuente específica", "sourceSpecific": "Fuente específica",
"appSource": "Obtainium en GitHub", "appSource": "Filtrar por fuente",
"noLogs": "Ningún registro", "noLogs": "Ningún registro",
"appLogs": "Registros", "appLogs": "Registros",
"close": "Cerrar", "close": "Cerrar",
@@ -220,11 +220,11 @@
"versionDetectionExplanation": "Conciliar la cadena de versión con la versión detectada desde el sistema operativo", "versionDetectionExplanation": "Conciliar la cadena de versión con la versión detectada desde el sistema operativo",
"versionDetection": "Detección de versiones", "versionDetection": "Detección de versiones",
"standardVersionDetection": "Por versión", "standardVersionDetection": "Por versión",
"groupByCategory": "Agrupar por categoría", "groupByCategory": "Agrupar por categorías",
"autoApkFilterByArch": "Filtrar APK por arquitectura del procesador (si es posible)", "autoApkFilterByArch": "Filtrar APK por arquitectura del procesador (si es posible)",
"overrideSource": "Forzar desde la fuente", "overrideSource": "Forzar desde la fuente",
"dontShowAgain": "No mostrar de nuevo", "dontShowAgain": "No mostrar de nuevo",
"dontShowTrackOnlyWarnings": "No mostrar avisos sobre apps 'solo para seguimiento", "dontShowTrackOnlyWarnings": "No mostrar avisos sobre apps 'solo para seguimiento'",
"dontShowAPKOriginWarnings": "No mostrar avisos sobre las fuentes de las APKs", "dontShowAPKOriginWarnings": "No mostrar avisos sobre las fuentes de las APKs",
"moveNonInstalledAppsToBottom": "Mover apps no instaladas al final", "moveNonInstalledAppsToBottom": "Mover apps no instaladas al final",
"gitlabPATLabel": "Token de acceso personal a GitLab", "gitlabPATLabel": "Token de acceso personal a GitLab",
@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Deshabilitar las actualizaciones en segundo plano sin WiFi", "bgUpdatesOnWiFiOnly": "Deshabilitar las actualizaciones en segundo plano sin WiFi",
"autoSelectHighestVersionCode": "Auto selección del paquete APK con versión más reciente", "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", "highlightTouchTargets": "Resaltar objetivos menos obvios",
"pickExportDir": "Directorio para exportar", "pickExportDir": "Directorio para exportar",
@@ -288,7 +290,7 @@
"supportFixedAPKURL": "Soporte para URLs fijas de APK", "supportFixedAPKURL": "Soporte para URLs fijas de APK",
"selectX": "Elija {}", "selectX": "Elija {}",
"parallelDownloads": "Permitir descargas paralelas", "parallelDownloads": "Permitir descargas paralelas",
"useShizuku": "Use Shizuku o Sui para instalar", "useShizuku": "Usar Shizuku o Sui para instalar",
"shizukuBinderNotFound": "Shizuku no funciona", "shizukuBinderNotFound": "Shizuku no funciona",
"shizukuOld": "Versión antigua de Shizuku (<11) - actualícela", "shizukuOld": "Versión antigua de Shizuku (<11) - actualícela",
"shizukuOldAndroidWithADB": "Shizuku corriendo en Android < 8.1 con ADB - actualiza Android o usa Sui en su lugar", "shizukuOldAndroidWithADB": "Shizuku corriendo en Android < 8.1 con ADB - actualiza Android o usa Sui en su lugar",
@@ -308,7 +310,7 @@
"note": "Nota", "note": "Nota",
"selfHostedNote": "El desplegable «{}» puede usarse para acceder a instancias autoalojadas/personalizadas de cualquier fuente.", "selfHostedNote": "El desplegable «{}» puede usarse para acceder a instancias autoalojadas/personalizadas de cualquier fuente.",
"badDownload": "No se ha podido analizar el APK (incompatible o descarga parcial)", "badDownload": "No se ha podido analizar el APK (incompatible o descarga parcial)",
"beforeNewInstallsShareToAppVerifier": "Compartir nuevas aplicaciones con AppVerifier (si está disponible)", "beforeNewInstallsShareToAppVerifier": "Compartir aplicaciones nuevas con AppVerifier (si está disponible)",
"appVerifierInstructionToast": "Comparta con AppVerifier y vuelva aquí cuando esté listo.", "appVerifierInstructionToast": "Comparta con AppVerifier y vuelva aquí cuando esté listo.",
"wiki": "Ayuda/Wiki", "wiki": "Ayuda/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (uso bajo su propia responsabilidad)", "crowdsourcedConfigsLabel": "Crowdsourced App Configurations (uso bajo su propia responsabilidad)",
@@ -333,8 +335,8 @@
"other": "{} Aplicaciones" "other": "{} Aplicaciones"
}, },
"url": { "url": {
"uno": "{} URL", "one": "{} URL",
"otro": "{} URL" "other": "{} URL"
}, },
"minute": { "minute": {
"one": "{} minuto", "one": "{} minuto",

View File

@@ -113,7 +113,7 @@
"dark": "تاریک", "dark": "تاریک",
"light": "روشن", "light": "روشن",
"followSystem": "هماهنگ با سیستم", "followSystem": "هماهنگ با سیستم",
"followSystemThemeExplanation": "Following system theme is possible only by using third-party applications", "followSystemThemeExplanation": "دنبال کردن تم سیستم فقط با استفاده از برنامه های شخص ثالث امکان پذیر است",
"useBlackTheme": "استفاده از تم تیره سیاه خالص", "useBlackTheme": "استفاده از تم تیره سیاه خالص",
"appSortBy": "مرتب سازی برنامه بر اساس", "appSortBy": "مرتب سازی برنامه بر اساس",
"authorName": "سازنده/اسم", "authorName": "سازنده/اسم",
@@ -147,10 +147,10 @@
"noNewUpdates": "به روز رسانی جدیدی وجود ندارد.", "noNewUpdates": "به روز رسانی جدیدی وجود ندارد.",
"xHasAnUpdate": "{} یک به روز رسانی دارد.", "xHasAnUpdate": "{} یک به روز رسانی دارد.",
"appsUpdated": "برنامه ها به روز شدند", "appsUpdated": "برنامه ها به روز شدند",
"appsNotUpdated": "Failed to update applications", "appsNotUpdated": "به روز رسانی برنامه ها ناموفق بود",
"appsUpdatedNotifDescription": "به کاربر اطلاع می دهد که به روز رسانی یک یا چند برنامه در پس زمینه اعمال شده است", "appsUpdatedNotifDescription": "به کاربر اطلاع می دهد که به روز رسانی یک یا چند برنامه در پس زمینه اعمال شده است",
"xWasUpdatedToY": "{} به {} به روز شد.", "xWasUpdatedToY": "{} به {} به روز شد.",
"xWasNotUpdatedToY": "Failed to update {} to {}.", "xWasNotUpdatedToY": "به روز رسانی {} به {} انجام نشد.",
"errorCheckingUpdates": "خطا در بررسی به‌روزرسانی‌ها", "errorCheckingUpdates": "خطا در بررسی به‌روزرسانی‌ها",
"errorCheckingUpdatesNotifDescription": "اعلانی که وقتی بررسی به‌روزرسانی پس‌زمینه ناموفق است نشان می‌دهد", "errorCheckingUpdatesNotifDescription": "اعلانی که وقتی بررسی به‌روزرسانی پس‌زمینه ناموفق است نشان می‌دهد",
"appsRemoved": "برنامه ها حذف شدند", "appsRemoved": "برنامه ها حذف شدند",
@@ -189,9 +189,9 @@
"disableVersionDetection": "غیرفعال کردن تشخیص نسخه", "disableVersionDetection": "غیرفعال کردن تشخیص نسخه",
"noVersionDetectionExplanation": "این گزینه فقط باید برای برنامه هایی استفاده شود که تشخیص نسخه به درستی کار نمی کند.", "noVersionDetectionExplanation": "این گزینه فقط باید برای برنامه هایی استفاده شود که تشخیص نسخه به درستی کار نمی کند.",
"downloadingX": "در حال دانلود {}", "downloadingX": "در حال دانلود {}",
"downloadX": "Download {}", "downloadX": "دانلود {}",
"downloadedX": "Downloaded {}", "downloadedX": "دانلود شده {}",
"releaseAsset": "Release Asset", "releaseAsset": "انتشار دارایی",
"downloadNotifDescription": "کاربر را از پیشرفت دانلود یک برنامه مطلع می کند", "downloadNotifDescription": "کاربر را از پیشرفت دانلود یک برنامه مطلع می کند",
"noAPKFound": "APK پیدا نشد فایل", "noAPKFound": "APK پیدا نشد فایل",
"noVersionDetection": "بدون تشخیص نسخه", "noVersionDetection": "بدون تشخیص نسخه",
@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "به‌روزرسانی‌های پس‌زمینه را در صورت عدم اتصال به WiFi غیرفعال کنید", "bgUpdatesOnWiFiOnly": "به‌روزرسانی‌های پس‌زمینه را در صورت عدم اتصال به WiFi غیرفعال کنید",
"autoSelectHighestVersionCode": "انتخاب خودکار بالاترین نسخه کد APK", "autoSelectHighestVersionCode": "انتخاب خودکار بالاترین نسخه کد APK",
"versionExtractionRegEx": "نسخه استخراج RegEx", "versionExtractionRegEx": "نسخه استخراج RegEx",
"trimVersionString": "Trim Version String With RegEx",
"matchGroupToUseForX": "Match Group to Use for \"{}\"",
"matchGroupToUse": "گروه مورد استفاده را مطابقت دهید", "matchGroupToUse": "گروه مورد استفاده را مطابقت دهید",
"highlightTouchTargets": "اهداف لمسی کمتر واضح را برجسته کنید", "highlightTouchTargets": "اهداف لمسی کمتر واضح را برجسته کنید",
"pickExportDir": "فهرست برون ریزی را انتخاب کنید", "pickExportDir": "فهرست برون ریزی را انتخاب کنید",
@@ -305,13 +307,13 @@
"installed": "نصب شده است", "installed": "نصب شده است",
"latest": "آخرین", "latest": "آخرین",
"invertRegEx": "معکوس کردن عبارت منظم", "invertRegEx": "معکوس کردن عبارت منظم",
"note": "Note", "note": "یادداشت",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "از منوی کرکره ای \"{}\" می توان برای دسترسی به نمونه های خود میزبانی/سفارشی از هر منبعی استفاده کرد.",
"badDownload": "The APK could not be parsed (incompatible or partial download)", "badDownload": "APK قابل تجزیه نیست (دانلود ناسازگار یا جزئی)",
"beforeNewInstallsShareToAppVerifier": "Share new Apps with AppVerifier (if available)", "beforeNewInstallsShareToAppVerifier": "اشتراک‌گذاری برنامه‌های جدید با AppVerifier (در صورت وجود)",
"appVerifierInstructionToast": "Share to AppVerifier, then return here when ready.", "appVerifierInstructionToast": "در AppVerifier به اشتراک بگذارید، سپس پس از آماده شدن به اینجا برگردید.",
"wiki": "Help/Wiki", "wiki": "راهنما/ویکی",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)", "crowdsourcedConfigsLabel": "تنظیمات برنامه Crowdsourced (با مسئولیت خود استفاده کنید)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "برنامه حذف شود؟", "one": "برنامه حذف شود؟",
"other": "برنامه ها حذف شوند؟" "other": "برنامه ها حذف شوند؟"
@@ -361,8 +363,8 @@
"other": "{} و {} برنامه دیگر به روز شدند." "other": "{} و {} برنامه دیگر به روز شدند."
}, },
"xAndNMoreUpdatesFailed": { "xAndNMoreUpdatesFailed": {
"one": "Failed to update {} and 1 more app.", "one": "{} و 1 برنامه دیگر به روز نشد.",
"other": "Failed to update {} and {} more apps." "other": "{} و {} برنامه دیگر به روز نشد."
}, },
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} و 1 برنامه دیگر ممکن است به روز شده باشند.", "one": "{} و 1 برنامه دیگر ممکن است به روز شده باشند.",

View File

@@ -1,86 +1,86 @@
{ {
"invalidURLForSource": "URL d'application {} invalide", "invalidURLForSource": "URL de l'application {} n'es pas valide",
"noReleaseFound": "Impossible de trouver une version adaptée", "noReleaseFound": "Impossible de trouver une publication correspondante",
"noVersionFound": "Impossible de déterminer la variante de la version", "noVersionFound": "Impossible de déterminer la version de la publication",
"urlMatchesNoSource": "L'URL ne correspond pas à une source connue", "urlMatchesNoSource": "L'URL ne correspond pas à une source connue",
"cantInstallOlderVersion": "Impossible d'installer une ancienne version d'une application", "cantInstallOlderVersion": "Impossible d'installer une ancienne version de l'application",
"appIdMismatch": "L'ID de paquet téléchargé ne correspond pas à l'ID de l'application existante", "appIdMismatch": "L'ID du paquet téléchargé ne correspond pas à l'ID de l'application existante",
"functionNotImplemented": "Cette classe n'a pas implémenté cette fonction", "functionNotImplemented": "Cette classe n'implémente pas cette fonction",
"placeholder": "Espace réservé", "placeholder": "Espace réservé",
"someErrors": "Des erreurs se sont produites", "someErrors": "Des erreurs se sont produites",
"unexpectedError": "Erreur inattendue", "unexpectedError": "Erreur inattendue",
"ok": "D'accord", "ok": "Ok",
"and": "et", "and": "et",
"githubPATLabel": "Jeton d'Accès Personnel GitHub (Augmente la limite de débit)", "githubPATLabel": "Jeton d'accès personnel GitHub (augmente la limite de débit)",
"includePrereleases": "Inclure les avant-premières", "includePrereleases": "Inclure les versions préliminaires",
"fallbackToOlderReleases": "Retour aux anciennes versions", "fallbackToOlderReleases": "Retour aux anciennes versions",
"filterReleaseTitlesByRegEx": "Filtrer les titres de version par expression régulière", "filterReleaseTitlesByRegEx": "Filtrer les titres de version par expression régulière",
"invalidRegEx": "Expression régulière invalide", "invalidRegEx": "Expression régulière invalide",
"noDescription": "Pas de description", "noDescription": "Aucune description",
"cancel": "Annuler", "cancel": "Annuler",
"continue": "Continuer", "continue": "Continuer",
"requiredInBrackets": "(Requis)", "requiredInBrackets": "(Requis)",
"dropdownNoOptsError": "ERREUR : LE DÉROULEMENT DOIT AVOIR AU MOINS UNE OPT", "dropdownNoOptsError": "ERREUR: LE DÉROULEMENT DOIT AVOIR AU MOINS UNE OPT",
"colour": "Couleur", "colour": "Couleur",
"standard": "Standard", "standard": "Standard",
"custom": "Sur mesure", "custom": "Personnalisé",
"useMaterialYou": "Utiliser le matériel que vous", "useMaterialYou": "Utiliser Material You",
"githubStarredRepos": "Dépôts étoilés GitHub", "githubStarredRepos": "Dépôts étoilés GitHub",
"uname": "Nom d'utilisateur", "uname": "Nom d'utilisateur",
"wrongArgNum": "Mauvais nombre d'arguments fournis", "wrongArgNum": "Nombre incorrect des arguments fournis",
"xIsTrackOnly": "{} est en 'Suivi uniquement'", "xIsTrackOnly": "{} en Suivi uniquement",
"source": "Source", "source": "Source",
"app": "Application", "app": "Application",
"appsFromSourceAreTrackOnly": "Les applications de cette source sont en 'Suivi uniquement'.", "appsFromSourceAreTrackOnly": "Les applications de cette source sont en 'Suivi uniquement'.",
"youPickedTrackOnly": "Vous avez sélectionné l'option 'Suivi uniquement'.", "youPickedTrackOnly": "Vous avez sélectionné l'option 'Suivi uniquement'.",
"trackOnlyAppDescription": "L'application sera suivie pour les mises à jour, mais Obtainium ne pourra pas la télécharger ou l'installer.", "trackOnlyAppDescription": "L'application sera suivie pour les mises à jour, mais Obtainium ne pourra pas le télécharger ou l'installer.",
"cancelled": "Annulé", "cancelled": "Annulé",
"appAlreadyAdded": "Application déjà ajoutée", "appAlreadyAdded": "L'application a déjà été ajoutée",
"alreadyUpToDateQuestion": "Application déjà à jour ?", "alreadyUpToDateQuestion": "L'application est déjà à jour ?",
"addApp": "Ajouter une application", "addApp": "Ajouter Appli",
"appSourceURL": "URL de la source de l'application", "appSourceURL": "URL source de l'application",
"error": "Erreur", "error": "Erreur",
"add": "Ajouter", "add": "Ajouter",
"searchSomeSourcesLabel": "Rechercher (certaines sources uniquement)", "searchSomeSourcesLabel": "Rechercher (certaines sources uniquement)",
"search": "Rechercher", "search": "Rechercher",
"additionalOptsFor": "Options supplémentaires pour {}", "additionalOptsFor": "Options supplémentaires pour {}",
"supportedSources": "Sources prises en charge ", "supportedSources": "Sources prises en charge",
"trackOnlyInBrackets": "(Suivi uniquement)", "trackOnlyInBrackets": "(Suivi uniquement)",
"searchableInBrackets": "(Intérrogeable)", "searchableInBrackets": "(Interrogeable)",
"appsString": "Applications", "appsString": "Applications",
"noApps": "Aucune application", "noApps": "Aucune applications",
"noAppsForFilter": "Aucune application pour le filtre", "noAppsForFilter": "Aucune application à Filtrer",
"byX": "Par {}", "byX": "Par {}",
"percentProgress": "Progrès: {}%", "percentProgress": "Progression: {}%",
"pleaseWait": "Veuillez patienter", "pleaseWait": "Veuillez patienter",
"updateAvailable": "Mise à jour disponible", "updateAvailable": "Mise à jour disponible",
"notInstalled": "Non installé", "notInstalled": "Non installé",
"pseudoVersion": "pseudo-version", "pseudoVersion": "Version fictive",
"selectAll": "Tout sélectionner", "selectAll": "Tout sélectionner",
"deselectX": "Déselectionner {}", "deselectX": "Déselectionner {}",
"xWillBeRemovedButRemainInstalled": "{} sera supprimé d'Obtainium mais restera installé sur l'appareil.", "xWillBeRemovedButRemainInstalled": "{} sera supprimée d'Obtainium mais restera installée sur l'appareil.",
"removeSelectedAppsQuestion": "Supprimer les applications sélectionnées ?", "removeSelectedAppsQuestion": "Supprimer les applications sélectionnées ?",
"removeSelectedApps": "Supprimer les applications sélectionnées", "removeSelectedApps": "Les applications sélectionnées ont étés supprimés",
"updateX": "Mise à jour {}", "updateX": "Mettre à jour {}",
"installX": "Installer {}", "installX": "Installer {}",
"markXTrackOnlyAsUpdated": "Marquer {}\n(Suivi uniquement)\n comme mis à jour", "markXTrackOnlyAsUpdated": "Marquer {}\n(Suivi uniquement)\ncomme étant à jour",
"changeX": "Changer {}", "changeX": "Changer {}",
"installUpdateApps": "Installer/Mettre à jour les applications", "installUpdateApps": "Installer/Mettre à jour les applications",
"installUpdateSelectedApps": "Installer/Mettre à jour les applications sélectionnées", "installUpdateSelectedApps": "Installer/Mettre à jour les applications sélectionnées",
"markXSelectedAppsAsUpdated": "Marquer {} les applications sélectionnées comme étant à jour ?", "markXSelectedAppsAsUpdated": "Marquer les {} applications sélectionnées comme étant à jour ?",
"no": "Non", "no": "Non",
"yes": "Oui", "yes": "Oui",
"markSelectedAppsUpdated": "Marquer les applications sélectionnées comme étant à jour", "markSelectedAppsUpdated": "Marquer les application sélectionnées comme étant à jour",
"pinToTop": "Épingler en haut", "pinToTop": "Épingler en haut",
"unpinFromTop": "Désépingler du haut", "unpinFromTop": "Désépingler du haut",
"resetInstallStatusForSelectedAppsQuestion": "Réinitialiser le statu d'installation des applications sélectionnées ?", "resetInstallStatusForSelectedAppsQuestion": "Réinitialiser ltat d'installation des applications sélectionnées ?",
"installStatusOfXWillBeResetExplanation": "Le statu d'installation de toutes les applications sélectionnées sera réinitialisé.\n\nCela peut aider lorsque la version de l'application affichée dans Obtainium est incorrecte en raison d'échecs de mises à jour ou d'autres problèmes.", "installStatusOfXWillBeResetExplanation": "Ltat d'installation de toutes les applications sélectionnées sera réinitialisé.\n\nCela peut être utile lorsque la version de l'application affichée dans Obtainium est incorrecte en raison de l'échec des mises à jour ou d'autres problèmes.",
"customLinkMessage": "Ces liens fonctionnent sur les appareils sur lesquels Obtainium est installé", "customLinkMessage": "Ces liens fonctionnent sur les appareils sur lesquels Obtainium est installé",
"shareAppConfigLinks": "Partager la configuration de l'application sous forme de lien HTML", "shareAppConfigLinks": "Partager la configuration de l'application sous forme de lien HTML",
"shareSelectedAppURLs": "Partager les URL d'application sélectionnées", "shareSelectedAppURLs": "Partager les URL des applications sélectionnées",
"resetInstallStatus": "Réinitialiser le statu d'installation", "resetInstallStatus": "L'état d'installation des applications ont étés réinitialisés",
"more": "Plus", "more": "Plus",
"removeOutdatedFilter": "Supprimer le filtre d'application obsolète", "removeOutdatedFilter": "Supprimer le filtre des applications obsolètes",
"showOutdatedOnly": "Afficher uniquement les applications obsolètes", "showOutdatedOnly": "Afficher uniquement les applications obsolètes",
"filter": "Filtre", "filter": "Filtre",
"filterApps": "Filtrer les applications", "filterApps": "Filtrer les applications",
@@ -91,76 +91,76 @@
"importExport": "Importer/Exporter", "importExport": "Importer/Exporter",
"settings": "Paramètres", "settings": "Paramètres",
"exportedTo": "Exporté vers {}", "exportedTo": "Exporté vers {}",
"obtainiumExport": "Exporter d'Obtainium", "obtainiumExport": "Exporter Obtainium",
"invalidInput": "Entrée invalide", "invalidInput": "Entrée invalide",
"importedX": "Importé {}", "importedX": "Importé {}",
"obtainiumImport": "Importer d'Obtainium", "obtainiumImport": "Importer Obtainium",
"importFromURLList": "Importer à partir de la liste d'URL", "importFromURLList": "Importer depuis une liste d'URL",
"searchQuery": "Requête", "searchQuery": "Requête de recherche",
"appURLList": "Liste d'URL d'application", "appURLList": "Liste d'URL de l'application",
"line": "Queue", "line": "File d'attente",
"searchX": "Rechercher {}", "searchX": "Rechercher {}",
"noResults": "Aucun résultat trouvé", "noResults": "Aucun résultat",
"importX": "Importer {}", "importX": "Importer {}",
"importedAppsIdDisclaimer": "Les applications importées peuvent s'afficher à tort comme \"Non installées\".\nPour résoudre ce problème, réinstallez-les via Obtainium.\nCela ne devrait pas affecter les données de l'application.\n\nN'affecte que les URL et les méthodes d'importation tierces.", "importedAppsIdDisclaimer": "Les applications importées peuvent s'afficher de manière incorrecte comme \"Non installées\".\nPour résoudre ce problème, réinstallez-les via Obtainium.\nCela n'affectera pas les données des applications. Cela n'affecte que la méthode d'importation par URL et par des tiers.",
"importErrors": "Erreurs d'importation", "importErrors": "Erreurs d'importation",
"importedXOfYApps": "{} sur {} applications importées.", "importedXOfYApps": "{} applications sur {} ont étés importées.",
"followingURLsHadErrors": "Les URL suivantes comportaient des erreurs :", "followingURLsHadErrors": "Les URL suivants comportent des erreurs :",
"selectURL": "Sélectionnez l'URL", "selectURL": "Sélectionner l'URL",
"selectURLs": "Sélectionnez les URLs", "selectURLs": "Sélectionner les URL",
"pick": "Prendre", "pick": "Choisir",
"theme": "Thème", "theme": "Thème",
"dark": "Sombre", "dark": "Sombre",
"light": "Clair", "light": "Clair",
"followSystem": "Suivre le système", "followSystem": "Correspondre au système",
"followSystemThemeExplanation": "Il n'est possible de suivre le thème du système qu'en utilisant des applications tierces.", "followSystemThemeExplanation": "Correspondre au thème du système est possible en utilisant des applications tierces.",
"useBlackTheme": "Utilisez le thème noir pur", "useBlackTheme": "Utiliser un thème Noir",
"appSortBy": "Applications triées par", "appSortBy": "Trier les applications par",
"authorName": "Auteur/Nom", "authorName": "Auteur/Nom",
"nameAuthor": "Nom/Auteur", "nameAuthor": "Nom/Auteur",
"asAdded": "Comme ajouté", "asAdded": "Date d'ajout",
"appSortOrder": "Ordre de tri des applications", "appSortOrder": "Ordre de tri des applications",
"ascending": "Ascendant", "ascending": "Ascendant",
"descending": "Descendant", "descending": "Descendant",
"bgUpdateCheckInterval": "Intervalle de vérification des mises à jour en arrière-plan", "bgUpdateCheckInterval": "Intervalle de recherche de mises à jour en arrière-plan",
"neverManualOnly": "Jamais - Manuel uniquement", "neverManualOnly": "Jamais - Manuellement uniquement",
"appearance": "Apparence", "appearance": "Apparence",
"showWebInAppView": "Afficher la page Web source dans la vue de l'application", "showWebInAppView": "Afficher la page Web source dans la vue Applications",
"pinUpdates": "Épingler les mises à jour dans la vue Top des applications", "pinUpdates": "Épingler les mises à jour en haut de la vue Applications",
"updates": "Mises à jour", "updates": "Mises à jour",
"sourceSpecific": "Spécifique à la source", "sourceSpecific": "Spécifique à la source",
"appSource": "Source de l'application", "appSource": "Source de l'application",
"noLogs": "Aucun journal", "noLogs": "Aucun journal",
"appLogs": "Journaux d'application", "appLogs": "Journaux d'applications",
"close": "Fermer", "close": "Fermer",
"share": "Partager", "share": "Partager",
"appNotFound": "Application introuvable", "appNotFound": "Application introuvable",
"obtainiumExportHyphenatedLowercase": "exportation d'Obtainium", "obtainiumExportHyphenatedLowercase": "export-obtainium",
"pickAnAPK": "Choisissez un APK", "pickAnAPK": "Selectionner une APK",
"appHasMoreThanOnePackage": "{} a plus d'un paquet :", "appHasMoreThanOnePackage": "{} a plus d'un paquet :",
"deviceSupportsXArch": "Votre appareil prend en charge l'architecture CPU {}.", "deviceSupportsXArch": "Votre appareil prend en charge l'architecture CPU {}.",
"deviceSupportsFollowingArchs": "Votre appareil prend en charge les architectures CPU suivantes :", "deviceSupportsFollowingArchs": "Votre appareil prend en charge les architectures CPU suivants : ",
"warning": "Avertissement", "warning": "Avertissement",
"sourceIsXButPackageFromYPrompt": "La source de l'application est '{}' mais la version du paquet provient de '{}'. Continuer?", "sourceIsXButPackageFromYPrompt": "La source de l'application est '{}' mais le paquet de mise à jour provient de '{}'. Continuer ?",
"updatesAvailable": "Mises à jour disponibles", "updatesAvailable": "Mises à jour disponibles",
"updatesAvailableNotifDescription": "Avertit l'utilisateur que des mises à jour sont disponibles pour une ou plusieurs applications suivies par Obtainium", "updatesAvailableNotifDescription": "Notifie à l'utilisateur que des mises à jour sont disponibles pour une ou plusieurs applications suivies par Obtainium.",
"noNewUpdates": "Aucune nouvelle mise à jour.", "noNewUpdates": "Aucune nouvelle mise à jour.",
"xHasAnUpdate": "{} a une mise à jour.", "xHasAnUpdate": "{} a une mise à jour.",
"appsUpdated": "Applications mises à jour", "appsUpdated": "Applications mises à jour",
"appsNotUpdated": "Échec de la mise à jour des applications", "appsNotUpdated": "Échec de la mise à jour des applications",
"appsUpdatedNotifDescription": "Avertit l'utilisateur que les mises à jour d'une ou plusieurs applications ont été appliquées en arrière-plan", "appsUpdatedNotifDescription": "Notifie à l'utilisateur que des mises à jour d'une ou plusieurs applications ont été installés en arrière-plan.",
"xWasUpdatedToY": "{} a été mis à jour pour {}.", "xWasUpdatedToY": "{} a été mis à jour en {}.",
"xWasNotUpdatedToY": "Échec de la mise à jour de {} vers {}.", "xWasNotUpdatedToY": "Échec de la mise à jour de {} vers {}.",
"errorCheckingUpdates": "Erreur lors de la vérification des mises à jour", "errorCheckingUpdates": "Erreur lors de la recherche de mises à jour",
"errorCheckingUpdatesNotifDescription": "Une notification qui s'affiche lorsque la vérification de la mise à jour en arrière-plan échoue", "errorCheckingUpdatesNotifDescription": "Notifie l'utilisateur lorsque la recherche de mises à jour en arrière-plan échoue.",
"appsRemoved": "Applications supprimées", "appsRemoved": "Applications supprimées",
"appsRemovedNotifDescription": "Avertit l'utilisateur qu'une ou plusieurs applications ont été supprimées en raison d'erreurs lors de leur chargement", "appsRemovedNotifDescription": "Notifie à l'utilisateur qu'une ou plusieurs applications ont été supprimées en raison d'erreurs lors de leur chargement.",
"xWasRemovedDueToErrorY": "{} a été supprimé en raison de cette erreur : {}", "xWasRemovedDueToErrorY": "{} a été supprimée en raison de cette erreur : {}",
"completeAppInstallation": "Installation complète de l'application", "completeAppInstallation": "Installation complète de l'application",
"obtainiumMustBeOpenToInstallApps": "Obtainium doit être ouvert pour installer des applications", "obtainiumMustBeOpenToInstallApps": "Obtainium doit être ouvert pour installer les applications",
"completeAppInstallationNotifDescription": "Demande à l'utilisateur de retourner sur Obtainium pour terminer l'installation d'une application", "completeAppInstallationNotifDescription": "Demande à l'utilisateur de retourner sur Obtainium pour terminer l'installation d'une application",
"checkingForUpdates": "Vérification des mises à jour", "checkingForUpdates": "Recherche de mises à jour",
"checkingForUpdatesNotifDescription": "Notification transitoire qui apparaît lors de la recherche de mises à jour", "checkingForUpdatesNotifDescription": "Notification temporaire qui apparaît lors de la recherche de mises à jour",
"pleaseAllowInstallPerm": "Veuillez autoriser Obtainium à installer des applications", "pleaseAllowInstallPerm": "Veuillez autoriser Obtainium à installer des applications",
"trackOnly": "Suivi uniquement", "trackOnly": "Suivi uniquement",
"errorWithHttpStatusCode": "Erreur {}", "errorWithHttpStatusCode": "Erreur {}",
@@ -168,165 +168,167 @@
"unknown": "Inconnu", "unknown": "Inconnu",
"none": "Aucun", "none": "Aucun",
"never": "Jamais", "never": "Jamais",
"latestVersionX": "Dernière version: {}", "latestVersionX": "Dernière version : {}",
"installedVersionX": "Version installée : {}", "installedVersionX": "Version installée : {}",
"lastUpdateCheckX": "Vérification de la dernière mise à jour : {}", "lastUpdateCheckX": "Dernière recherche de mises à jour : {}",
"remove": "Retirer", "remove": "Supprimer",
"yesMarkUpdated": "Oui, marquer comme mis à jour", "yesMarkUpdated": "Oui, Marquer comme étant à jour",
"fdroid": "F-Droid Officiel", "fdroid": "F-Droid Officiel",
"appIdOrName": "ID ou nom de l'application", "appIdOrName": "ID ou nom de l'application",
"appId": "ID de l'application", "appId": "ID de l'application",
"appWithIdOrNameNotFound": "Aucune application n'a été trouvée avec cet identifiant ou ce nom", "appWithIdOrNameNotFound": "Aucune application n'a été trouvée avec cet identifiant ou ce nom",
"reposHaveMultipleApps": "Les dépôts peuvent contenir plusieurs applications", "reposHaveMultipleApps": "Les dépôts peuvent contenir plusieurs applications",
"fdroidThirdPartyRepo": "Dépôt tiers F-Droid", "fdroidThirdPartyRepo": "Dépôt tiers F-Droid",
"steamMobile": "Vapeur Mobile", "steamMobile": "Steam Mobile",
"steamChat": "Chat sur Steam", "steamChat": "Steam Chat",
"install": "Installer", "install": "Installer",
"markInstalled": "Marquer installée", "markInstalled": "Marquer comme étant installé",
"update": "Mettre à jour", "update": "Mettre à jour",
"markUpdated": "Marquer à jour", "markUpdated": "Marquer comme étant à jour",
"additionalOptions": "Options additionnelles", "additionalOptions": "Options supplémentaires",
"disableVersionDetection": "Désactiver la détection de version", "disableVersionDetection": "Désactiver la détection de la version",
"noVersionDetectionExplanation": "Cette option ne doit être utilisée que pour les applications où la détection de version ne fonctionne pas correctement.", "noVersionDetectionExplanation": "Cette option ne doit être utilisée que pour les applications où la détection de la version ne fonctionne pas correctement.",
"downloadingX": "Téléchargement {}", "downloadingX": "Téléchargement {}",
"downloadX": "Télécharger {}", "downloadX": "Télécharger {}",
"downloadedX": "Téléchargé {}", "downloadedX": "Téléchargé {}",
"releaseAsset": "Actif libéré", "releaseAsset": "Version actif",
"downloadNotifDescription": "Avertit l'utilisateur de la progression du téléchargement d'une application", "downloadNotifDescription": "Notifie l'utilisateur sur l'avancement du téléchargement d'une application",
"noAPKFound": "Aucun APK trouvé", "noAPKFound": "Aucun APK trouvé",
"noVersionDetection": "Aucune de détection de version", "noVersionDetection": "Aucune version trouvée",
"categorize": "Catégoriser", "categorize": "Catégoriser",
"categories": "Catégories", "categories": "Catégories",
"category": "Catégorie", "category": "Catégorie",
"noCategory": "Aucune catégorie", "noCategory": "Aucune Catégorie",
"noCategories": "Aucune catégorie", "noCategories": "Aucune Catégories",
"deleteCategoriesQuestion": "Supprimer les catégories ?", "deleteCategoriesQuestion": "Supprimer les Catégories ?",
"categoryDeleteWarning": "Toutes les applications dans les catégories supprimées seront définies sur non catégorisées.", "categoryDeleteWarning": "Toutes les applications des catégories supprimées seront définies comme non catégorisées.",
"addCategory": "Ajouter une catégorie", "addCategory": "Ajouter une catégorie",
"label": "Étiquette", "label": "Nom",
"language": "Langue", "language": "Langue",
"copiedToClipboard": "Copié dans le presse-papier", "copiedToClipboard": "Copié dans le presse-papier",
"storagePermissionDenied": "Autorisation de stockage refusée", "storagePermissionDenied": "Permission de stockage refusée",
"selectedCategorizeWarning": "Cela remplacera toutes les catégorie définies pour les applications sélectionnées.", "selectedCategorizeWarning": "Cela va remplacer toutes les catégories définies des applications sélectionnées.",
"filterAPKsByRegEx": "Filtrer les APK par expression régulière", "filterAPKsByRegEx": "Filtrer les APK par expression régulière",
"removeFromObtainium": "Supprimer d'Obtainium", "removeFromObtainium": "Supprimer d'Obtainium",
"uninstallFromDevice": "Désinstaller de l'appareil", "uninstallFromDevice": "Désinstaller de l'appareil",
"onlyWorksWithNonVersionDetectApps": "Fonctionne uniquement pour les applications avec la détection de version désactivée.", "onlyWorksWithNonVersionDetectApps": "Ne fonctionne que pour les applications dont la détection de la version est désactivée.",
"releaseDateAsVersion": "Utiliser la date de sortie comme version", "releaseDateAsVersion": "Utiliser la date de sortie comme version",
"releaseDateAsVersionExplanation": "Cette option ne doit être utilisée que pour les applications la détection de version ne fonctionne pas correctement, mais dont une date de sortie est disponible.", "releaseDateAsVersionExplanation": "Cette option ne doit être utilisée que pour les applications pour lesquelles la détection de la version ne fonctionne pas correctement, mais pour lesquelles une date de sortie est disponible.",
"changes": "Changements", "changes": "Correctifs",
"releaseDate": "Date de sortie", "releaseDate": "Date de sortie",
"importFromURLsInFile": "Importer à partir d'URL dans un fichier (comme OPML)", "importFromURLsInFile": "Importer à partir des URLs d'un fichier (Comme OPML)",
"versionDetectionExplanation": "Réconcilier la chaîne de version avec la version détectée à partir du système d'exploitation", "versionDetectionExplanation": "Reporter la chaîne de version par la version détectée par le système d'exploitation",
"versionDetection": "Détection des versions", "versionDetection": "Détection de la version",
"standardVersionDetection": "Détection de version standard", "standardVersionDetection": "Détection de la version standard",
"groupByCategory": "Regrouper par catégorie", "groupByCategory": "Grouper par Catégorie",
"autoApkFilterByArch": "Si possible, essayez de filtrer les APK par architecture CPU", "autoApkFilterByArch": "Essayer de filtrer les APKs par architecture CPU si possible",
"overrideSource": "Remplacer la source", "overrideSource": "Remplacer la source",
"dontShowAgain": "Ne plus montrer", "dontShowAgain": "Ne plus afficher",
"dontShowTrackOnlyWarnings": "Ne pas afficher l'avertissement 'Track-Only'", "dontShowTrackOnlyWarnings": "Ne plus afficher les erreurs 'Suivi uniquement'",
"dontShowAPKOriginWarnings": "Ne pas afficher les avertissements sur l'origine de l'APK", "dontShowAPKOriginWarnings": "Ne plus afficher les erreurs sur l'origine de l'APK",
"moveNonInstalledAppsToBottom": "Déplacer les applications non installées vers le bas de la vue Applications", "moveNonInstalledAppsToBottom": "Déplacer les applications non installés vers le bas de la vue Applications",
"gitlabPATLabel": "Jeton d'accès personnel GitLab", "gitlabPATLabel": "Jeton d'accès personnel GitLab",
"about": "À propos de", "about": "À propos",
"requiresCredentialsInSettings": "{}: Cela nécessite des identifiants supplémentaires (dans Paramètres)", "requiresCredentialsInSettings": "{} a besoin d'un complément d'information (dans les Paramètres)",
"checkOnStart": "Vérifier les mises à jour au démarrage", "checkOnStart": "Rechercher les mises à jour au démarrage",
"tryInferAppIdFromCode": "Essayez de déduire l'ID de l'application à partir du code source", "tryInferAppIdFromCode": "Essayer de déduire l'identifiant de l'application à partir du code source",
"removeOnExternalUninstall": "Supprimer automatiquement les applications désinstallées en externe", "removeOnExternalUninstall": "Supprimer automatiquement les applications désinstallées en externe",
"pickHighestVersionCode": "Sélectionner automatiquement le code de version de l'APK la plus élevée", "pickHighestVersionCode": "Sélectionner automatiquement la version la plus récente du code APK",
"checkUpdateOnDetailPage": "Vérifier les mises à jour lors de l'ouverture de la page détaillée d'une application", "checkUpdateOnDetailPage": "Rechercher les mises à jour lors de l'ouverture de la page détaillée d'une application",
"disablePageTransitions": "Désactiver les animations de transition de page", "disablePageTransitions": "Désactiver les animations de transition de page",
"reversePageTransitions": "Inverser les animations de transition de page", "reversePageTransitions": "Inverser les animations de transition de page",
"minStarCount": "Nombre minimum d'étoiles", "minStarCount": "Nombre minimum d'étoiles",
"addInfoBelow": "Ajoutez ces informations ci-dessous.", "addInfoBelow": "Ajoutez cette information ci-dessous.",
"addInfoInSettings": "Ajoutez ces informations dans les paramètres.", "addInfoInSettings": "Ajoutez cette information dans les paramètres.",
"githubSourceNote": "La limite de débit GitHub peut être évitée à l'aide d'une clé API.", "githubSourceNote": "La limitation du débit de GitHub peut être évitée à l'aide d'une clé d'API.",
"sortByLastLinkSegment": "Trier uniquement sur le dernier segment du lien", "sortByLastLinkSegment": "Trier par le dernier segment du lien",
"filterReleaseNotesByRegEx": "Filtrer les notes de version par expression régulière", "filterReleaseNotesByRegEx": "Filtrer les notes de version par expression régulière",
"customLinkFilterRegex": "Filtre du lien APK personnalisé par expression régulière (par défaut '.apk$')", "customLinkFilterRegex": "Filtre de lien APK personnalisé par expression régulière (par défaut '.apk$')",
"appsPossiblyUpdated": "Tentative de mise à jour de l'application", "appsPossiblyUpdated": "Tentative de mise à jour des applications",
"appsPossiblyUpdatedNotifDescription": "Avertit l'utilisateur que des mises à jour d'une ou plusieurs applications ont été potentiellement appliquées en arrière-plan", "appsPossiblyUpdatedNotifDescription": "Notifie à l'utilisateur que des mises à jour d'une ou plusieurs applications ont potentiellement été appliquées en arrière-plan",
"xWasPossiblyUpdatedToY": "{} a peut-être été mis à jour vers {}.", "xWasPossiblyUpdatedToY": "{} peut être mis à jour en {}.",
"enableBackgroundUpdates": "Activer les mises à jour en arrière-plan", "enableBackgroundUpdates": "Activer les mises à jour en arrière-plan",
"backgroundUpdateReqsExplanation": "Les mises à jour en arrière-plan peuvent ne pas être possibles pour toutes les applications.", "backgroundUpdateReqsExplanation": "Les mises à jour en arrière-plan peuvent ne pas être possibles pour toutes les applications.",
"backgroundUpdateLimitsExplanation": "Le succès d'une installation en arrière-plan ne peut être déterminé qu'à l'ouverture d'Obtainium.", "backgroundUpdateLimitsExplanation": "Le résultat d'une installation en arrière-plan ne peut être déterminé qu'à l'ouverture d'Obtainium.",
"verifyLatestTag": "Vérifiez la balise 'Latest'", "verifyLatestTag": "Vérifier la balise 'latest'",
"intermediateLinkRegex": " Filtrer un lien \" intermédiaire \" à visiter ", "intermediateLinkRegex": "Filtrer un lien 'intermédiaire' à visiter",
"filterByLinkText": "Filtrer les liens par le texte du lien", "filterByLinkText": "Filtrer les liens par texte du lien",
"intermediateLinkNotFound": "Lien intermédiaire introuvable", "intermediateLinkNotFound": "Lien intermédiaire introuvable",
"intermediateLink": "Lien intermédiaire", "intermediateLink": "Lien intermédiaire",
"exemptFromBackgroundUpdates": "Exempté des mises à jour en arrière-plan (si activé)", "exemptFromBackgroundUpdates": "Exclure de la mise à jour en arrière-plan (si activé)",
"bgUpdatesOnWiFiOnly": "Désactiver les mises à jour en arrière-plan lorsque vous n'êtes pas connecté au WiFi", "bgUpdatesOnWiFiOnly": "Désactiver les mises à jour en arrière-plan lorsque vous n'êtes pas en WiFi",
"autoSelectHighestVersionCode": "Sélection automatique du code de version de l'APK la plus élevée", "autoSelectHighestVersionCode": "Sélectionner automatiquement la version la plus récente du code APK",
"versionExtractionRegEx": "Expression régulière d'extraction de version", "versionExtractionRegEx": "Extraire la version par Expression régulière",
"matchGroupToUse": "Groupe de correspondance pour l'expression régulière d'extraction de version", "trimVersionString": "Découper la version par Expression régulière",
"highlightTouchTargets": "Mettre en évidence les cibles tactiles moins évidentes", "matchGroupToUseForX": "Groupe de correspondance à utiliser pour \"{}\"",
"pickExportDir": "Choisir le répertoire d'exportation", "matchGroupToUse": "Groupe de correspondance à utiliser pour l'extraction de la version par Expression régulière",
"autoExportOnChanges": "Exporter automatiquement après modification", "highlightTouchTargets": "Mettre en évidence les touches moins évidentes",
"pickExportDir": "Selectionner le dossier pour l'exportation",
"autoExportOnChanges": "Exportation automatique lors de modification",
"includeSettings": "Inclure les paramètres", "includeSettings": "Inclure les paramètres",
"filterVersionsByRegEx": "Filtrer les versions par expression régulière", "filterVersionsByRegEx": "Filtrer les versions par expression régulière",
"trySelectingSuggestedVersionCode": "Essayez de sélectionner le code de la version APK suggérée", "trySelectingSuggestedVersionCode": "Essayez de sélectionner la version suggérée du Code APK",
"dontSortReleasesList": "Conserver l'ordre des version de l'API", "dontSortReleasesList": "Conserver l'ordre de la version de l'API",
"reverseSort": "Tri inversé", "reverseSort": "Tri inversé",
"takeFirstLink": "Prendre le premier lien", "takeFirstLink": "Utiliser le premier lien",
"skipSort": "Sauter le tri", "skipSort": "Ignorer le tri",
"debugMenu": "Menu de débogage", "debugMenu": "Menu de déboggage",
"bgTaskStarted": "Tâche en arrière-plan démarrée - vérifier les journaux.", "bgTaskStarted": "Tâche en arrière plan démarrée - vérifier les journaux.",
"runBgCheckNow": "Exécuter maintenant la vérification de la mise à jour en arrière-plan", "runBgCheckNow": "Exécuter la recherche de la mise à jour en l'arrière-plan maintenant",
"versionExtractWholePage": "Appliquer l'expression régulière d'extraction de version sur l'ensemble de la page", "versionExtractWholePage": "Appliquer l'extraction de la version par expression régulière à l'ensemble de la page",
"installing": "Installation", "installing": "Installation",
"skipUpdateNotifications": "Ignorer les notifications de mise à jour", "skipUpdateNotifications": "Ignorer les notifications de mise à jour",
"updatesAvailableNotifChannel": "Mises à jour disponibles", "updatesAvailableNotifChannel": "Mises à jour disponibles",
"appsUpdatedNotifChannel": "Applications mises à jour", "appsUpdatedNotifChannel": "Applications mises à jour",
"appsPossiblyUpdatedNotifChannel": "Tentative de mise à jour de l'application", "appsPossiblyUpdatedNotifChannel": "Essayer de mettre à jour les applications",
"errorCheckingUpdatesNotifChannel": "Erreur lors de la vérification des mises à jour", "errorCheckingUpdatesNotifChannel": "Erreur lors de la recherche de mises à jour",
"appsRemovedNotifChannel": "Applications supprimées", "appsRemovedNotifChannel": "Applications supprimées",
"downloadingXNotifChannel": "Téléchargement {}", "downloadingXNotifChannel": "Téléchargement {}",
"completeAppInstallationNotifChannel": "Installation complète de l'application", "completeAppInstallationNotifChannel": "Installation complète de l'application",
"checkingForUpdatesNotifChannel": "Vérification des mises à jour", "checkingForUpdatesNotifChannel": "Recherche de mises à jour",
"onlyCheckInstalledOrTrackOnlyApps": "Vérifiez uniquement les mises à jour des applications installées et 'Track-Only'", "onlyCheckInstalledOrTrackOnlyApps": "Rechercher uniquement les mises à jour des applications installées et des applications 'Suivi uniquement'",
"supportFixedAPKURL": "Prise en charge des URL APK fixes", "supportFixedAPKURL": "Prise en charge des URL APK fixes",
"selectX": "Sélectionner {}", "selectX": "Selectionner {}",
"parallelDownloads": "Autoriser les téléchargements parallèles", "parallelDownloads": "Autoriser les téléchargements simultanés",
"useShizuku": "Utiliser Shizuku ou Sui pour l'installation", "useShizuku": "Utiliser Shizuku ou Sui pour l'installation",
"shizukuBinderNotFound": "Service Shizuku compatible non trouvé", "shizukuBinderNotFound": "Le service Shizuku n'es pas démarré",
"shizukuOld": "Ancienne version de Shizuku (<11) - la mettre à jour", "shizukuOld": "Ancienne version de Shizuku (<11) - veuillez le mettre à jour",
"shizukuOldAndroidWithADB": "Shizuku fonctionne sur Android < 8.1 avec ADB - mettre à jour Android ou utiliser Sui à la place", "shizukuOldAndroidWithADB": "Shizuku fonctionne sur Android < 8.1 avec ADB - veuillez mettre à jour Android ou utiliser Sui à la place",
"shizukuPretendToBeGooglePlay": "Définir Google Play comme source d'installation (si Shizuku est utilisé)", "shizukuPretendToBeGooglePlay": "Définir Google Play comme source d'installation (si Shizuku est utilisé)",
"useSystemFont": "Utiliser la police du système", "useSystemFont": "Utiliser la police du système",
"useVersionCodeAsOSVersion": "Utiliser le code de version de l'application comme version détectée par le système d'exploitation", "useVersionCodeAsOSVersion": "Utiliser le code de version de l'application détectée par le système d'exploitation",
"requestHeader": "En-tête de demande", "requestHeader": "Intitulé de la demande",
"useLatestAssetDateAsReleaseDate": "Utiliser le dernier élément téléversé comme date de sortie", "useLatestAssetDateAsReleaseDate": "Utiliser le dernier élément mis en ligne comme date de sortie",
"defaultPseudoVersioningMethod": "Méthode de pseudo-version par défaut", "defaultPseudoVersioningMethod": "Methode de version fictive par défaut",
"partialAPKHash": "Hash APK partiel", "partialAPKHash": "Hash partiel de l'APK",
"APKLinkHash": "Hash de lien APK", "APKLinkHash": "Hash du lien APK",
"directAPKLink": "Lien APK direct", "directAPKLink": "Lien direct de l'APK",
"pseudoVersionInUse": "Une pseudo-version est utilisée", "pseudoVersionInUse": "Version fictive utilisé",
"installed": "Installée", "installed": "Installée",
"latest": "Dernier", "latest": "Dernière version",
"invertRegEx": "Inverser l'expression régulière", "invertRegEx": "Inverser l'expression régulière",
"note": "Note", "note": "Note",
"selfHostedNote": "La liste déroulante \"{}\" peut être utilisée pour accéder aux instances auto-hébergées/personnalisées de n'importe quelle source.", "selfHostedNote": "La liste déroulante \"{}\" peut être utilisé pour accéder à des instances auto-hébergées/personnalisées de n'importe quelle source.",
"badDownload": "L'APK n'a pas pu être analysé (téléchargement incompatible ou partiel)", "badDownload": "L'APK n'a pas pu être analysé (téléchargement incompatible ou partiel)",
"beforeNewInstallsShareToAppVerifier": "Partager les nouvelles applications avec AppVerifier (si disponible)", "beforeNewInstallsShareToAppVerifier": "Partager les nouvelles applications avec AppVerifier (si disponible)",
"appVerifierInstructionToast": "Partagez avec AppVerifier, puis revenez ici lorsque vous êtes prêt.", "appVerifierInstructionToast": "Partagez avec AppVerifier, puis revenez ici lorsque tout est prêt.",
"wiki": "Aide/Wiki", "wiki": "Aide/Wiki",
"crowdsourcedConfigsLabel": "Configurations d'applications par la foule (utilisation à vos risques et périls)", "crowdsourcedConfigsLabel": "Configurations d'applications par la communauté (à utiliser à vos risques et périls)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Supprimer l'application ?", "one": "Supprimer l'application?",
"other": "Supprimer les applications ?" "other": "Supprimer les applications?"
}, },
"tooManyRequestsTryAgainInMinutes": { "tooManyRequestsTryAgainInMinutes": {
"one": "Trop de demandes (taux limité) - réessayez dans {} minute", "one": "Trop de requêtes (taux limité) - réessayez dans {} minute",
"other": "Trop de demandes (taux limité) - réessayez dans {} minutes" "other": "Trop de requêtes (taux limité) - réessayez dans {} minutes"
}, },
"bgUpdateGotErrorRetryInMinutes": { "bgUpdateGotErrorRetryInMinutes": {
"one": "La vérification de la mise à jour en arrière-plan a rencontré un {}, une nouvelle tentative de vérification sera planifié dans {} minute", "one": "La recherche de mise à jour en arrière-plan a rencontré un {}, une nouvelle tentative programmée dans {} minute",
"other": "La vérification de la mise à jour en arrière-plan a rencontré un {}, une nouvelle tentative de vérification sera planifié dans {} minute" "other": "La recherche de mise à jour en arrière-plan a rencontré un {}, une nouvelle tentative programmée dans {} minutes"
}, },
"bgCheckFoundUpdatesWillNotifyIfNeeded": { "bgCheckFoundUpdatesWillNotifyIfNeeded": {
"one": "La vérification des mises à jour en arrière-plan a trouvée {} mise à jour - l'utilisateur sera notifié si nécessaire", "one": "La recherche de mises à jour en arrière-plan à trouvée {} mise à jour - l'utilisateur sera notifié si nécessaire",
"other": "La vérification des mises à jour en arrière-plan a trouvé {} mises à jour - l'utilisateur sera notifié si nécessaire" "other": "La recherche de mises à jour en arrière-plan à trouvée {} mises à jour - l'utilisateur sera notifié si nécessaire"
}, },
"apps": { "apps": {
"one": "{} Application", "one": "{} Application",
@@ -337,7 +339,7 @@
"other": "{} URL" "other": "{} URL"
}, },
"minute": { "minute": {
"one": "{} Minutes", "one": "{} Minute",
"other": "{} Minutes" "other": "{} Minutes"
}, },
"hour": { "hour": {
@@ -349,24 +351,24 @@
"other": "{} Jours" "other": "{} Jours"
}, },
"clearedNLogsBeforeXAfterY": { "clearedNLogsBeforeXAfterY": {
"one": "{n} journal effacé (avant = {before}, après = {after})", "one": "Nettoyage du journal {n} (avant = {before}, après = {after})",
"other": "{n} journaux effacés (avant = {before}, après = {after})" "other": "Nettoyage des journaux {n} (avant = {before}, après = {after})"
}, },
"xAndNMoreUpdatesAvailable": { "xAndNMoreUpdatesAvailable": {
"one": "{} et 1 autre application ont des mises à jour.", "one": "{} et 1 autre application ont des mises à jour.",
"other": "{} et {} autres applications ont des mises à jour." "other": "{} et {} autres applications ont des mises à jour."
}, },
"xAndNMoreUpdatesInstalled": { "xAndNMoreUpdatesInstalled": {
"one": "{} et 1 autre application ont été mises à jour.", "one": "{} et 1 autre application ont étés mis à jour.",
"other": "{} et {} autres applications ont été mises à jour." "other": "{} et {} autres applications ont étés mis à jour."
}, },
"xAndNMoreUpdatesFailed": { "xAndNMoreUpdatesFailed": {
"one": "Échec de la mise à jour de {} et d'une autre application.", "one": "Échec de la mise à jour de {} et 1 autre application.",
"other": "Échec de la mise à jour de {} et {} autres applications." "other": "Échec de la mise à jour de {} et {} autres applications."
}, },
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"une": "{} et 1 application supplémentaire ont peut-être été mises à jour.", "one": "{} et 1 autre application ont peut-être étés mis à jour.",
"other": "{} et {} autres applications peuvent avoir été mises à jour." "other": "{} et {} autres applications ont peut-être étés mis à jour."
}, },
"apk": { "apk": {
"one": "{} APK", "one": "{} APK",

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Tiltsa le a háttérben frissítéseket, ha nincs Wi-Fi-n", "bgUpdatesOnWiFiOnly": "Tiltsa le a háttérben frissítéseket, ha nincs Wi-Fi-n",
"autoSelectHighestVersionCode": "A legmagasabb verziószámú APK auto. kiválasztása", "autoSelectHighestVersionCode": "A legmagasabb verziószámú APK auto. kiválasztása",
"versionExtractionRegEx": "Verzió kibontása reguláris kifejezéssel", "versionExtractionRegEx": "Verzió kibontása reguláris kifejezéssel",
"trimVersionString": "Trim Version String RegEx-szel",
"matchGroupToUseForX": "A \"{}\" csoporthoz használandó csoport egyeztetése",
"matchGroupToUse": "Párosítsa a csoportot a használathoz", "matchGroupToUse": "Párosítsa a csoportot a használathoz",
"highlightTouchTargets": "Emelje ki a kevésbé nyilvánvaló érintési célokat", "highlightTouchTargets": "Emelje ki a kevésbé nyilvánvaló érintési célokat",
"pickExportDir": "Válassza az Exportálási könyvtárat", "pickExportDir": "Válassza az Exportálási könyvtárat",

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Disattiva aggiornamenti in secondo piano quando non si usa il WiFi", "bgUpdatesOnWiFiOnly": "Disattiva aggiornamenti in secondo piano quando non si usa il WiFi",
"autoSelectHighestVersionCode": "Auto-seleziona APK con versionCode più alto", "autoSelectHighestVersionCode": "Auto-seleziona APK con versionCode più alto",
"versionExtractionRegEx": "RegEx di estrazione versione", "versionExtractionRegEx": "RegEx di estrazione versione",
"trimVersionString": "Tagliare la stringa della versione con RegEx",
"matchGroupToUseForX": "Gruppo di corrispondenza da utilizzare per \"{}\"",
"matchGroupToUse": "Gruppo da usare", "matchGroupToUse": "Gruppo da usare",
"highlightTouchTargets": "Evidenzia elementi toccabili meno ovvi", "highlightTouchTargets": "Evidenzia elementi toccabili meno ovvi",
"pickExportDir": "Scegli cartella esp.", "pickExportDir": "Scegli cartella esp.",

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "WiFiを使用していない場合、バックグラウンドアップデートを無効にする", "bgUpdatesOnWiFiOnly": "WiFiを使用していない場合、バックグラウンドアップデートを無効にする",
"autoSelectHighestVersionCode": "最も高いバージョンコードのAPKを自動で選択する", "autoSelectHighestVersionCode": "最も高いバージョンコードのAPKを自動で選択する",
"versionExtractionRegEx": "バージョン抽出の正規表現", "versionExtractionRegEx": "バージョン抽出の正規表現",
"trimVersionString": "正規表現でバージョン文字列をトリムする",
"matchGroupToUseForX": "\"{}\"に使用するマッチしたグループ",
"matchGroupToUse": "使用するマッチしたグループ", "matchGroupToUse": "使用するマッチしたグループ",
"highlightTouchTargets": "目立たないタップ可能な対象をハイライトする", "highlightTouchTargets": "目立たないタップ可能な対象をハイライトする",
"pickExportDir": "エクスポートディレクトリを選択", "pickExportDir": "エクスポートディレクトリを選択",

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Achtergrond-updates uitschakelen wanneer niet verbonden met WiFi", "bgUpdatesOnWiFiOnly": "Achtergrond-updates uitschakelen wanneer niet verbonden met WiFi",
"autoSelectHighestVersionCode": "De APK met de hoogste versiecode automatisch selecteren", "autoSelectHighestVersionCode": "De APK met de hoogste versiecode automatisch selecteren",
"versionExtractionRegEx": "Reguliere expressie voor versie-extractie", "versionExtractionRegEx": "Reguliere expressie voor versie-extractie",
"trimVersionString": "Versie string trimmen met RegEx",
"matchGroupToUseForX": "Overeenkomende groep te gebruiken voor \"{}\"",
"matchGroupToUse": "Overeenkomende groep om te gebruiken voor de reguliere expressie voor versie-extractie", "matchGroupToUse": "Overeenkomende groep om te gebruiken voor de reguliere expressie voor versie-extractie",
"highlightTouchTargets": "Minder voor de hand liggende aanraakdoelen markeren.", "highlightTouchTargets": "Minder voor de hand liggende aanraakdoelen markeren.",
"pickExportDir": "Kies de exportmap", "pickExportDir": "Kies de exportmap",

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Wyłącz aktualizacje w tle, gdy nie ma połączenia z Wi-Fi", "bgUpdatesOnWiFiOnly": "Wyłącz aktualizacje w tle, gdy nie ma połączenia z Wi-Fi",
"autoSelectHighestVersionCode": "Automatycznie wybierz najwyższy kod wersji APK", "autoSelectHighestVersionCode": "Automatycznie wybierz najwyższy kod wersji APK",
"versionExtractionRegEx": "Wyrażenie regularne wyodrębniające wersję", "versionExtractionRegEx": "Wyrażenie regularne wyodrębniające wersję",
"trimVersionString": "Przycinanie łańcucha wersji za pomocą RegEx",
"matchGroupToUseForX": "Dopasuj grupę do użycia dla \"{}\"",
"matchGroupToUse": "Dopasuj grupę do użycia dla wyrażenia regularnego wyodrębniania wersji", "matchGroupToUse": "Dopasuj grupę do użycia dla wyrażenia regularnego wyodrębniania wersji",
"highlightTouchTargets": "Wyróżnij mniej oczywiste elementy dotykowe", "highlightTouchTargets": "Wyróżnij mniej oczywiste elementy dotykowe",
"pickExportDir": "Wybierz katalog eksportu", "pickExportDir": "Wybierz katalog eksportu",

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Desative as atualizações em segundo-plano quando não estiver conectado no Wi-Fi", "bgUpdatesOnWiFiOnly": "Desative as atualizações em segundo-plano quando não estiver conectado no Wi-Fi",
"autoSelectHighestVersionCode": "Auto-selecionar a versão mais recente", "autoSelectHighestVersionCode": "Auto-selecionar a versão mais recente",
"versionExtractionRegEx": "Regex de extração de versão", "versionExtractionRegEx": "Regex de extração de versão",
"trimVersionString": "Cortar a cadeia de caracteres da versão com RegEx",
"matchGroupToUseForX": "Grupo de correspondência a utilizar para \"{}\"",
"matchGroupToUse": "Grupo correspondente a ser usado no Regex de extração de versão", "matchGroupToUse": "Grupo correspondente a ser usado no Regex de extração de versão",
"highlightTouchTargets": "Realçar áreas sensíveis ao toque que são menos óbvias", "highlightTouchTargets": "Realçar áreas sensíveis ao toque que são menos óbvias",
"pickExportDir": "Escolher diretório para exportação", "pickExportDir": "Escolher diretório para exportação",

View File

@@ -9,7 +9,7 @@
"placeholder": "Заполнитель", "placeholder": "Заполнитель",
"someErrors": "Возникли некоторые ошибки", "someErrors": "Возникли некоторые ошибки",
"unexpectedError": "Неожиданная ошибка", "unexpectedError": "Неожиданная ошибка",
"ok": "Ok", "ok": "Ок",
"and": "и", "and": "и",
"githubPATLabel": "Персональный токен доступа GitHub\n(увеличивает лимит запросов)", "githubPATLabel": "Персональный токен доступа GitHub\n(увеличивает лимит запросов)",
"includePrereleases": "Включить предварительные релизы", "includePrereleases": "Включить предварительные релизы",
@@ -129,13 +129,13 @@
"pinUpdates": "Отображать обновления приложений сверху списка", "pinUpdates": "Отображать обновления приложений сверху списка",
"updates": "Обновления", "updates": "Обновления",
"sourceSpecific": "Настройки источников", "sourceSpecific": "Настройки источников",
"appSource": "Исходный код", "appSource": "Источник",
"noLogs": "Нет журналов", "noLogs": "Нет журналов",
"appLogs": "Логи", "appLogs": "Логи",
"close": "Закрыть", "close": "Закрыть",
"share": "Поделиться", "share": "Поделиться",
"appNotFound": "Приложение не найдено", "appNotFound": "Приложение не найдено",
"obtainiumExportHyphenatedLowercase": "получение-экспорт", "obtainiumExportHyphenatedLowercase": "экспорт-obtainium",
"pickAnAPK": "Выберите APK-файл", "pickAnAPK": "Выберите APK-файл",
"appHasMoreThanOnePackage": "{} имеет более одного пакета:", "appHasMoreThanOnePackage": "{} имеет более одного пакета:",
"deviceSupportsXArch": "Ваше устройство поддерживает архитектуру процессора {}", "deviceSupportsXArch": "Ваше устройство поддерживает архитектуру процессора {}",
@@ -179,8 +179,8 @@
"appWithIdOrNameNotFound": "Приложение с таким ID или названием не было найдено", "appWithIdOrNameNotFound": "Приложение с таким ID или названием не было найдено",
"reposHaveMultipleApps": "В хранилище несколько приложений", "reposHaveMultipleApps": "В хранилище несколько приложений",
"fdroidThirdPartyRepo": "Сторонние репозитории F-Droid", "fdroidThirdPartyRepo": "Сторонние репозитории F-Droid",
"steamMobile": "Стим Мобайл", "steamMobile": "Приложение Steam",
"steamChat": "Стим-чат", "steamChat": "Steam Chat",
"install": "Установить", "install": "Установить",
"markInstalled": "Пометить как установленное", "markInstalled": "Пометить как установленное",
"update": "Обновить", "update": "Обновить",
@@ -191,7 +191,7 @@
"downloadingX": "Загрузка {}", "downloadingX": "Загрузка {}",
"downloadX": "Скачать {}", "downloadX": "Скачать {}",
"downloadedX": "Загружено {}", "downloadedX": "Загружено {}",
"releaseAsset": "Освобождение актива", "releaseAsset": "Релизный объект",
"downloadNotifDescription": "Уведомляет пользователя о прогрессе загрузки приложения", "downloadNotifDescription": "Уведомляет пользователя о прогрессе загрузки приложения",
"noAPKFound": "APK не найден", "noAPKFound": "APK не найден",
"noVersionDetection": "Обнаружение версий отключено", "noVersionDetection": "Обнаружение версий отключено",
@@ -254,11 +254,13 @@
"intermediateLinkRegex": "Фильтр для \"промежуточной\" ссылки для посещения", "intermediateLinkRegex": "Фильтр для \"промежуточной\" ссылки для посещения",
"filterByLinkText": "Фильтрация ссылок по тексту ссылки", "filterByLinkText": "Фильтрация ссылок по тексту ссылки",
"intermediateLinkNotFound": "Промежуточная ссылка не найдена", "intermediateLinkNotFound": "Промежуточная ссылка не найдена",
"intermediateLink": "Промежуточное звено", "intermediateLink": "Промежуточная ссылка",
"exemptFromBackgroundUpdates": "Исключить из фоновых обновлений (если включено)", "exemptFromBackgroundUpdates": "Исключить из фоновых обновлений (если включено)",
"bgUpdatesOnWiFiOnly": "Отключить фоновые обновления, если нет соединения с Wi-Fi", "bgUpdatesOnWiFiOnly": "Отключить фоновые обновления, если нет соединения с Wi-Fi",
"autoSelectHighestVersionCode": "Автоматически выбирать APK с актуальной версией кода", "autoSelectHighestVersionCode": "Автоматически выбирать APK с актуальной версией кода",
"versionExtractionRegEx": "Регулярное выражение для извлечения версии", "versionExtractionRegEx": "Регулярное выражение для извлечения версии",
"trimVersionString": "Обрезка строки версии с помощью RegEx",
"matchGroupToUseForX": "Группа соответствия, которую следует использовать для \"{}\"",
"matchGroupToUse": "Выберите группу для использования", "matchGroupToUse": "Выберите группу для использования",
"highlightTouchTargets": "Выделить менее очевидные элементы управления касанием", "highlightTouchTargets": "Выделить менее очевидные элементы управления касанием",
"pickExportDir": "Выбрать каталог для экспорта", "pickExportDir": "Выбрать каталог для экспорта",

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Inaktivera Bakgrundsuppdateringar utan WiFi", "bgUpdatesOnWiFiOnly": "Inaktivera Bakgrundsuppdateringar utan WiFi",
"autoSelectHighestVersionCode": "Välj automatiskt högsta versionskod APK", "autoSelectHighestVersionCode": "Välj automatiskt högsta versionskod APK",
"versionExtractionRegEx": "Version Extraction RegEx", "versionExtractionRegEx": "Version Extraction RegEx",
"trimVersionString": "Trimma versionssträng med RegEx",
"matchGroupToUseForX": "Matchningsgrupp att använda för \"{}\"",
"matchGroupToUse": "Match Group to Use", "matchGroupToUse": "Match Group to Use",
"highlightTouchTargets": "Markera mindre uppenbara beröringsobjekt", "highlightTouchTargets": "Markera mindre uppenbara beröringsobjekt",
"pickExportDir": "Välj Exportsökväg", "pickExportDir": "Välj Exportsökväg",

View File

@@ -3,7 +3,7 @@
"noReleaseFound": "Uygun bir sürüm bulunamadı", "noReleaseFound": "Uygun bir sürüm bulunamadı",
"noVersionFound": "Sürüm bulunamadı", "noVersionFound": "Sürüm bulunamadı",
"urlMatchesNoSource": "URL, bilinen bir kaynağa uymuyor", "urlMatchesNoSource": "URL, bilinen bir kaynağa uymuyor",
"cantInstallOlderVersion": "Eski bir sürümü yükleyemem", "cantInstallOlderVersion": "Eski bir sürüm yüklenemez",
"appIdMismatch": "İndirilen paket kimliği mevcut Uygulama kimliği ile eşleşmiyor", "appIdMismatch": "İndirilen paket kimliği mevcut Uygulama kimliği ile eşleşmiyor",
"functionNotImplemented": "Bu sınıf bu işlevi uygulamamıştır", "functionNotImplemented": "Bu sınıf bu işlevi uygulamamıştır",
"placeholder": "Yer Tutucu", "placeholder": "Yer Tutucu",
@@ -13,22 +13,22 @@
"and": "ve", "and": "ve",
"githubPATLabel": "GitHub Kişisel Erişim Anahtarı (Sınırlamayı Artırır)", "githubPATLabel": "GitHub Kişisel Erişim Anahtarı (Sınırlamayı Artırır)",
"includePrereleases": "Ön sürümleri dahil et", "includePrereleases": "Ön sürümleri dahil et",
"fallbackToOlderReleases": "Daha eski sürümlere geri dön", "fallbackToOlderReleases": "Daha eski sürümleri alternatif olarak tut",
"filterReleaseTitlesByRegEx": "Düzenli İfadelerle Sürüm Başlıklarını Filtrele", "filterReleaseTitlesByRegEx": "Düzenli İfadelerle Sürüm Başlıklarını Filtrele",
"invalidRegEx": "Geçersiz düzenli ifade", "invalidRegEx": "Geçersiz düzenli ifade",
"noDescription": "Açıklama yok", "noDescription": "Açıklama yok",
"cancel": "İptal", "cancel": "İptal",
"continue": "Devam Et", "continue": "Devam Et",
"requiredInBrackets": "(Gerekli)", "requiredInBrackets": "(Gerekli)",
"dropdownNoOptsError": "HATA: DİPLOMADA EN AZ BİR SEÇENEK OLMALI", "dropdownNoOptsError": "HATA: AÇILIR MENÜDE EN AZ BİR SEÇENEK OLMALI",
"colour": "Renk", "colour": "Renk",
"standard": "Standart", "standard": "Standart",
"custom": "Özel", "custom": "Özel",
"useMaterialYou": "Sizin Malzemenizi Kullanın", "useMaterialYou": "MaterialYou Kullanın",
"githubStarredRepos": "GitHub'a Yıldızlı Depolar", "githubStarredRepos": "GitHub Yıldızlı Depolar",
"uname": "Kullanıcı Adı", "uname": "Kullanıcı Adı",
"wrongArgNum": "Hatalı argüman sayısı sağlandı", "wrongArgNum": "Hatalı sayıda argüman sağlandı",
"xIsTrackOnly": "{} yalnızca Takip Edilen", "xIsTrackOnly": "{} yalnızca Takip Ediliyor",
"source": "Kaynak", "source": "Kaynak",
"app": "Uygulama", "app": "Uygulama",
"appsFromSourceAreTrackOnly": "Bu kaynaktan gelen uygulamalar 'Yalnızca Takip Edilen'dir.", "appsFromSourceAreTrackOnly": "Bu kaynaktan gelen uygulamalar 'Yalnızca Takip Edilen'dir.",
@@ -41,9 +41,9 @@
"appSourceURL": "Uygulama Kaynak URL'si", "appSourceURL": "Uygulama Kaynak URL'si",
"error": "Hata", "error": "Hata",
"add": "Ekle", "add": "Ekle",
"searchSomeSourcesLabel": "Ara (Bazı Kaynaklar Yalnızca)", "searchSomeSourcesLabel": "Ara (Yalnızca Bazı Kaynaklar)",
"search": "Ara", "search": "Ara",
"additionalOptsFor": "{} İçin Ek Seçenekler", "additionalOptsFor": "{} için Ek Seçenekler",
"supportedSources": "Desteklenen Kaynaklar", "supportedSources": "Desteklenen Kaynaklar",
"trackOnlyInBrackets": "(Yalnızca Takip)", "trackOnlyInBrackets": "(Yalnızca Takip)",
"searchableInBrackets": "(Aranabilir)", "searchableInBrackets": "(Aranabilir)",
@@ -173,13 +173,13 @@
"lastUpdateCheckX": "Son Güncelleme Kontrolü: {}", "lastUpdateCheckX": "Son Güncelleme Kontrolü: {}",
"remove": "Kaldır", "remove": "Kaldır",
"yesMarkUpdated": "Evet, Güncellendi olarak İşaretle", "yesMarkUpdated": "Evet, Güncellendi olarak İşaretle",
"fdroid": "F-Droid Resmi", "fdroid": "Resmi F-Droid",
"appIdOrName": "Uygulama Kimliği veya Adı", "appIdOrName": "Uygulama Kimliği veya Adı",
"appId": "Uygulama Kimliği", "appId": "Uygulama Kimliği",
"appWithIdOrNameNotFound": "Bu kimlik veya ada sahip bir uygulama bulunamadı", "appWithIdOrNameNotFound": "Bu kimlik veya ada sahip bir uygulama bulunamadı",
"reposHaveMultipleApps": "Depolar birden fazla uygulama içerebilir", "reposHaveMultipleApps": "Depolar birden fazla uygulama içerebilir",
"fdroidThirdPartyRepo": "F-Droid Üçüncü Taraf Depo", "fdroidThirdPartyRepo": "F-Droid Üçüncü Parti Depo",
"steamMobile": "Buhar Mobil", "steamMobile": "Steam Mobil",
"steamChat": "Steam Sohbet", "steamChat": "Steam Sohbet",
"install": "Yükle", "install": "Yükle",
"markInstalled": "Yüklendi olarak İşaretle", "markInstalled": "Yüklendi olarak İşaretle",
@@ -222,7 +222,7 @@
"standardVersionDetection": "Standart sürüm tespiti", "standardVersionDetection": "Standart sürüm tespiti",
"groupByCategory": "Kategoriye Göre Grupla", "groupByCategory": "Kategoriye Göre Grupla",
"autoApkFilterByArch": "Mümkünse APK'leri CPU mimarisi ile filtreleme girişimi", "autoApkFilterByArch": "Mümkünse APK'leri CPU mimarisi ile filtreleme girişimi",
"overrideSource": "Kaynağı Geçersiz Kıl", "overrideSource": "Öncelenecek Kaynak",
"dontShowAgain": "Bunu tekrar gösterme", "dontShowAgain": "Bunu tekrar gösterme",
"dontShowTrackOnlyWarnings": "'Yalnızca Takip Edilen' uyarılarını gösterme", "dontShowTrackOnlyWarnings": "'Yalnızca Takip Edilen' uyarılarını gösterme",
"dontShowAPKOriginWarnings": "APK kaynağı uyarılarını gösterme", "dontShowAPKOriginWarnings": "APK kaynağı uyarılarını gösterme",
@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "WiFi olmadığında arka plan güncellemelerini devre dışı bırak", "bgUpdatesOnWiFiOnly": "WiFi olmadığında arka plan güncellemelerini devre dışı bırak",
"autoSelectHighestVersionCode": "Otomatik olarak en yüksek sürüm kodunu seç", "autoSelectHighestVersionCode": "Otomatik olarak en yüksek sürüm kodunu seç",
"versionExtractionRegEx": "Sürüm Çıkarma Düzenli İfade", "versionExtractionRegEx": "Sürüm Çıkarma Düzenli İfade",
"trimVersionString": "RegEx ile Sürüm Dizesini Kırpma",
"matchGroupToUseForX": "\"{}\" için Kullanılacak Grubu Eşleştirin",
"matchGroupToUse": "Sürüm Çıkarma Regex için Kullanılacak Eşleşme Grubu", "matchGroupToUse": "Sürüm Çıkarma Regex için Kullanılacak Eşleşme Grubu",
"highlightTouchTargets": "Daha az belirgin dokunma hedeflerini vurgula", "highlightTouchTargets": "Daha az belirgin dokunma hedeflerini vurgula",
"pickExportDir": "Dışa Aktarılacak Klasörü Seç", "pickExportDir": "Dışa Aktarılacak Klasörü Seç",
@@ -286,10 +288,10 @@
"checkingForUpdatesNotifChannel": "Güncellemeler Kontrol Ediliyor", "checkingForUpdatesNotifChannel": "Güncellemeler Kontrol Ediliyor",
"onlyCheckInstalledOrTrackOnlyApps": "Yalnızca yüklü ve Yalnızca İzleme Uygulamalarını güncelleme", "onlyCheckInstalledOrTrackOnlyApps": "Yalnızca yüklü ve Yalnızca İzleme Uygulamalarını güncelleme",
"supportFixedAPKURL": "Sabit APK URL'lerini destekleyin", "supportFixedAPKURL": "Sabit APK URL'lerini destekleyin",
"selectX": "Seçme {}", "selectX": "{} Tanesini Seç",
"parallelDownloads": "Paralel indirmelere izin ver", "parallelDownloads": "Paralel indirmelere izin ver",
"useShizuku": "Yüklemek için Shizuku veya Sui'yi kullanın", "useShizuku": "Yüklemek için Shizuku veya Sui'yi kullanın",
"shizukuBinderNotFound": "Shizuku is not running", "shizukuBinderNotFound": "Shizuku servisi çalışmıyor",
"shizukuOld": "Eski Shizuku sürümü (<11) - güncelleyin", "shizukuOld": "Eski Shizuku sürümü (<11) - güncelleyin",
"shizukuOldAndroidWithADB": "Shizuku ADB ile Android < 8.1 üzerinde çalışıyor - Android'i güncelleyin veya bunun yerine Sui kullanın", "shizukuOldAndroidWithADB": "Shizuku ADB ile Android < 8.1 üzerinde çalışıyor - Android'i güncelleyin veya bunun yerine Sui kullanın",
"shizukuPretendToBeGooglePlay": "Google Play'i yükleme kaynağı olarak ayarlayın (Shizuku kullanılıyorsa)", "shizukuPretendToBeGooglePlay": "Google Play'i yükleme kaynağı olarak ayarlayın (Shizuku kullanılıyorsa)",
@@ -334,7 +336,7 @@
}, },
"url": { "url": {
"one": "{} URL", "one": "{} URL",
"other": "{} URL'ler" "other": "{} URL"
}, },
"minute": { "minute": {
"one": "{} Dakika", "one": "{} Dakika",
@@ -370,6 +372,6 @@
}, },
"apk": { "apk": {
"one": "{} APK", "one": "{} APK",
"other": "{} APK'lar" "other": "{} APK"
} }
} }

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Вимкнути фонові оновлення поза Wi-Fi", "bgUpdatesOnWiFiOnly": "Вимкнути фонові оновлення поза Wi-Fi",
"autoSelectHighestVersionCode": "Автоматичний вибір APK з найвищим кодом версії", "autoSelectHighestVersionCode": "Автоматичний вибір APK з найвищим кодом версії",
"versionExtractionRegEx": "Регулярний вираз для вилучення рядка версії", "versionExtractionRegEx": "Регулярний вираз для вилучення рядка версії",
"trimVersionString": "Обрізати рядок версії за допомогою RegEx",
"matchGroupToUseForX": "Група збігів для \"{}\"",
"matchGroupToUse": "Група співпадінь для використання в регулярному виразі вилучення версії", "matchGroupToUse": "Група співпадінь для використання в регулярному виразі вилучення версії",
"highlightTouchTargets": "Підсвічувати менш очевидні області дотику", "highlightTouchTargets": "Підсвічувати менш очевидні області дотику",
"pickExportDir": "Вибрати каталог експорту", "pickExportDir": "Вибрати каталог експорту",

View File

@@ -22,9 +22,9 @@
"requiredInBrackets": "(Yêu cầu)", "requiredInBrackets": "(Yêu cầu)",
"dropdownNoOptsError": "LỖI: TẢI XUỐNG PHẢI CÓ ÍT NHẤT MỘT LỰA CHỌN", "dropdownNoOptsError": "LỖI: TẢI XUỐNG PHẢI CÓ ÍT NHẤT MỘT LỰA CHỌN",
"colour": "Màu sắc", "colour": "Màu sắc",
"standard": "Standard", "standard": "Mặc định",
"custom": "Custom", "custom": "Tùy chỉnh",
"useMaterialYou": "Use Material You", "useMaterialYou": "Sử dụng Material You",
"githubStarredRepos": "Kho lưu trữ có gắn dấu sao GitHub", "githubStarredRepos": "Kho lưu trữ có gắn dấu sao GitHub",
"uname": "Tên người dùng", "uname": "Tên người dùng",
"wrongArgNum": "Số lượng đối số được cung cấp sai", "wrongArgNum": "Số lượng đối số được cung cấp sai",
@@ -147,10 +147,10 @@
"noNewUpdates": "Không có bản cập nhật mới.", "noNewUpdates": "Không có bản cập nhật mới.",
"xHasAnUpdate": "{} có bản cập nhật.", "xHasAnUpdate": "{} có bản cập nhật.",
"appsUpdated": "Ứng dụng đã cập nhật ", "appsUpdated": "Ứng dụng đã cập nhật ",
"appsNotUpdated": "Failed to update applications", "appsNotUpdated": "Ứng dụng đã cập nhật không thành công",
"appsUpdatedNotifDescription": "Thông báo cho người dùng rằng các bản cập nhật cho một hoặc nhiều Ứng dụng đã được áp dụng trong nền", "appsUpdatedNotifDescription": "Thông báo cho người dùng rằng các bản cập nhật cho một hoặc nhiều Ứng dụng đã được áp dụng trong nền",
"xWasUpdatedToY": "{} đã được cập nhật thành {}.", "xWasUpdatedToY": "{} đã được cập nhật thành {}.",
"xWasNotUpdatedToY": "Failed to update {} to {}.", "xWasNotUpdatedToY": "{} đã cập nhật thành {} không thành công.",
"errorCheckingUpdates": "Lỗi kiểm tra bản cập nhật", "errorCheckingUpdates": "Lỗi kiểm tra bản cập nhật",
"errorCheckingUpdatesNotifDescription": "Thông báo hiển thị khi kiểm tra cập nhật nền không thành công", "errorCheckingUpdatesNotifDescription": "Thông báo hiển thị khi kiểm tra cập nhật nền không thành công",
"appsRemoved": "Ứng dụng đã loại bỏ", "appsRemoved": "Ứng dụng đã loại bỏ",
@@ -189,8 +189,8 @@
"disableVersionDetection": "Tắt tính năng phát hiện phiên bản", "disableVersionDetection": "Tắt tính năng phát hiện phiên bản",
"noVersionDetectionExplanation": "Chỉ nên sử dụng tùy chọn này cho Ứng dụng mà tính năng phát hiện phiên bản không hoạt động chính xác.", "noVersionDetectionExplanation": "Chỉ nên sử dụng tùy chọn này cho Ứng dụng mà tính năng phát hiện phiên bản không hoạt động chính xác.",
"downloadingX": "Đang tải xuống {}", "downloadingX": "Đang tải xuống {}",
"downloadX": "Download {}", "downloadX": "Tải xuống {}",
"downloadedX": "Downloaded {}", "downloadedX": "Đã tải xuống {}",
"releaseAsset": "Release Asset", "releaseAsset": "Release Asset",
"downloadNotifDescription": "Thông báo cho người dùng về tiến trình tải xuống Ứng dụng", "downloadNotifDescription": "Thông báo cho người dùng về tiến trình tải xuống Ứng dụng",
"noAPKFound": "Không tìm thấy APK", "noAPKFound": "Không tìm thấy APK",
@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Tắt cập nhật nền khi không có WiFi", "bgUpdatesOnWiFiOnly": "Tắt cập nhật nền khi không có WiFi",
"autoSelectHighestVersionCode": "Tự động chọn APK mã phiên bản cao nhất", "autoSelectHighestVersionCode": "Tự động chọn APK mã phiên bản cao nhất",
"versionExtractionRegEx": "Trích xuất phiên bản RegEx", "versionExtractionRegEx": "Trích xuất phiên bản RegEx",
"trimVersionString": "Trim Version String With RegEx",
"matchGroupToUseForX": "Match Group to Use for \"{}\"",
"matchGroupToUse": "Nhóm đối sánh để sử dụng cho Regex trích xuất phiên bản", "matchGroupToUse": "Nhóm đối sánh để sử dụng cho Regex trích xuất phiên bản",
"highlightTouchTargets": "Đánh dấu các mục tiêu cảm ứng ít rõ ràng hơn", "highlightTouchTargets": "Đánh dấu các mục tiêu cảm ứng ít rõ ràng hơn",
"pickExportDir": "Chọn thư mục xuất", "pickExportDir": "Chọn thư mục xuất",
@@ -288,10 +290,10 @@
"supportFixedAPKURL": "Hỗ trợ URL APK cố định", "supportFixedAPKURL": "Hỗ trợ URL APK cố định",
"selectX": "Lựa chọn {}", "selectX": "Lựa chọn {}",
"parallelDownloads": "Cho phép tải đa luồng", "parallelDownloads": "Cho phép tải đa luồng",
"useShizuku": "Use Shizuku or Sui to install", "useShizuku": "Sử dụng Shizuku hoặc Sui để cài đặt",
"shizukuBinderNotFound": "Shizuku chưa khởi động", "shizukuBinderNotFound": "Shizuku chưa khởi động",
"shizukuOld": "Old Shizuku version (<11) - update it", "shizukuOld": "Phiên bản Shizuku lỗi thời (<11) - hãy cập nhật nó",
"shizukuOldAndroidWithADB": "Shizuku running on Android < 8.1 with ADB - update Android or use Sui instead", "shizukuOldAndroidWithADB": "Shizuku chạy trên Android < 8.1 với ADB - hãy cập nhật Android hoặc thay bằng Sui",
"shizukuPretendToBeGooglePlay": "Set Google Play as the installation source (if Shizuku is used)", "shizukuPretendToBeGooglePlay": "Set Google Play as the installation source (if Shizuku is used)",
"useSystemFont": "Sử dụng phông chữ hệ thống", "useSystemFont": "Sử dụng phông chữ hệ thống",
"useVersionCodeAsOSVersion": "Sử dụng Mã phiên bản ứng dụng làm phiên bản do hệ điều hành phát hiện", "useVersionCodeAsOSVersion": "Sử dụng Mã phiên bản ứng dụng làm phiên bản do hệ điều hành phát hiện",
@@ -310,7 +312,7 @@
"badDownload": "Không thể phân tích cú pháp APK (tải xuống một phần hoặc không tương thích)", "badDownload": "Không thể phân tích cú pháp APK (tải xuống một phần hoặc không tương thích)",
"beforeNewInstallsShareToAppVerifier": "Chia sẻ ứng dụng mới với AppVerifier (nếu có)", "beforeNewInstallsShareToAppVerifier": "Chia sẻ ứng dụng mới với AppVerifier (nếu có)",
"appVerifierInstructionToast": "Chia sẻ lên AppVerifier, sau đó quay lại đây khi sẵn sàng.", "appVerifierInstructionToast": "Chia sẻ lên AppVerifier, sau đó quay lại đây khi sẵn sàng.",
"wiki": "Help/Wiki", "wiki": "Trợ giúp/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)", "crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Gỡ ứng dụng?", "one": "Gỡ ứng dụng?",
@@ -361,8 +363,8 @@
"other": "{} và {} ứng dụng khác đã được cập nhật." "other": "{} và {} ứng dụng khác đã được cập nhật."
}, },
"xAndNMoreUpdatesFailed": { "xAndNMoreUpdatesFailed": {
"one": "Failed to update {} and 1 more app.", "one": "{} và 1 ứng dụng khác đã cập nhật không thành công.",
"other": "Failed to update {} and {} more apps." "other": "{} và {} ứng dụng khác đã cập nhật không thảnh công."
}, },
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} và 1 ứng dụng khác có thể đã được cập nhật.", "one": "{} và 1 ứng dụng khác có thể đã được cập nhật.",

View File

@@ -0,0 +1,377 @@
{
"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 Starred Repos",
"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\n僅影響 URL 和第三方匯入方法。",
"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 第三方倉庫",
"steamMobile": "Steam 行動版",
"steamChat": "Steam 聊天",
"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": "使用發佈日期作為版本字串",
"releaseDateAsVersionExplanation": "此選項僅應用於版本檢測無法正確工作但有發佈日期的應用程式。",
"changes": "變更",
"releaseDate": "發佈日期",
"importFromURLsInFile": "從文件中的 URL 匯入(如 OPML",
"versionDetectionExplanation": "將版本字串與作業系統檢測到的版本對比",
"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": "使用 API 金鑰可以避免 GitHub 的速率限制。",
"sortByLastLinkSegment": "僅按連結的最後一段排序",
"filterReleaseNotesByRegEx": "用正則表達式過濾發佈說明",
"customLinkFilterRegex": "自定 APK 連結過濾正則表達式(預設為 '.apk$'",
"appsPossiblyUpdated": "嘗試更新應用程式",
"appsPossiblyUpdatedNotifDescription": "通知使用者一個或多個應用程式的更新可能已在背景中應用",
"xWasPossiblyUpdatedToY": "{} 可能已更新到 {}。",
"enableBackgroundUpdates": "啟用背景更新",
"backgroundUpdateReqsExplanation": "並非所有應用程式都能進行背景更新。",
"backgroundUpdateLimitsExplanation": "背景安裝的成功與否只能在打開 Obtainium 時確定。",
"verifyLatestTag": "驗證「最新」標籤",
"intermediateLinkRegex": "過濾要訪問的「中間」連結",
"filterByLinkText": "按連結文本過濾連結",
"intermediateLinkNotFound": "未找到中間連結",
"intermediateLink": "中間連結",
"exemptFromBackgroundUpdates": "免除背景更新(若已啟用)",
"bgUpdatesOnWiFiOnly": "禁用非 WiFi 的背景更新",
"autoSelectHighestVersionCode": "自動選擇最高 versionCode 的 APK",
"versionExtractionRegEx": "版本字串提取正則表達式",
"trimVersionString": "Trim Version String With RegEx",
"matchGroupToUseForX": "Match Group to Use for \"{}\"",
"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 網址",
"selectX": "選擇 {}",
"parallelDownloads": "允許平行下載",
"useShizuku": "使用 Shizuku 或 Sui 來安裝",
"shizukuBinderNotFound": "Shizuku 服務未運行",
"shizukuOld": "舊版 Shizuku (<11) - 請更新",
"shizukuOldAndroidWithADB": "Shizuku 在 Android 8.1 以下版本使用 ADB 運行 - 請更新 Android 或改用 Sui",
"shizukuPretendToBeGooglePlay": "設置 Google Play 為安裝來源(如果使用 Shizuku",
"useSystemFont": "使用系統字體",
"useVersionCodeAsOSVersion": "使用應用程式 versionCode 作為操作系統檢測的版本",
"requestHeader": "請求標頭",
"useLatestAssetDateAsReleaseDate": "使用最新資源上傳日期作為發佈日期",
"defaultPseudoVersioningMethod": "預設偽版本管理方法",
"partialAPKHash": "部分 APK Hash",
"APKLinkHash": "APK 連結 Hash",
"directAPKLink": "直接 APK 連結",
"pseudoVersionInUse": "正在使用偽版本",
"installed": "已安裝",
"latest": "最新",
"invertRegEx": "反轉正則表達式",
"note": "備註",
"selfHostedNote": "可使用「{}」下拉選單來訪問任何來源的自託管/自定義實例。",
"badDownload": "無法解析 APK不兼容或下載不完整",
"beforeNewInstallsShareToAppVerifier": "將新應用程式分享到 AppVerifier如果可用",
"appVerifierInstructionToast": "分享至 AppVerifier然後準備好時返回此處。",
"wiki": "幫助/維基",
"crowdsourcedConfigsLabel": "群眾外包的應用程式配置(使用風險自負)",
"removeAppQuestion": {
"one": "移除應用程式?",
"other": "移除應用程式?"
},
"tooManyRequestsTryAgainInMinutes": {
"one": "請求過多(速率限制)- {} 分鐘後重試",
"other": "請求過多(速率限制)- {} 分鐘後重試"
},
"bgUpdateGotErrorRetryInMinutes": {
"one": "背景更新檢查遇到 {},將在 {} 分鐘後重新檢查",
"other": "背景更新檢查遇到 {},將在 {} 分鐘後重新檢查"
},
"bgCheckFoundUpdatesWillNotifyIfNeeded": {
"one": "背景更新檢查發現 {} 個更新 - 如果需要將通知使用者",
"other": "背景更新檢查發現 {} 個更新 - 如果需要將通知使用者"
},
"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"
}
}

View File

@@ -24,7 +24,7 @@
"colour": "配色", "colour": "配色",
"standard": "标准", "standard": "标准",
"custom": "定制", "custom": "定制",
"useMaterialYou": "使用 Material You 配色", "useMaterialYou": "使用 Material You",
"githubStarredRepos": "已星标的 GitHub 仓库", "githubStarredRepos": "已星标的 GitHub 仓库",
"uname": "用户名", "uname": "用户名",
"wrongArgNum": "参数数量错误", "wrongArgNum": "参数数量错误",
@@ -45,8 +45,8 @@
"search": "搜索", "search": "搜索",
"additionalOptsFor": "{} 的更多选项", "additionalOptsFor": "{} 的更多选项",
"supportedSources": "支持的来源", "supportedSources": "支持的来源",
"trackOnlyInBrackets": "(仅追踪)", "trackOnlyInBrackets": "仅追踪",
"searchableInBrackets": "(可搜索)", "searchableInBrackets": "可搜索",
"appsString": "应用列表", "appsString": "应用列表",
"noApps": "无应用", "noApps": "无应用",
"noAppsForFilter": "没有符合条件的应用", "noAppsForFilter": "没有符合条件的应用",
@@ -125,7 +125,7 @@
"bgUpdateCheckInterval": "后台更新检查间隔", "bgUpdateCheckInterval": "后台更新检查间隔",
"neverManualOnly": "手动", "neverManualOnly": "手动",
"appearance": "外观", "appearance": "外观",
"showWebInAppView": "应用详情页显示来源网", "showWebInAppView": "应用详情页显示来源网站内容",
"pinUpdates": "将待更新应用置顶", "pinUpdates": "将待更新应用置顶",
"updates": "更新", "updates": "更新",
"sourceSpecific": "来源", "sourceSpecific": "来源",
@@ -147,7 +147,7 @@
"noNewUpdates": "全部应用已是最新。", "noNewUpdates": "全部应用已是最新。",
"xHasAnUpdate": "“{}”可以更新了。", "xHasAnUpdate": "“{}”可以更新了。",
"appsUpdated": "应用已更新", "appsUpdated": "应用已更新",
"appsNotUpdated": "更新应用程序失败", "appsNotUpdated": "更新应用失败",
"appsUpdatedNotifDescription": "当应用在后台安装更新时发送通知", "appsUpdatedNotifDescription": "当应用在后台安装更新时发送通知",
"xWasUpdatedToY": "“{}”已更新至 {}。", "xWasUpdatedToY": "“{}”已更新至 {}。",
"xWasNotUpdatedToY": "未能将 {} 更新为 {}。", "xWasNotUpdatedToY": "未能将 {} 更新为 {}。",
@@ -191,7 +191,7 @@
"downloadingX": "正在下载“{}”", "downloadingX": "正在下载“{}”",
"downloadX": "下载 {}", "downloadX": "下载 {}",
"downloadedX": "下载 {}", "downloadedX": "下载 {}",
"releaseAsset": "APK 文件", "releaseAsset": "发行版附件",
"downloadNotifDescription": "提示应用的下载进度", "downloadNotifDescription": "提示应用的下载进度",
"noAPKFound": "未找到 APK 文件", "noAPKFound": "未找到 APK 文件",
"noVersionDetection": "禁用版本检测", "noVersionDetection": "禁用版本检测",
@@ -201,7 +201,7 @@
"noCategory": "无类别", "noCategory": "无类别",
"noCategories": "无类别", "noCategories": "无类别",
"deleteCategoriesQuestion": "是否删除选中的类别?", "deleteCategoriesQuestion": "是否删除选中的类别?",
"categoryDeleteWarning": "被删除类别的应用将恢复为未分类状态。", "categoryDeleteWarning": "被删除类别的应用将恢复为未分类状态。",
"addCategory": "添加类别", "addCategory": "添加类别",
"label": "标签", "label": "标签",
"language": "语言", "language": "语言",
@@ -247,7 +247,7 @@
"appsPossiblyUpdated": "已尝试更新应用", "appsPossiblyUpdated": "已尝试更新应用",
"appsPossiblyUpdatedNotifDescription": "当应用已尝试在后台更新时发送通知", "appsPossiblyUpdatedNotifDescription": "当应用已尝试在后台更新时发送通知",
"xWasPossiblyUpdatedToY": "已尝试将“{}”更新至 {}。", "xWasPossiblyUpdatedToY": "已尝试将“{}”更新至 {}。",
"enableBackgroundUpdates": "启用后台更新", "enableBackgroundUpdates": "启用全局后台更新",
"backgroundUpdateReqsExplanation": "后台更新未必适用于所有的应用。", "backgroundUpdateReqsExplanation": "后台更新未必适用于所有的应用。",
"backgroundUpdateLimitsExplanation": "只有在启动 Obtainium 时才能确认安装是否成功。", "backgroundUpdateLimitsExplanation": "只有在启动 Obtainium 时才能确认安装是否成功。",
"verifyLatestTag": "验证“Latest”标签", "verifyLatestTag": "验证“Latest”标签",
@@ -255,12 +255,14 @@
"filterByLinkText": "根据链接文本进行筛选", "filterByLinkText": "根据链接文本进行筛选",
"intermediateLinkNotFound": "未找到中转链接", "intermediateLinkNotFound": "未找到中转链接",
"intermediateLink": "中转链接", "intermediateLink": "中转链接",
"exemptFromBackgroundUpdates": "禁用后台更新(如果已经全局启用", "exemptFromBackgroundUpdates": "禁用后台更新(仅此应用生效,即使已启用全局后台更新",
"bgUpdatesOnWiFiOnly": "未连接 Wi-Fi 时禁用后台更新", "bgUpdatesOnWiFiOnly": "未连接 Wi-Fi 时禁用后台更新",
"autoSelectHighestVersionCode": "自动选择内部版本号最高的 APK 文件", "autoSelectHighestVersionCode": "自动选择内部版本号最高的 APK 文件",
"versionExtractionRegEx": "提取版本号的正则表达式", "versionExtractionRegEx": "提取版本号的正则表达式",
"trimVersionString": "使用 RegEx 修剪版本字符串",
"matchGroupToUseForX": "用于\"{}\"的匹配组",
"matchGroupToUse": "从上述匹配结果中引用的捕获组", "matchGroupToUse": "从上述匹配结果中引用的捕获组",
"highlightTouchTargets": "突出展示不明显的触摸区域", "highlightTouchTargets": "突出展示不明显的可交互区域",
"pickExportDir": "选择导出文件夹", "pickExportDir": "选择导出文件夹",
"autoExportOnChanges": "数据变更时自动导出", "autoExportOnChanges": "数据变更时自动导出",
"includeSettings": "同时导出应用设置", "includeSettings": "同时导出应用设置",
@@ -291,12 +293,12 @@
"useShizuku": "使用 Shizuku 或 Sui 安装", "useShizuku": "使用 Shizuku 或 Sui 安装",
"shizukuBinderNotFound": "未发现兼容的 Shizuku 服务", "shizukuBinderNotFound": "未发现兼容的 Shizuku 服务",
"shizukuOld": "Shizuku 版本过低(<11- 请更新", "shizukuOld": "Shizuku 版本过低(<11- 请更新",
"shizukuOldAndroidWithADB": "正在低版本 Android<8.1)系统中以 ADB 模式运行 Shizuku - 请更新 Android 版本或使用 Sui 代替", "shizukuOldAndroidWithADB": "正在低版本 Android<8.1)系统中以 ADB 模式运行 Shizuku - 请更新 Android 系统版本或使用 Sui 代替",
"shizukuPretendToBeGooglePlay": "使用 Shizuku 时,将安装来源伪装为Google Play", "shizukuPretendToBeGooglePlay": "将安装来源伪装为 Google Play(需要使用 Shizuku",
"useSystemFont": "使用系统字体", "useSystemFont": "使用系统字体",
"useVersionCodeAsOSVersion": "使用内部版本号代替应用定义的版本号", "useVersionCodeAsOSVersion": "使用内部版本号代替应用定义的版本号",
"requestHeader": "请求标头", "requestHeader": "请求标头",
"useLatestAssetDateAsReleaseDate": "使用最文件上传时间作为发行日期", "useLatestAssetDateAsReleaseDate": "使用最文件上传时间作为发行日期",
"defaultPseudoVersioningMethod": "默认虚拟版本方案", "defaultPseudoVersioningMethod": "默认虚拟版本方案",
"partialAPKHash": "APK 文件散列值片段", "partialAPKHash": "APK 文件散列值片段",
"APKLinkHash": "APK 文件链接散列值", "APKLinkHash": "APK 文件链接散列值",
@@ -310,19 +312,19 @@
"badDownload": "无法解析 APK 文件(不兼容或文件不完整)", "badDownload": "无法解析 APK 文件(不兼容或文件不完整)",
"beforeNewInstallsShareToAppVerifier": "通过 AppVerifier 校验新应用(如果可用)", "beforeNewInstallsShareToAppVerifier": "通过 AppVerifier 校验新应用(如果可用)",
"appVerifierInstructionToast": "分享至 AppVerifier完成后返回此处。", "appVerifierInstructionToast": "分享至 AppVerifier完成后返回此处。",
"wiki": "帮助/维基", "wiki": "帮助/Wiki",
"crowdsourcedConfigsLabel": "众包应用程序配置(使用风险自负)", "crowdsourcedConfigsLabel": "众包应用程序配置(使用风险自负)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "是否删除应用?", "one": "是否删除应用?",
"other": "是否删除应用?" "other": "是否删除应用?"
}, },
"tooManyRequestsTryAgainInMinutes": { "tooManyRequestsTryAgainInMinutes": {
"one": "API 请求过于频繁(速率限制)- 在 {} 分钟后重试", "one": "API 请求过于频繁(速率限制)- 在 {} 分钟后重试",
"other": "API 请求过于频繁(速率限制)- 在 {} 分钟后重试" "other": "API 请求过于频繁(速率限制)- 在 {} 分钟后重试"
}, },
"bgUpdateGotErrorRetryInMinutes": { "bgUpdateGotErrorRetryInMinutes": {
"one": "后台更新检查遇到了“{}”问题,预定于 {} 分钟后重试", "one": "后台更新检查遇到了“{}”问题,于 {} 分钟后重试",
"other": "后台更新检查遇到了“{}”问题,预定于 {} 分钟后重试" "other": "后台更新检查遇到了“{}”问题,于 {} 分钟后重试"
}, },
"bgCheckFoundUpdatesWillNotifyIfNeeded": { "bgCheckFoundUpdatesWillNotifyIfNeeded": {
"one": "后台检查发现 {} 个应用更新 - 如有需要将发送通知", "one": "后台检查发现 {} 个应用更新 - 如有需要将发送通知",
@@ -361,8 +363,8 @@
"other": "“{}”和另外 {} 个应用已更新。" "other": "“{}”和另外 {} 个应用已更新。"
}, },
"xAndNMoreUpdatesFailed": { "xAndNMoreUpdatesFailed": {
"one": "更新 {} 和另外 1 个应用程序失败。", "one": "{} 和另外 1 个应用更新失败。",
"other": "未能更新 {} 和 {} 更多应用程序。" "other": "{} 和另外 {} 个应用更新失败。"
}, },
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} 和另外 1 个应用已尝试更新。", "one": "{} 和另外 1 个应用已尝试更新。",

View File

@@ -9,7 +9,7 @@
<ul> <ul>
<li>GitHub</li> <li>GitHub</li>
<li>GitLab</li> <li>GitLab</li>
<li>Codeberg</li> <li>Forgejo (Codeberg)</li>
<li>F-Droid</li> <li>F-Droid</li>
<li>Third Party F-Droid Repos</li> <li>Third Party F-Droid Repos</li>
<li>IzzyOnDroid</li> <li>IzzyOnDroid</li>

View File

@@ -9,7 +9,7 @@
<ul> <ul>
<li>GitHub</li> <li>GitHub</li>
<li>GitLab</li> <li>GitLab</li>
<li>Codeberg</li> <li>Forgejo (Codeberg)</li>
<li>F-Droid</li> <li>F-Droid</li>
<li>Third Party F-Droid Repos</li> <li>Third Party F-Droid Repos</li>
<li>IzzyOnDroid</li> <li>IzzyOnDroid</li>

View File

@@ -1,5 +1,7 @@
import 'package:device_info_plus/device_info_plus.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:html/parser.dart'; import 'package:html/parser.dart';
import 'package:obtainium/app_sources/html.dart';
import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/providers/source_provider.dart'; import 'package:obtainium/providers/source_provider.dart';
@@ -29,14 +31,15 @@ class APKPure extends AppSource {
@override @override
String sourceSpecificStandardizeURL(String url) { String sourceSpecificStandardizeURL(String url) {
RegExp standardUrlRegExB = RegExp( RegExp standardUrlRegExB = RegExp(
'^https?://m.${getSourceRegex(hosts)}/+[^/]+/+[^/]+(/+[^/]+)?', '^https?://m.${getSourceRegex(hosts)}(/+[^/]{2})?/+[^/]+/+[^/]+',
caseSensitive: false); caseSensitive: false);
RegExpMatch? match = standardUrlRegExB.firstMatch(url); RegExpMatch? match = standardUrlRegExB.firstMatch(url);
if (match != null) { if (match != null) {
url = 'https://${getSourceRegex(hosts)}${Uri.parse(url).path}'; var uri = Uri.parse(url);
url = 'https://${uri.host.substring(2)}${uri.path}';
} }
RegExp standardUrlRegExA = RegExp( RegExp standardUrlRegExA = RegExp(
'^https?://(www\\.)?${getSourceRegex(hosts)}/+[^/]+/+[^/]+(/+[^/]+)?', '^https?://(www\\.)?${getSourceRegex(hosts)}(/+[^/]{2})?/+[^/]+/+[^/]+',
caseSensitive: false); caseSensitive: false);
match = standardUrlRegExA.firstMatch(url); match = standardUrlRegExA.firstMatch(url);
if (match == null) { if (match == null) {
@@ -58,40 +61,102 @@ class APKPure extends AppSource {
) async { ) async {
String appId = (await tryInferringAppId(standardUrl))!; String appId = (await tryInferringAppId(standardUrl))!;
String host = Uri.parse(standardUrl).host; String host = Uri.parse(standardUrl).host;
var res = await sourceRequest('$standardUrl/download', additionalSettings);
var resChangelog = await sourceRequest(standardUrl, additionalSettings); var res0 = await sourceRequest('$standardUrl/versions', additionalSettings);
if (res.statusCode == 200 && resChangelog.statusCode == 200) { var versionLinks = await grabLinksCommon(res0, {
var html = parse(res.body); 'skipSort': true,
var htmlChangelog = parse(resChangelog.body); 'customLinkFilterRegex': '$standardUrl/download/[^/]+\$'
String? version = html.querySelector('span.info-sdk span')?.text.trim(); });
if (version == null) {
throw NoVersionError(); // if (versionLinks.length > 7) {
} // // Returns up to 30 which is too much - would take too long and possibly get blocked/rate-limited
String? dateString = // versionLinks = versionLinks.sublist(0, 7);
html.querySelector('span.info-other span.date')?.text.trim(); // }
DateTime? releaseDate = parseDateTimeMMMddCommayyyy(dateString);
String type = html.querySelector('a.info-tag')?.text.trim() ?? 'APK'; var supportedArchs = (await DeviceInfoPlugin().androidInfo).supportedAbis;
List<MapEntry<String, String>> apkUrls = [
MapEntry('$appId.apk', if (additionalSettings['autoApkFilterByArch'] != true) {
'https://d.${hosts.contains(host) ? 'cdnpure.com' : host}/b/$type/$appId?version=latest') // No need to request multiple versions when we're not going to filter them (always pick the top one)
]; versionLinks = versionLinks.sublist(0, 1);
String author = html
.querySelector('span.info-sdk')
?.text
.trim()
.substring(version.length + 4) ??
Uri.parse(standardUrl).pathSegments.reversed.last;
String appName =
html.querySelector('h1.info-title')?.text.trim() ?? appId;
String? changeLog = htmlChangelog
.querySelector("div.whats-new-info p:not(.date)")
?.innerHtml
.trim()
.replaceAll("<br>", " \n");
return APKDetails(version, apkUrls, AppNames(author, appName),
releaseDate: releaseDate, changeLog: changeLog);
} else {
throw getObtainiumHttpError(res);
} }
if (versionLinks.isEmpty) {
throw NoReleasesError();
}
for (var i = 0; i < versionLinks.length; i++) {
var link = versionLinks[i];
var res = await sourceRequest(link.key, additionalSettings);
if (res.statusCode == 200) {
var html = parse(res.body);
var apksDiv =
html.querySelector('#version-list div div.show-more-content');
DateTime? topReleaseDate;
var apkUrls = apksDiv
?.querySelectorAll('div.group-title')
.map((e) {
String architecture = e.text.trim();
if (architecture.toLowerCase() == 'unlimited' ||
architecture.toLowerCase() == 'universal') {
architecture = '';
}
// Only take the first APK for each architecture, ignore others for now, for simplicity
// Unclear why there can even be multiple APKs for the same version and arch
var apkInfo = e.nextElementSibling?.querySelector('div.info');
String? versionCode = RegExp('[0-9]+')
.firstMatch(apkInfo
?.querySelector('div.info-top span.code')
?.text ??
'')
?.group(0)
?.trim();
String? type = apkInfo
?.querySelector('div.info-top span.tag')
?.text
.trim() ??
'APK';
String? dateString = apkInfo
?.querySelector('div.info-bottom span.time')
?.text
.trim();
DateTime? releaseDate =
parseDateTimeMMMddCommayyyy(dateString);
if (additionalSettings['autoApkFilterByArch'] == true &&
architecture.isNotEmpty &&
!supportedArchs.contains(architecture)) {
return const MapEntry('', '');
}
topReleaseDate ??=
releaseDate; // Just use the release date of the first APK in the list as the release date for this version
return MapEntry(
'$appId-$versionCode-$architecture.${type.toLowerCase()}',
'https://d.${hosts.contains(host) ? 'cdnpure.com' : host}/b/$type/$appId?versionCode=$versionCode');
})
.where((e) => e.key.isNotEmpty)
.toList() ??
[];
if (apkUrls.isEmpty) {
continue;
}
String version = Uri.parse(link.key).pathSegments.last;
String author = html
.querySelector('span.info-sdk')
?.text
.trim()
.substring(version.length + 4) ??
Uri.parse(standardUrl).pathSegments.reversed.last;
String appName =
html.querySelector('h1.info-title')?.text.trim() ?? appId;
String? changeLog = html
.querySelector('div.module.change-log')
?.innerHtml
.trim()
.replaceAll("<br>", " \n");
return APKDetails(version, apkUrls, AppNames(author, appName),
releaseDate: topReleaseDate, changeLog: changeLog);
} else {
throw getObtainiumHttpError(res);
}
}
throw NoAPKError();
} }
} }

View File

@@ -5,6 +5,7 @@ import 'package:obtainium/providers/source_provider.dart';
class Codeberg extends AppSource { class Codeberg extends AppSource {
GitHub gh = GitHub(); GitHub gh = GitHub();
Codeberg() { Codeberg() {
name = 'Forgejo (Codeberg)';
hosts = ['codeberg.org']; hosts = ['codeberg.org'];
additionalSourceAppSpecificSettingFormItems = additionalSourceAppSpecificSettingFormItems =

View File

@@ -24,6 +24,14 @@ class DirectAPKLink extends AppSource {
]; ];
} }
@override
Future<Map<String, String>?> getRequestHeaders(
Map<String, dynamic> additionalSettings,
{bool forAPKDownload = false}) {
return html.getRequestHeaders(additionalSettings,
forAPKDownload: forAPKDownload);
}
@override @override
Future<APKDetails> getLatestAPKDetails( Future<APKDetails> getLatestAPKDetails(
String standardUrl, String standardUrl,

View File

@@ -9,7 +9,7 @@ class FDroidRepo extends AppSource {
FDroidRepo() { FDroidRepo() {
name = tr('fdroidThirdPartyRepo'); name = tr('fdroidThirdPartyRepo');
canSearch = true; canSearch = true;
excludeFromMassSearch = true; includeAdditionalOptsInMainSearch = true;
neverAutoSelect = true; neverAutoSelect = true;
showReleaseDateAsVersionToggle = true; showReleaseDateAsVersionToggle = true;
@@ -86,6 +86,27 @@ class FDroidRepo extends AppSource {
} }
} }
@override
void runOnAddAppInputChange(String userInput) {
additionalSourceAppSpecificSettingFormItems =
additionalSourceAppSpecificSettingFormItems.map((row) {
row = row.map((item) {
if (item.key == 'appIdOrName') {
try {
var appId = Uri.parse(userInput).queryParameters['appId'];
if (appId != null && item is GeneratedFormTextField) {
item.required = false;
}
} catch (e) {
//
}
}
return item;
}).toList();
return row;
}).toList();
}
@override @override
App endOfGetAppChanges(App app) { App endOfGetAppChanges(App app) {
var uri = Uri.parse(app.url); var uri = Uri.parse(app.url);
@@ -142,6 +163,7 @@ class FDroidRepo extends AppSource {
if (appIdOrName == null) { if (appIdOrName == null) {
throw NoReleasesError(); throw NoReleasesError();
} }
additionalSettings['appIdOrName'] = appIdOrName;
var res = var res =
await sourceRequestWithURLVariants(standardUrl, additionalSettings); await sourceRequestWithURLVariants(standardUrl, additionalSettings);
if (res.statusCode == 200) { if (res.statusCode == 200) {

View File

@@ -171,7 +171,7 @@ class GitHub extends AppSource {
{bool forAPKDownload = false}) async { {bool forAPKDownload = false}) async {
var token = await getTokenIfAny(additionalSettings); var token = await getTokenIfAny(additionalSettings);
var headers = <String, String>{}; var headers = <String, String>{};
if (token != null) { if (token != null && token.isNotEmpty) {
headers[HttpHeaders.authorizationHeader] = 'Token $token'; headers[HttpHeaders.authorizationHeader] = 'Token $token';
} }
if (forAPKDownload == true) { if (forAPKDownload == true) {
@@ -285,7 +285,9 @@ class GitHub extends AppSource {
DateTime? getPublishDateFromRelease(dynamic rel) => DateTime? getPublishDateFromRelease(dynamic rel) =>
rel?['published_at'] != null rel?['published_at'] != null
? DateTime.parse(rel['published_at']) ? DateTime.parse(rel['published_at'])
: null; : rel?['commit']?['created'] != null
? DateTime.parse(rel['commit']['created'])
: null;
DateTime? getNewestAssetDateFromRelease(dynamic rel) { DateTime? getNewestAssetDateFromRelease(dynamic rel) {
var t = (rel['assets'] as List<dynamic>?) var t = (rel['assets'] as List<dynamic>?)
?.map((e) { ?.map((e) {

View File

@@ -111,6 +111,14 @@ class GitLab extends AppSource {
} }
} }
@override
Future<String> apkUrlPrefetchModifier(String apkUrl, String standardUrl,
Map<String, dynamic> additionalSettings) async {
String? PAT = await getPATIfAny(hostChanged ? additionalSettings : {});
String optionalAuth = (PAT != null) ? 'private_token=$PAT' : '';
return '$apkUrl?$optionalAuth';
}
@override @override
Future<APKDetails> getLatestAPKDetails( Future<APKDetails> getLatestAPKDetails(
String standardUrl, String standardUrl,
@@ -123,6 +131,18 @@ class GitLab extends AppSource {
bool trackOnly = additionalSettings['trackOnly'] == true; bool trackOnly = additionalSettings['trackOnly'] == true;
// Get project ID
Response res0 = await sourceRequest(
'https://${hosts[0]}/api/v4/projects/${names.author}%2F${names.name}?$optionalAuth',
additionalSettings);
if (res0.statusCode != 200) {
throw getObtainiumHttpError(res0);
}
int? projectId = jsonDecode(res0.body)['id'];
if (projectId == null) {
throw NoReleasesError();
}
// Request data from REST API // Request data from REST API
Response res = await sourceRequest( 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/${names.author}%2F${names.name}/${trackOnly ? 'repository/tags' : 'releases'}?$optionalAuth',
@@ -149,11 +169,12 @@ class GitLab extends AppSource {
.join('.apk\n') .join('.apk\n')
.split('\n') .split('\n')
.where((s) => s.startsWith('/uploads/') && s.endsWith('apk')) .where((s) => s.startsWith('/uploads/') && s.endsWith('apk'))
.map((s) => '$standardUrl$s') .map((s) => 'https://${hosts[0]}/-/project/$projectId$s')
.toList(); .toList();
var apkUrlsSet = apkUrlsFromAssets.toSet(); var apkUrlsSet = apkUrlsFromAssets.toSet();
apkUrlsSet.addAll(uploadedAPKsFromDescription); apkUrlsSet.addAll(uploadedAPKsFromDescription);
var releaseDateString = e['released_at'] ?? e['created_at']; var releaseDateString =
e['released_at'] ?? e['created_at'] ?? e['commit']?['created_at'];
DateTime? releaseDate = DateTime? releaseDate =
releaseDateString != null ? DateTime.parse(releaseDateString) : null; releaseDateString != null ? DateTime.parse(releaseDateString) : null;
return APKDetails( return APKDetails(

View File

@@ -92,7 +92,89 @@ bool _isNumeric(String s) {
return s.codeUnitAt(0) >= 48 && s.codeUnitAt(0) <= 57; return s.codeUnitAt(0) >= 48 && s.codeUnitAt(0) <= 57;
} }
// Given an HTTP response, grab some links according to the common additional settings
// (those that apply to intermediate and final steps)
Future<List<MapEntry<String, String>>> grabLinksCommon(
Response res, Map<String, dynamic> additionalSettings) async {
if (res.statusCode != 200) {
throw getObtainiumHttpError(res);
}
var html = parse(res.body);
List<MapEntry<String, String>> allLinks = html
.querySelectorAll('a')
.map((element) => MapEntry(
element.attributes['href'] ?? '',
element.text.isNotEmpty
? element.text
: (element.attributes['href'] ?? '').split('/').last))
.where((element) => element.key.isNotEmpty)
.map((e) => MapEntry(ensureAbsoluteUrl(e.key, res.request!.url), e.value))
.toList();
if (allLinks.isEmpty) {
allLinks = RegExp(
r'(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?')
.allMatches(res.body)
.map((match) =>
MapEntry(match.group(0)!, match.group(0)?.split('/').last ?? ''))
.toList();
}
List<MapEntry<String, String>> links = [];
bool skipSort = additionalSettings['skipSort'] == true;
bool filterLinkByText = additionalSettings['filterByLinkText'] == true;
if ((additionalSettings['customLinkFilterRegex'] as String?)?.isNotEmpty ==
true) {
var reg = RegExp(additionalSettings['customLinkFilterRegex']);
links = allLinks.where((element) {
var link = element.key;
try {
link = Uri.decodeFull(element.key);
} catch (e) {
// Some links may not have valid encoding
}
return reg.hasMatch(filterLinkByText ? element.value : link);
}).toList();
} else {
links = allLinks.where((element) {
var link = element.key;
try {
link = Uri.decodeFull(element.key);
} catch (e) {
// Some links may not have valid encoding
}
return Uri.parse(filterLinkByText ? element.value : link)
.path
.toLowerCase()
.endsWith('.apk');
}).toList();
}
if (!skipSort) {
links.sort((a, b) => additionalSettings['sortByLastLinkSegment'] == true
? compareAlphaNumeric(a.key.split('/').where((e) => e.isNotEmpty).last,
b.key.split('/').where((e) => e.isNotEmpty).last)
: compareAlphaNumeric(a.key, b.key));
}
if (additionalSettings['reverseSort'] == true) {
links = links.reversed.toList();
}
return links;
}
class HTML extends AppSource { class HTML extends AppSource {
@override
List<List<GeneratedFormItem>> get combinedAppSpecificSettingFormItems {
return super.combinedAppSpecificSettingFormItems.map((r) {
return r.map((e) {
if (e.key == 'versionExtractionRegEx') {
e.label = tr('versionExtractionRegEx');
}
if (e.key == 'matchGroupToUse') {
e.label = tr('matchGroupToUse');
}
return e;
}).toList();
}).toList();
}
var finalStepFormitems = [ var finalStepFormitems = [
[ [
GeneratedFormTextField('customLinkFilterRegex', GeneratedFormTextField('customLinkFilterRegex',
@@ -210,75 +292,6 @@ class HTML extends AppSource {
return url; return url;
} }
// Given an HTTP response, grab some links according to the common additional settings
// (those that apply to intermediate and final steps)
Future<List<MapEntry<String, String>>> grabLinksCommon(
Response res, Map<String, dynamic> additionalSettings) async {
if (res.statusCode != 200) {
throw getObtainiumHttpError(res);
}
var html = parse(res.body);
List<MapEntry<String, String>> allLinks = html
.querySelectorAll('a')
.map((element) => MapEntry(
element.attributes['href'] ?? '',
element.text.isNotEmpty
? element.text
: (element.attributes['href'] ?? '').split('/').last))
.where((element) => element.key.isNotEmpty)
.map((e) =>
MapEntry(ensureAbsoluteUrl(e.key, res.request!.url), e.value))
.toList();
if (allLinks.isEmpty) {
allLinks = RegExp(
r'(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?')
.allMatches(res.body)
.map((match) =>
MapEntry(match.group(0)!, match.group(0)?.split('/').last ?? ''))
.toList();
}
List<MapEntry<String, String>> links = [];
bool skipSort = additionalSettings['skipSort'] == true;
bool filterLinkByText = additionalSettings['filterByLinkText'] == true;
if ((additionalSettings['customLinkFilterRegex'] as String?)?.isNotEmpty ==
true) {
var reg = RegExp(additionalSettings['customLinkFilterRegex']);
links = allLinks.where((element) {
var link = element.key;
try {
link = Uri.decodeFull(element.key);
} catch (e) {
// Some links may not have valid encoding
}
return reg.hasMatch(filterLinkByText ? element.value : link);
}).toList();
} else {
links = allLinks.where((element) {
var link = element.key;
try {
link = Uri.decodeFull(element.key);
} catch (e) {
// Some links may not have valid encoding
}
return Uri.parse(filterLinkByText ? element.value : link)
.path
.toLowerCase()
.endsWith('.apk');
}).toList();
}
if (!skipSort) {
links.sort((a, b) => additionalSettings['sortByLastLinkSegment'] == true
? compareAlphaNumeric(
a.key.split('/').where((e) => e.isNotEmpty).last,
b.key.split('/').where((e) => e.isNotEmpty).last)
: compareAlphaNumeric(a.key, b.key));
}
if (additionalSettings['reverseSort'] == true) {
links = links.reversed.toList();
}
return links;
}
@override @override
Future<APKDetails> getLatestAPKDetails( Future<APKDetails> getLatestAPKDetails(
String standardUrl, String standardUrl,
@@ -332,10 +345,13 @@ class HTML extends AppSource {
additionalSettings['versionExtractWholePage'] == true additionalSettings['versionExtractWholePage'] == true
? versionExtractionWholePageString ? versionExtractionWholePageString
: relDecoded); : relDecoded);
version ??= version ??= additionalSettings['defaultPseudoVersioningMethod'] ==
additionalSettings['defaultPseudoVersioningMethod'] == 'APKLinkHash' 'APKLinkHash'
? rel.hashCode.toString() ? rel.hashCode.toString()
: (await checkPartialDownloadHashDynamic(rel)).toString(); : (await checkPartialDownloadHashDynamic(rel,
headers: await getRequestHeaders(additionalSettings,
forAPKDownload: true)))
.toString();
return APKDetails(version, [rel].map((e) => MapEntry(e, e)).toList(), return APKDetails(version, [rel].map((e) => MapEntry(e, e)).toList(),
AppNames(uri.host, tr('app'))); AppNames(uri.host, tr('app')));
} }

View File

@@ -73,21 +73,23 @@ class HuaweiAppGallery extends AppSource {
throw NoReleasesError(); throw NoReleasesError();
} }
String appId = appIdFromRedirectDlUrl(res.headers['location']!); String appId = appIdFromRedirectDlUrl(res.headers['location']!);
if (appId.isEmpty) {
throw NoReleasesError();
}
var relDateStr = var relDateStr =
res.headers['location']?.split('?')[0].split('.').reversed.toList()[1]; res.headers['location']?.split('?')[0].split('.').reversed.toList()[1];
var relDateStrAdj = relDateStr?.split(''); if (relDateStr == null || relDateStr.length != 10) {
var tempLen = relDateStrAdj?.length ?? 0;
var i = 2;
while (i < tempLen) {
relDateStrAdj?.insert((i + i ~/ 2 - 1), '-');
i += 2;
}
var relDate = relDateStrAdj == null
? null
: DateFormat('yy-MM-dd-HH-mm', 'en_US').parse(relDateStrAdj.join(''));
if (relDateStr == null) {
throw NoVersionError(); throw NoVersionError();
} }
var relDateStrAdj = relDateStr.split('');
var tempLen = relDateStrAdj.length;
var i = 2;
while (i < tempLen) {
relDateStrAdj.insert((i + i ~/ 2 - 1), '-');
i += 2;
}
var relDate =
DateFormat('yy-MM-dd-HH-mm', 'en_US').parse(relDateStrAdj.join(''));
return APKDetails( return APKDetails(
relDateStr, [MapEntry('$appId.apk', dlUrl)], AppNames(name, appId), relDateStr, [MapEntry('$appId.apk', dlUrl)], AppNames(name, appId),
releaseDate: relDate); releaseDate: relDate);

View File

@@ -5,6 +5,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:obtainium/components/generated_form_modal.dart'; import 'package:obtainium/components/generated_form_modal.dart';
import 'package:obtainium/providers/source_provider.dart'; import 'package:obtainium/providers/source_provider.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart';
abstract class GeneratedFormItem { abstract class GeneratedFormItem {
late String key; late String key;
@@ -28,6 +29,7 @@ class GeneratedFormTextField extends GeneratedFormItem {
late String? hint; late String? hint;
late bool password; late bool password;
late TextInputType? textInputType; late TextInputType? textInputType;
late List<String>? autoCompleteOptions;
GeneratedFormTextField(super.key, GeneratedFormTextField(super.key,
{super.label, {super.label,
@@ -39,7 +41,8 @@ class GeneratedFormTextField extends GeneratedFormItem {
this.max = 1, this.max = 1,
this.hint, this.hint,
this.password = false, this.password = false,
this.textInputType}); this.textInputType,
this.autoCompleteOptions});
@override @override
String ensureType(val) { String ensureType(val) {
@@ -274,38 +277,62 @@ class _GeneratedFormState extends State<GeneratedForm> {
var formItem = e.value; var formItem = e.value;
if (formItem is GeneratedFormTextField) { if (formItem is GeneratedFormTextField) {
final formFieldKey = GlobalKey<FormFieldState>(); final formFieldKey = GlobalKey<FormFieldState>();
return TextFormField( var ctrl = TextEditingController(text: values[formItem.key]);
keyboardType: formItem.textInputType, return TypeAheadField<String>(
obscureText: formItem.password, controller: ctrl,
autocorrect: !formItem.password, builder: (context, controller, focusNode) {
enableSuggestions: !formItem.password, return TextFormField(
key: formFieldKey, controller: ctrl,
initialValue: values[formItem.key], focusNode: focusNode,
autovalidateMode: AutovalidateMode.onUserInteraction, keyboardType: formItem.textInputType,
onChanged: (value) { obscureText: formItem.password,
autocorrect: !formItem.password,
enableSuggestions: !formItem.password,
key: formFieldKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
onChanged: (value) {
setState(() {
values[formItem.key] = value;
someValueChanged();
});
},
decoration: InputDecoration(
helperText:
formItem.label + (formItem.required ? ' *' : ''),
hintText: formItem.hint),
minLines: formItem.max <= 1 ? null : formItem.max,
maxLines: formItem.max <= 1 ? 1 : formItem.max,
validator: (value) {
if (formItem.required &&
(value == null || value.trim().isEmpty)) {
return '${formItem.label} ${tr('requiredInBrackets')}';
}
for (var validator in formItem.additionalValidators) {
String? result = validator(value);
if (result != null) {
return result;
}
}
return null;
},
);
},
itemBuilder: (context, value) {
return ListTile(title: Text(value));
},
onSelected: (value) {
ctrl.text = value;
setState(() { setState(() {
values[formItem.key] = value; values[formItem.key] = value;
someValueChanged(); someValueChanged();
}); });
}, },
decoration: InputDecoration( suggestionsCallback: (search) {
helperText: formItem.label + (formItem.required ? ' *' : ''), return formItem.autoCompleteOptions
hintText: formItem.hint), ?.where((t) => t.toLowerCase().contains(search.toLowerCase()))
minLines: formItem.max <= 1 ? null : formItem.max, .toList();
maxLines: formItem.max <= 1 ? 1 : formItem.max,
validator: (value) {
if (formItem.required &&
(value == null || value.trim().isEmpty)) {
return '${formItem.label} ${tr('requiredInBrackets')}';
}
for (var validator in formItem.additionalValidators) {
String? result = validator(value);
if (result != null) {
return result;
}
}
return null;
}, },
hideOnEmpty: true,
); );
} else if (formItem is GeneratedFormDropdown) { } else if (formItem is GeneratedFormDropdown) {
if (formItem.opts!.isEmpty) { if (formItem.opts!.isEmpty) {

View File

@@ -40,6 +40,7 @@ List<MapEntry<Locale, String>> supportedLocales = const [
MapEntry(Locale('vi'), 'Tiếng Việt'), MapEntry(Locale('vi'), 'Tiếng Việt'),
MapEntry(Locale('tr'), 'Türkçe'), MapEntry(Locale('tr'), 'Türkçe'),
MapEntry(Locale('uk'), 'Українська'), MapEntry(Locale('uk'), 'Українська'),
MapEntry(Locale('da'), 'Dansk'),
]; ];
const fallbackLocale = Locale('en'); const fallbackLocale = Locale('en');
const localeDir = 'assets/translations'; const localeDir = 'assets/translations';
@@ -212,20 +213,23 @@ class _ObtainiumState extends State<Obtainium> {
// Decide on a colour/brightness scheme based on OS and user settings // Decide on a colour/brightness scheme based on OS and user settings
ColorScheme lightColorScheme; ColorScheme lightColorScheme;
ColorScheme darkColorScheme; ColorScheme darkColorScheme;
if (lightDynamic != null && darkDynamic != null && settingsProvider.useMaterialYou) { if (lightDynamic != null &&
darkDynamic != null &&
settingsProvider.useMaterialYou) {
lightColorScheme = lightDynamic.harmonized(); lightColorScheme = lightDynamic.harmonized();
darkColorScheme = darkDynamic.harmonized(); darkColorScheme = darkDynamic.harmonized();
} else { } else {
lightColorScheme = ColorScheme.fromSeed(seedColor: settingsProvider.themeColor); lightColorScheme =
ColorScheme.fromSeed(seedColor: settingsProvider.themeColor);
darkColorScheme = ColorScheme.fromSeed( darkColorScheme = ColorScheme.fromSeed(
seedColor: settingsProvider.themeColor, brightness: Brightness.dark); seedColor: settingsProvider.themeColor,
brightness: Brightness.dark);
} }
// set the background and surface colors to pure black in the amoled theme // set the background and surface colors to pure black in the amoled theme
if (settingsProvider.useBlackTheme) { if (settingsProvider.useBlackTheme) {
darkColorScheme = darkColorScheme darkColorScheme =
.copyWith(background: Colors.black, surface: Colors.black) darkColorScheme.copyWith(surface: Colors.black).harmonized();
.harmonized();
} }
if (settingsProvider.useSystemFont) NativeFeatures.loadSystemFont(); if (settingsProvider.useSystemFont) NativeFeatures.loadSystemFont();
@@ -242,14 +246,14 @@ class _ObtainiumState extends State<Obtainium> {
? darkColorScheme ? darkColorScheme
: lightColorScheme, : lightColorScheme,
fontFamily: fontFamily:
settingsProvider.useSystemFont ? 'SystemFont' : 'Metropolis'), settingsProvider.useSystemFont ? 'SystemFont' : 'Wix-Madefor-Display'),
darkTheme: ThemeData( darkTheme: ThemeData(
useMaterial3: true, useMaterial3: true,
colorScheme: settingsProvider.theme == ThemeSettings.light colorScheme: settingsProvider.theme == ThemeSettings.light
? lightColorScheme ? lightColorScheme
: darkColorScheme, : darkColorScheme,
fontFamily: fontFamily:
settingsProvider.useSystemFont ? 'SystemFont' : 'Metropolis'), settingsProvider.useSystemFont ? 'SystemFont' : 'Wix-Madefor-Display'),
home: Shortcuts(shortcuts: <LogicalKeySet, Intent>{ home: Shortcuts(shortcuts: <LogicalKeySet, Intent>{
LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(), LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(),
}, child: const HomePage())); }, child: const HomePage()));

View File

@@ -51,10 +51,13 @@ class AddAppPageState extends State<AddAppPage> {
} }
changeUserInput(String input, bool valid, bool isBuilding, changeUserInput(String input, bool valid, bool isBuilding,
{bool updateUrlInput = false}) { {bool updateUrlInput = false, String? overrideSource}) {
userInput = input; userInput = input;
if (!isBuilding) { if (!isBuilding) {
setState(() { setState(() {
if (overrideSource != null) {
pickedSourceOverride = overrideSource;
}
if (updateUrlInput) { if (updateUrlInput) {
urlInputKey++; urlInputKey++;
} }
@@ -68,6 +71,7 @@ class AddAppPageState extends State<AddAppPage> {
if (pickedSource.runtimeType != source.runtimeType || if (pickedSource.runtimeType != source.runtimeType ||
(prevHost != null && prevHost != source?.hosts[0])) { (prevHost != null && prevHost != source?.hosts[0])) {
pickedSource = source; pickedSource = source;
pickedSource?.runOnAddAppInputChange(userInput);
additionalSettings = source != null additionalSettings = source != null
? getDefaultValuesFromFormItems( ? getDefaultValuesFromFormItems(
source.combinedAppSpecificSettingFormItems) source.combinedAppSpecificSettingFormItems)
@@ -259,9 +263,7 @@ class AddAppPageState extends State<AddAppPage> {
searching = true; searching = true;
}); });
var sourceStrings = <String, List<String>>{}; var sourceStrings = <String, List<String>>{};
sourceProvider.sources sourceProvider.sources.where((e) => e.canSearch).forEach((s) {
.where((e) => e.canSearch && !e.excludeFromMassSearch)
.forEach((s) {
sourceStrings[s.name] = [s.name]; sourceStrings[s.name] = [s.name];
}); });
try { try {
@@ -282,32 +284,78 @@ class AddAppPageState extends State<AddAppPage> {
settingsProvider.searchDeselected = sourceStrings.keys settingsProvider.searchDeselected = sourceStrings.keys
.where((s) => !searchSources.contains(s)) .where((s) => !searchSources.contains(s))
.toList(); .toList();
var results = await Future.wait(sourceProvider.sources List<MapEntry<String, Map<String, List<String>>>?> results =
.where((e) => searchSources.contains(e.name)) (await Future.wait(sourceProvider.sources
.map((e) async { .where((e) => searchSources.contains(e.name))
.map((e) async {
try { try {
return await e.search(searchQuery); Map<String, dynamic>? querySettings = {};
if (e.includeAdditionalOptsInMainSearch) {
querySettings = await showDialog<Map<String, dynamic>?>(
context: context,
builder: (BuildContext ctx) {
return GeneratedFormModal(
title: tr('searchX', args: [e.name]),
items: [
...e.searchQuerySettingFormItems.map((e) => [e]),
[
GeneratedFormTextField('url',
label: e.hosts.isNotEmpty
? tr('overrideSource')
: plural('url', 1).substring(2),
autoCompleteOptions: [
...(e.hosts.isNotEmpty ? [e.hosts[0]] : []),
...appsProvider.apps.values
.where((a) =>
sourceProvider
.getSource(a.app.url,
overrideSource:
a.app.overrideSource)
.runtimeType ==
e.runtimeType)
.map((a) {
var uri = Uri.parse(a.app.url);
return '${uri.origin}${uri.path}';
})
],
defaultValue:
e.hosts.isNotEmpty ? e.hosts[0] : '',
required: true)
],
],
);
});
if (querySettings == null) {
return null;
}
}
return MapEntry(e.runtimeType.toString(),
await e.search(searchQuery, querySettings: querySettings));
} catch (err) { } catch (err) {
if (err is! CredsNeededError) { if (err is! CredsNeededError) {
rethrow; rethrow;
} else { } else {
err.unexpected = true; err.unexpected = true;
showError(err, context); showError(err, context);
return <String, List<String>>{}; return null;
} }
} }
})); })))
.where((a) => a != null)
.toList();
// Interleave results instead of simple reduce // Interleave results instead of simple reduce
Map<String, List<String>> res = {}; Map<String, MapEntry<String, List<String>>> res = {};
var si = 0; var si = 0;
var done = false; var done = false;
while (!done) { while (!done) {
done = true; done = true;
for (var r in results) { for (var r in results) {
if (r.length > si) { var sourceName = r!.key;
if (r.value.length > si) {
done = false; done = false;
res.addEntries([r.entries.elementAt(si)]); var singleRes = r.value.entries.elementAt(si);
res[singleRes.key] = MapEntry(sourceName, singleRes.value);
} }
} }
si++; si++;
@@ -322,13 +370,15 @@ class AddAppPageState extends State<AddAppPage> {
context: context, context: context,
builder: (BuildContext ctx) { builder: (BuildContext ctx) {
return SelectionModal( return SelectionModal(
entries: res, entries: res.map((k, v) => MapEntry(k, v.value)),
selectedByDefault: false, selectedByDefault: false,
onlyOneSelectionAllowed: true, onlyOneSelectionAllowed: true,
); );
}); });
if (selectedUrls != null && selectedUrls.isNotEmpty) { if (selectedUrls != null && selectedUrls.isNotEmpty) {
changeUserInput(selectedUrls[0], true, false, updateUrlInput: true); var sourceName = res[selectedUrls[0]]?.key;
changeUserInput(selectedUrls[0], true, false,
updateUrlInput: true, overrideSource: sourceName);
} }
} }
} catch (e) { } catch (e) {
@@ -349,7 +399,7 @@ class AddAppPageState extends State<AddAppPage> {
[ [
GeneratedFormDropdown( GeneratedFormDropdown(
'overrideSource', 'overrideSource',
defaultValue: '', defaultValue: pickedSourceOverride ?? '',
[ [
MapEntry('', tr('none')), MapEntry('', tr('none')),
...sourceProvider.sources.map( ...sourceProvider.sources.map(

View File

@@ -161,25 +161,46 @@ class _AppPageState extends State<AppPage> {
if (app?.app.apkUrls.isNotEmpty == true || if (app?.app.apkUrls.isNotEmpty == true ||
app?.app.otherAssetUrls.isNotEmpty == true) app?.app.otherAssetUrls.isNotEmpty == true)
GestureDetector( GestureDetector(
onTap: app?.app == null || updating onTap: app?.app == null || updating
? null ? null
: () async { : () async {
try { try {
await appsProvider await appsProvider
.downloadAppAssets([app!.app.id], context); .downloadAppAssets([app!.app.id], context);
} catch (e) { } catch (e) {
showError(e, context); showError(e, context);
} }
}, },
child: Text( child: Row(
tr('downloadX', args: [tr('releaseAsset').toLowerCase()]), mainAxisAlignment: MainAxisAlignment.center,
textAlign: TextAlign.center, children: [
style: Theme.of(context).textTheme.labelSmall!.copyWith( Container(
decoration: TextDecoration.underline, decoration: BoxDecoration(
fontStyle: FontStyle.italic, borderRadius: BorderRadius.circular(12),
), color: settingsProvider.highlightTouchTargets
), ? (Theme.of(context).brightness ==
), Brightness.light
? Theme.of(context).primaryColor
: Theme.of(context).primaryColorLight)
.withAlpha(20)
: null),
padding: settingsProvider.highlightTouchTargets
? const EdgeInsetsDirectional.fromSTEB(12, 6, 12, 6)
: const EdgeInsetsDirectional.fromSTEB(0, 6, 0, 6),
margin:
const EdgeInsetsDirectional.fromSTEB(0, 6, 0, 0),
child: Text(
tr('downloadX',
args: [tr('releaseAsset').toLowerCase()]),
textAlign: TextAlign.center,
style:
Theme.of(context).textTheme.labelSmall!.copyWith(
decoration: TextDecoration.underline,
fontStyle: FontStyle.italic,
),
))
],
)),
const SizedBox( const SizedBox(
height: 48, height: 48,
), ),
@@ -226,18 +247,26 @@ class _AppPageState extends State<AppPage> {
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
const SizedBox(height: 20), const SizedBox(height: 20),
app?.icon != null FutureBuilder(
? Row(mainAxisAlignment: MainAxisAlignment.center, children: [ future: appsProvider.updateAppIcon(app?.app.id),
GestureDetector( builder: (ctx, val) {
child: Image.memory( return app?.icon != null
app!.icon!, ? Row(
height: 150, mainAxisAlignment: MainAxisAlignment.center,
gaplessPlayback: true, children: [
), GestureDetector(
onTap: () => pm.openApp(app.app.id), onTap: app == null
) ? null
]) : () => pm.openApp(app.app.id),
: Container(), child: Image.memory(
app!.icon!,
height: 150,
gaplessPlayback: true,
),
)
])
: Container();
}),
const SizedBox( const SizedBox(
height: 25, height: 25,
), ),
@@ -286,7 +315,7 @@ class _AppPageState extends State<AppPage> {
? WebViewWidget( ? WebViewWidget(
controller: WebViewController() controller: WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted) ..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(Theme.of(context).colorScheme.background) ..setBackgroundColor(Theme.of(context).colorScheme.surface)
..setJavaScriptMode(JavaScriptMode.unrestricted) ..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate( ..setNavigationDelegate(
NavigationDelegate( NavigationDelegate(

View File

@@ -143,11 +143,14 @@ class AppsPageState extends State<AppsPage> {
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey = final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
GlobalKey<RefreshIndicatorState>(); GlobalKey<RefreshIndicatorState>();
late final ScrollController scrollController = ScrollController();
var sourceProvider = SourceProvider();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var appsProvider = context.watch<AppsProvider>(); var appsProvider = context.watch<AppsProvider>();
var settingsProvider = context.watch<SettingsProvider>(); var settingsProvider = context.watch<SettingsProvider>();
var sourceProvider = SourceProvider();
var listedApps = appsProvider.getAppValues().toList(); var listedApps = appsProvider.getAppValues().toList();
refresh() { refresh() {
@@ -354,7 +357,11 @@ class AppsPageState extends State<AppsPage> {
SliverFillRemaining( SliverFillRemaining(
child: Center( child: Center(
child: Text( child: Text(
appsProvider.apps.isEmpty ? tr('noApps') : tr('noAppsForFilter'), appsProvider.apps.isEmpty
? appsProvider.loadingApps
? tr('pleaseWait')
: tr('noApps')
: tr('noAppsForFilter'),
style: Theme.of(context).textTheme.headlineMedium, style: Theme.of(context).textTheme.headlineMedium,
textAlign: TextAlign.center, textAlign: TextAlign.center,
))), ))),
@@ -402,29 +409,36 @@ class AppsPageState extends State<AppsPage> {
} }
getAppIcon(int appIndex) { getAppIcon(int appIndex) {
return listedApps[appIndex].icon != null return FutureBuilder(
? Image.memory( future: appsProvider.updateAppIcon(listedApps[appIndex].app.id),
listedApps[appIndex].icon!, builder: (ctx, val) {
gaplessPlayback: true, return listedApps[appIndex].icon != null
) ? Image.memory(
: Row( listedApps[appIndex].icon!,
mainAxisSize: MainAxisSize.min, gaplessPlayback: true,
mainAxisAlignment: MainAxisAlignment.center, )
children: [ : Row(
Transform( mainAxisSize: MainAxisSize.min,
alignment: Alignment.center, mainAxisAlignment: MainAxisAlignment.center,
transform: Matrix4.rotationZ(0.31), children: [
child: Padding( Transform(
padding: const EdgeInsets.all(15), alignment: Alignment.center,
child: Image( transform: Matrix4.rotationZ(0.31),
image: const AssetImage( child: Padding(
'assets/graphics/icon_small.png'), padding: const EdgeInsets.all(15),
color: Colors.white.withOpacity(0.3), child: Image(
colorBlendMode: BlendMode.modulate, image: const AssetImage(
gaplessPlayback: true, 'assets/graphics/icon_small.png'),
), color: Theme.of(context).brightness ==
)), Brightness.dark
]); ? Colors.white.withOpacity(0.4)
: Colors.white.withOpacity(0.3),
colorBlendMode: BlendMode.modulate,
gaplessPlayback: true,
),
)),
]);
});
} }
getVersionText(int appIndex) { getVersionText(int appIndex) {
@@ -452,7 +466,7 @@ class AppsPageState extends State<AppsPage> {
hasUpdate ? getUpdateButton(index) : const SizedBox.shrink(), hasUpdate ? getUpdateButton(index) : const SizedBox.shrink(),
hasUpdate hasUpdate
? const SizedBox( ? const SizedBox(
width: 10, width: 5,
) )
: const SizedBox.shrink(), : const SizedBox.shrink(),
GestureDetector( GestureDetector(
@@ -503,7 +517,7 @@ class AppsPageState extends State<AppsPage> {
); );
var transparent = var transparent =
Theme.of(context).colorScheme.background.withAlpha(0).value; Theme.of(context).colorScheme.surface.withAlpha(0).value;
List<double> stops = [ List<double> stops = [
...listedApps[index].app.categories.asMap().entries.map( ...listedApps[index].app.categories.asMap().entries.map(
(e) => ((e.key / (listedApps[index].app.categories.length - 1)))), (e) => ((e.key / (listedApps[index].app.categories.length - 1)))),
@@ -893,7 +907,8 @@ class AppsPageState extends State<AppsPage> {
'preferredApkIndex': 'preferredApkIndex':
a.preferredApkIndex, a.preferredApkIndex,
'additionalSettings': 'additionalSettings':
jsonEncode(a.additionalSettings) jsonEncode(a.additionalSettings),
'overrideSource': a.overrideSource
}))}\n\n'; }))}\n\n';
} }
Share.share(urls, Share.share(urls,
@@ -902,6 +917,27 @@ class AppsPageState extends State<AppsPage> {
}, },
child: Text(tr('shareAppConfigLinks'))), child: Text(tr('shareAppConfigLinks'))),
const Divider(), const Divider(),
TextButton(
onPressed: selectedAppIds.isEmpty
? null
: () {
var exportJSON = jsonEncode(
appsProvider.generateExportJSON(
appIds: selectedApps
.map((e) => e.id)
.toList(),
overrideExportSettings: false));
XFile f = XFile.fromData(
Uint8List.fromList(
utf8.encode(exportJSON)),
mimeType: 'application/json',
name:
'${tr('obtainiumExportHyphenatedLowercase')}-${selectedApps.length}-${DateTime.now().millisecondsSinceEpoch}');
Share.shareXFiles([f]);
},
child: Text(
'${tr('share')} - ${tr('obtainiumExport')}')),
const Divider(),
TextButton( TextButton(
onPressed: () { onPressed: () {
appsProvider appsProvider
@@ -1041,7 +1077,9 @@ class AppsPageState extends State<AppsPage> {
IconButton( IconButton(
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,
style: const ButtonStyle(visualDensity: VisualDensity.compact), style: const ButtonStyle(visualDensity: VisualDensity.compact),
tooltip: '${tr('filter')}${isFilterOff ? '' : ' *'}', tooltip: isFilterOff
? tr('filterApps')
: '${tr('filter')} - ${tr('remove')}',
onPressed: isFilterOff onPressed: isFilterOff
? showFilterDialog ? showFilterDialog
: () { : () {
@@ -1050,8 +1088,8 @@ class AppsPageState extends State<AppsPage> {
}); });
}, },
icon: Icon(isFilterOff icon: Icon(isFilterOff
? Icons.filter_list_rounded ? Icons.search_rounded
: Icons.filter_list_off_rounded)), : Icons.search_off_rounded)),
const SizedBox( const SizedBox(
width: 10, width: 10,
), ),
@@ -1086,11 +1124,17 @@ class AppsPageState extends State<AppsPage> {
body: RefreshIndicator( body: RefreshIndicator(
key: _refreshIndicatorKey, key: _refreshIndicatorKey,
onRefresh: refresh, onRefresh: refresh,
child: CustomScrollView(slivers: <Widget>[ child: Scrollbar(
CustomAppBar(title: tr('appsString')), interactive: true,
...getLoadingWidgets(), controller: scrollController,
getDisplayedList() child: CustomScrollView(
])), physics: const AlwaysScrollableScrollPhysics(),
controller: scrollController,
slivers: <Widget>[
CustomAppBar(title: tr('appsString')),
...getLoadingWidgets(),
getDisplayedList()
]))),
persistentFooterButtons: appsProvider.apps.isEmpty persistentFooterButtons: appsProvider.apps.isEmpty
? null ? null
: [ : [

View File

@@ -13,6 +13,7 @@ import 'package:obtainium/pages/import_export.dart';
import 'package:obtainium/pages/settings.dart'; import 'package:obtainium/pages/settings.dart';
import 'package:obtainium/providers/apps_provider.dart'; import 'package:obtainium/providers/apps_provider.dart';
import 'package:obtainium/providers/settings_provider.dart'; import 'package:obtainium/providers/settings_provider.dart';
import 'package:obtainium/providers/source_provider.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class HomePage extends StatefulWidget { class HomePage extends StatefulWidget {
@@ -102,13 +103,22 @@ class _HomePageState extends State<HomePage> {
}) != }) !=
null) { null) {
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
var result = await context.read<AppsProvider>().import( var appsProvider = context.read<AppsProvider>();
action == 'app' var result = await appsProvider.import(action == 'app'
? '{ "apps": [$dataStr] }' ? '{ "apps": [$dataStr] }'
: '{ "apps": $dataStr }'); : '{ "apps": $dataStr }');
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
showMessage( showMessage(
tr('importedX', args: [plural('apps', result.key)]), context); tr('importedX', args: [plural('apps', result.key.length)]),
context);
await appsProvider
.checkUpdates(specificIds: result.key.map((e) => e.id).toList())
.catchError((e) {
if (e is Map && e['errors'] is MultiAppMultiError) {
showError(e['errors'].toString(), context);
}
return <App>[];
});
} }
} else { } else {
throw ObtainiumError(tr('unknown')); throw ObtainiumError(tr('unknown'));

View File

@@ -33,7 +33,7 @@ class _ImportExportPageState extends State<ImportExportPage> {
var settingsProvider = context.watch<SettingsProvider>(); var settingsProvider = context.watch<SettingsProvider>();
var outlineButtonStyle = ButtonStyle( var outlineButtonStyle = ButtonStyle(
shape: MaterialStateProperty.all( shape: WidgetStateProperty.all(
StadiumBorder( StadiumBorder(
side: BorderSide( side: BorderSide(
width: 1, width: 1,
@@ -144,7 +144,7 @@ class _ImportExportPageState extends State<ImportExportPage> {
appsProvider.addMissingCategories(settingsProvider); appsProvider.addMissingCategories(settingsProvider);
showMessage( showMessage(
'${tr('importedX', args: [ '${tr('importedX', args: [
plural('apps', value.key) plural('apps', value.key.length)
])}${value.value ? ' + ${tr('settings')}' : ''}', ])}${value.value ? ' + ${tr('settings')}' : ''}',
context); context);
}); });

View File

@@ -5,6 +5,7 @@ import 'package:flex_color_picker/flex_color_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:obtainium/components/custom_app_bar.dart'; import 'package:obtainium/components/custom_app_bar.dart';
import 'package:obtainium/components/generated_form.dart'; import 'package:obtainium/components/generated_form.dart';
import 'package:obtainium/components/generated_form_modal.dart';
import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/main.dart'; import 'package:obtainium/main.dart';
import 'package:obtainium/providers/apps_provider.dart'; import 'package:obtainium/providers/apps_provider.dart';
@@ -945,6 +946,25 @@ class _LogsDialogState extends State<LogsDialog> {
], ],
), ),
actions: [ actions: [
TextButton(
onPressed: () async {
var cont = (await showDialog<Map<String, dynamic>?>(
context: context,
builder: (BuildContext ctx) {
return GeneratedFormModal(
title: tr('appLogs'),
items: const [],
initValid: true,
message: tr('removeFromObtainium'),
);
})) !=
null;
if (cont) {
logsProvider.clear();
Navigator.of(context).pop();
}
},
child: Text(tr('remove'))),
TextButton( TextButton(
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();

View File

@@ -220,7 +220,9 @@ Future<File> downloadFile(String url, String fileName, bool fileNameHasExt,
if (ext.endsWith('"') || ext.endsWith("other")) { if (ext.endsWith('"') || ext.endsWith("other")) {
ext = ext.substring(0, ext.length - 1); ext = ext.substring(0, ext.length - 1);
} }
if (url.toLowerCase().endsWith('.apk') && ext != 'apk') { if (((Uri.tryParse(url)?.path ?? url).toLowerCase().endsWith('.apk') ||
ext == 'attachment') &&
ext != 'apk') {
ext = 'apk'; ext = 'apk';
} }
fileName = fileName.split('/').last; // Ensure the fileName is a file name fileName = fileName.split('/').last; // Ensure the fileName is a file name
@@ -329,6 +331,10 @@ Future<Map<String, String>> getHeaders(String url,
return returnHeaders; return returnHeaders;
} }
Future<List<PackageInfo>> getAllInstalledInfo() async {
return await pm.getInstalledPackages() ?? [];
}
Future<PackageInfo?> getInstalledInfo(String? packageName, Future<PackageInfo?> getInstalledInfo(String? packageName,
{bool printErr = true}) async { {bool printErr = true}) async {
if (packageName != null) { if (packageName != null) {
@@ -361,10 +367,12 @@ class AppsProvider with ChangeNotifier {
AppsProvider({isBg = false}) { AppsProvider({isBg = false}) {
// Subscribe to changes in the app foreground status // Subscribe to changes in the app foreground status
foregroundStream = FGBGEvents.stream.asBroadcastStream(); foregroundStream = FGBGEvents.instance.stream.asBroadcastStream();
foregroundSubscription = foregroundStream?.listen((event) async { foregroundSubscription = foregroundStream?.listen((event) async {
isForeground = event == FGBGType.foreground; isForeground = event == FGBGType.foreground;
if (isForeground) loadApps(); if (isForeground) {
await loadApps();
}
}); });
() async { () async {
await settingsProvider.initializeSettings(); await settingsProvider.initializeSettings();
@@ -421,7 +429,8 @@ class AppsProvider with ChangeNotifier {
} }
Future<Object> downloadApp(App app, BuildContext? context, Future<Object> downloadApp(App app, BuildContext? context,
{NotificationsProvider? notificationsProvider}) async { {NotificationsProvider? notificationsProvider,
bool useExisting = true}) async {
var notifId = DownloadNotification(app.finalName, 0).id; var notifId = DownloadNotification(app.finalName, 0).id;
if (apps[app.id] != null) { if (apps[app.id] != null) {
apps[app.id]!.downloadProgress = 0; apps[app.id]!.downloadProgress = 0;
@@ -453,7 +462,7 @@ class AppsProvider with ChangeNotifier {
notificationsProvider?.notify(notif); notificationsProvider?.notify(notif);
} }
prevProg = prog; prevProg = prog;
}, APKDir.path); }, APKDir.path, useExisting: useExisting);
// Set to 90 for remaining steps, will make null in 'finally' // Set to 90 for remaining steps, will make null in 'finally'
if (apps[app.id] != null) { if (apps[app.id] != null) {
apps[app.id]!.downloadProgress = -1; apps[app.id]!.downloadProgress = -1;
@@ -563,7 +572,7 @@ class AppsProvider with ChangeNotifier {
if (!isForeground) { if (!isForeground) {
await notificationsProvider.notify(completeInstallationNotification, await notificationsProvider.notify(completeInstallationNotification,
cancelExisting: true); cancelExisting: true);
while (await FGBGEvents.stream.first != FGBGType.foreground) {} while (await FGBGEvents.instance.stream.first != FGBGType.foreground) {}
await notificationsProvider.cancel(completeInstallationNotification.id); await notificationsProvider.cancel(completeInstallationNotification.id);
} }
} }
@@ -710,7 +719,8 @@ class AppsProvider with ChangeNotifier {
} }
Future<MapEntry<String, String>?> confirmAppFileUrl( Future<MapEntry<String, String>?> confirmAppFileUrl(
App app, BuildContext? context, bool pickAnyAsset) async { App app, BuildContext? context, bool pickAnyAsset,
{bool evenIfSingleChoice = false}) async {
var urlsToSelectFrom = app.apkUrls; var urlsToSelectFrom = app.apkUrls;
if (pickAnyAsset) { if (pickAnyAsset) {
urlsToSelectFrom = [...urlsToSelectFrom, ...app.otherAssetUrls]; urlsToSelectFrom = [...urlsToSelectFrom, ...app.otherAssetUrls];
@@ -721,7 +731,8 @@ class AppsProvider with ChangeNotifier {
// get device supported architecture // get device supported architecture
List<String> archs = (await DeviceInfoPlugin().androidInfo).supportedAbis; List<String> archs = (await DeviceInfoPlugin().androidInfo).supportedAbis;
if (urlsToSelectFrom.length > 1 && context != null) { if ((urlsToSelectFrom.length > 1 || evenIfSingleChoice) &&
context != null) {
appFileUrl = await showDialog( appFileUrl = await showDialog(
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
context: context, context: context,
@@ -766,7 +777,8 @@ class AppsProvider with ChangeNotifier {
Future<List<String>> downloadAndInstallLatestApps( Future<List<String>> downloadAndInstallLatestApps(
List<String> appIds, BuildContext? context, List<String> appIds, BuildContext? context,
{NotificationsProvider? notificationsProvider, {NotificationsProvider? notificationsProvider,
bool forceParallelDownloads = false}) async { bool forceParallelDownloads = false,
bool useExisting = true}) async {
notificationsProvider = notificationsProvider =
notificationsProvider ?? context?.read<NotificationsProvider>(); notificationsProvider ?? context?.read<NotificationsProvider>();
List<String> appsToInstall = []; List<String> appsToInstall = [];
@@ -818,21 +830,82 @@ class AppsProvider with ChangeNotifier {
appsToInstall = appsToInstall =
moveStrToEnd(appsToInstall, obtainiumId, strB: obtainiumTempId); moveStrToEnd(appsToInstall, obtainiumId, strB: obtainiumTempId);
Future<String> updateFn(String id, {bool skipInstalls = false}) async { Future<void> installFn(String id, bool willBeSilent,
DownloadedApk? downloadedFile, DownloadedXApkDir? downloadedDir) async {
apps[id]?.downloadProgress = -1;
notifyListeners();
try {
bool sayInstalled = true;
var contextIfNewInstall =
apps[id]?.installedInfo == null ? context : null;
bool needBGWorkaround =
willBeSilent && context == null && !settingsProvider.useShizuku;
if (downloadedFile != null) {
if (needBGWorkaround) {
// ignore: use_build_context_synchronously
installApk(downloadedFile, contextIfNewInstall,
needsBGWorkaround: true);
} else {
// ignore: use_build_context_synchronously
sayInstalled = await installApk(downloadedFile, contextIfNewInstall,
shizukuPretendToBeGooglePlay: apps[id]!
.app
.additionalSettings['shizukuPretendToBeGooglePlay'] ==
true);
}
} else {
if (needBGWorkaround) {
// ignore: use_build_context_synchronously
installXApkDir(downloadedDir!, contextIfNewInstall,
needsBGWorkaround: true);
} else {
// ignore: use_build_context_synchronously
sayInstalled = await installXApkDir(
downloadedDir!, contextIfNewInstall,
shizukuPretendToBeGooglePlay: apps[id]!
.app
.additionalSettings['shizukuPretendToBeGooglePlay'] ==
true);
}
}
if (willBeSilent && context == null) {
if (!settingsProvider.useShizuku) {
notificationsProvider?.notify(SilentUpdateAttemptNotification(
[apps[id]!.app],
id: id.hashCode));
} else {
notificationsProvider?.notify(SilentUpdateNotification(
[apps[id]!.app], sayInstalled,
id: id.hashCode));
}
}
if (sayInstalled) {
installedIds.add(id);
}
} finally {
apps[id]?.downloadProgress = null;
notifyListeners();
}
}
Future<Map<Object?, Object?>> downloadFn(String id,
{bool skipInstalls = false}) async {
bool willBeSilent = false;
DownloadedApk? downloadedFile;
DownloadedXApkDir? downloadedDir;
try { try {
var downloadedArtifact = var downloadedArtifact =
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
await downloadApp(apps[id]!.app, context, await downloadApp(apps[id]!.app, context,
notificationsProvider: notificationsProvider); notificationsProvider: notificationsProvider,
DownloadedApk? downloadedFile; useExisting: useExisting);
DownloadedXApkDir? downloadedDir;
if (downloadedArtifact is DownloadedApk) { if (downloadedArtifact is DownloadedApk) {
downloadedFile = downloadedArtifact; downloadedFile = downloadedArtifact;
} else { } else {
downloadedDir = downloadedArtifact as DownloadedXApkDir; downloadedDir = downloadedArtifact as DownloadedXApkDir;
} }
id = downloadedFile?.appId ?? downloadedDir!.appId; id = downloadedFile?.appId ?? downloadedDir!.appId;
bool willBeSilent = await canInstallSilently(apps[id]!.app); willBeSilent = await canInstallSilently(apps[id]!.app);
if (!settingsProvider.useShizuku) { if (!settingsProvider.useShizuku) {
if (!(await settingsProvider.getInstallPermission(enforce: false))) { if (!(await settingsProvider.getInstallPermission(enforce: false))) {
throw ObtainiumError(tr('cancelled')); throw ObtainiumError(tr('cancelled'));
@@ -853,80 +926,33 @@ class AppsProvider with ChangeNotifier {
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
await waitForUserToReturnToForeground(context); await waitForUserToReturnToForeground(context);
} }
apps[id]?.downloadProgress = -1;
notifyListeners();
try {
if (!skipInstalls) {
bool sayInstalled = true;
var contextIfNewInstall =
apps[id]?.installedInfo == null ? context : null;
bool needBGWorkaround =
willBeSilent && context == null && !settingsProvider.useShizuku;
if (downloadedFile != null) {
if (needBGWorkaround) {
// ignore: use_build_context_synchronously
installApk(downloadedFile, contextIfNewInstall,
needsBGWorkaround: true);
} else {
// ignore: use_build_context_synchronously
sayInstalled = await installApk(
downloadedFile, contextIfNewInstall,
shizukuPretendToBeGooglePlay:
apps[id]!.app.additionalSettings[
'shizukuPretendToBeGooglePlay'] ==
true);
}
} else {
if (needBGWorkaround) {
// ignore: use_build_context_synchronously
installXApkDir(downloadedDir!, contextIfNewInstall,
needsBGWorkaround: true);
} else {
// ignore: use_build_context_synchronously
sayInstalled = await installXApkDir(
downloadedDir!, contextIfNewInstall,
shizukuPretendToBeGooglePlay:
apps[id]!.app.additionalSettings[
'shizukuPretendToBeGooglePlay'] ==
true);
}
}
if (willBeSilent && context == null) {
if (!settingsProvider.useShizuku) {
notificationsProvider?.notify(SilentUpdateAttemptNotification(
[apps[id]!.app],
id: id.hashCode));
} else {
notificationsProvider?.notify(SilentUpdateNotification(
[apps[id]!.app], sayInstalled,
id: id.hashCode));
}
}
if (sayInstalled) {
installedIds.add(id);
}
}
} finally {
apps[id]?.downloadProgress = null;
notifyListeners();
}
} catch (e) { } catch (e) {
errors.add(id, e, appName: apps[id]?.name); errors.add(id, e, appName: apps[id]?.name);
} }
return id; return {
'id': id,
'willBeSilent': willBeSilent,
'downloadedFile': downloadedFile,
'downloadedDir': downloadedDir
};
} }
List<Map<Object?, Object?>> downloadResults = [];
if (forceParallelDownloads || !settingsProvider.parallelDownloads) { if (forceParallelDownloads || !settingsProvider.parallelDownloads) {
for (var id in appsToInstall) { for (var id in appsToInstall) {
await updateFn(id); downloadResults.add(await downloadFn(id));
} }
} else { } else {
List<String> ids = await Future.wait( downloadResults = await Future.wait(
appsToInstall.map((id) => updateFn(id, skipInstalls: true))); appsToInstall.map((id) => downloadFn(id, skipInstalls: true)));
for (var id in ids) { }
if (!errors.appIdNames.containsKey(id)) { for (var res in downloadResults) {
await updateFn(id); if (!errors.appIdNames.containsKey(res['id'])) {
} await installFn(
res['id'] as String,
res['willBeSilent'] as bool,
res['downloadedFile'] as DownloadedApk?,
res['downloadedDir'] as DownloadedXApkDir?);
} }
} }
@@ -951,7 +977,8 @@ class AppsProvider with ChangeNotifier {
if (apps[id]!.app.apkUrls.isNotEmpty || if (apps[id]!.app.apkUrls.isNotEmpty ||
apps[id]!.app.otherAssetUrls.isNotEmpty) { apps[id]!.app.otherAssetUrls.isNotEmpty) {
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
fileUrl = await confirmAppFileUrl(apps[id]!.app, context, true); fileUrl = await confirmAppFileUrl(apps[id]!.app, context, true,
evenIfSingleChoice: true);
} }
if (fileUrl != null) { if (fileUrl != null) {
filesToDownload.add(MapEntry(fileUrl, apps[id]!.app)); filesToDownload.add(MapEntry(fileUrl, apps[id]!.app));
@@ -1144,17 +1171,6 @@ class AppsProvider with ChangeNotifier {
: false; : false;
} }
Future<void> updateInstallStatusInMemory(AppInMemory app) async {
apps[app.app.id]?.installedInfo = await getInstalledInfo(app.app.id);
apps[app.app.id]?.icon =
await apps[app.app.id]?.installedInfo?.applicationInfo?.getAppIcon();
apps[app.app.id]?.app.name = await (apps[app.app.id]
?.installedInfo
?.applicationInfo
?.getAppLabel()) ??
app.name;
}
Future<void> loadApps({String? singleId}) async { Future<void> loadApps({String? singleId}) async {
while (loadingApps) { while (loadingApps) {
await Future.delayed(const Duration(microseconds: 1)); await Future.delayed(const Duration(microseconds: 1));
@@ -1163,67 +1179,75 @@ class AppsProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
var sp = SourceProvider(); var sp = SourceProvider();
List<List<String>> errors = []; List<List<String>> errors = [];
List<App?> newApps = (await getAppsDir()) // Parse Apps from JSON var installedAppsData = await getAllInstalledInfo();
List<String> removedAppIds = [];
await Future.wait((await getAppsDir()) // Parse Apps from JSON
.listSync() .listSync()
.where((item) => item.path.toLowerCase().endsWith('.json')) .map((item) async {
.where((item) => App? app;
singleId == null || if (item.path.toLowerCase().endsWith('.json') &&
item.path.split('/').last.toLowerCase() == (singleId == null ||
'${singleId.toLowerCase()}.json') item.path.split('/').last.toLowerCase() ==
.map((e) { '${singleId.toLowerCase()}.json')) {
try { try {
return App.fromJson(jsonDecode(File(e.path).readAsStringSync())); app = App.fromJson(jsonDecode(File(item.path).readAsStringSync()));
} catch (err) { } catch (err) {
if (err is FormatException) { if (err is FormatException) {
logs.add('Corrupt JSON when loading App (will be ignored): $e'); logs.add('Corrupt JSON when loading App (will be ignored): $e');
e.renameSync('${e.path}.corrupt'); item.renameSync('${item.path}.corrupt');
} else { } else {
rethrow; rethrow;
}
} }
} }
}).toList();
for (var app in newApps) {
// Put Apps into memory to list them (fast)
if (app != null) { if (app != null) {
// Save the app to the in-memory list without grabbing any OS info first
apps.update(
app.id,
(value) => AppInMemory(
app!, value.downloadProgress, value.installedInfo, value.icon),
ifAbsent: () => AppInMemory(app!, null, null, null));
notifyListeners();
try { try {
// Try getting the app's source to ensure no invalid apps get loaded
sp.getSource(app.url, overrideSource: app.overrideSource); sp.getSource(app.url, overrideSource: app.overrideSource);
// If the app is installed, grab its OS data and reconcile install statuses
PackageInfo? installedInfo;
try {
installedInfo =
installedAppsData.firstWhere((i) => i.packageName == app!.id);
} catch (e) {
// If the app isn't installed the above throws an error
}
// Reconcile differences between the installed and recorded install info
var moddedApp =
getCorrectedInstallStatusAppIfPossible(app, installedInfo);
if (moddedApp != null) {
app = moddedApp;
// Note the app ID if it was uninstalled externally
if (moddedApp.installedVersion == null) {
removedAppIds.add(moddedApp.id);
}
}
// Update the app in memory with install info and corrections
apps.update( apps.update(
app.id, app.id,
(value) => AppInMemory( (value) => AppInMemory(
app, value.downloadProgress, value.installedInfo, value.icon), app!, value.downloadProgress, installedInfo, value.icon),
ifAbsent: () => AppInMemory(app, null, null, null)); ifAbsent: () => AppInMemory(app!, null, installedInfo, null));
notifyListeners();
} catch (e) { } catch (e) {
errors.add([app.id, app.finalName, e.toString()]); errors.add([app!.id, app.finalName, e.toString()]);
} }
} }
} }));
notifyListeners();
if (errors.isNotEmpty) { if (errors.isNotEmpty) {
removeApps(errors.map((e) => e[0]).toList()); removeApps(errors.map((e) => e[0]).toList());
NotificationsProvider().notify( NotificationsProvider().notify(
AppsRemovedNotification(errors.map((e) => [e[1], e[2]]).toList())); AppsRemovedNotification(errors.map((e) => [e[1], e[2]]).toList()));
} }
// Get install status and other OS info for each App (slow) // Delete externally uninstalled Apps if needed
await Future.wait(apps.values.map((app) { if (removedAppIds.isNotEmpty) {
return updateInstallStatusInMemory(app);
}));
notifyListeners();
// Reconcile version differences
List<App> modifiedApps = [];
for (var app in apps.values) {
var moddedApp =
getCorrectedInstallStatusAppIfPossible(app.app, app.installedInfo);
if (moddedApp != null) {
modifiedApps.add(moddedApp);
}
}
if (modifiedApps.isNotEmpty) {
await saveApps(modifiedApps, attemptToCorrectInstallStatus: false);
var removedAppIds = modifiedApps
.where((a) => a.installedVersion == null)
.map((e) => e.id)
.toList();
// After reconciliation, delete externally uninstalled Apps if needed
if (removedAppIds.isNotEmpty) { if (removedAppIds.isNotEmpty) {
if (settingsProvider.removeOnExternalUninstall) { if (settingsProvider.removeOnExternalUninstall) {
await removeApps(removedAppIds); await removeApps(removedAppIds);
@@ -1234,11 +1258,27 @@ class AppsProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
Future<void> updateAppIcon(String? appId) async {
if (apps[appId]?.icon == null) {
var icon =
(await apps[appId]?.installedInfo?.applicationInfo?.getAppIcon());
if (icon != null) {
apps.update(
apps[appId]!.app.id,
(value) => AppInMemory(apps[appId]!.app, value.downloadProgress,
value.installedInfo, icon),
ifAbsent: () => AppInMemory(
apps[appId]!.app, null, apps[appId]?.installedInfo, icon));
notifyListeners();
}
}
}
Future<void> saveApps(List<App> apps, Future<void> saveApps(List<App> apps,
{bool attemptToCorrectInstallStatus = true, {bool attemptToCorrectInstallStatus = true,
bool onlyIfExists = true}) async { bool onlyIfExists = true}) async {
attemptToCorrectInstallStatus = attemptToCorrectInstallStatus; attemptToCorrectInstallStatus = attemptToCorrectInstallStatus;
for (var a in apps) { await Future.wait(apps.map((a) async {
var app = a.deepCopy(); var app = a.deepCopy();
PackageInfo? info = await getInstalledInfo(app.id); PackageInfo? info = await getInstalledInfo(app.id);
var icon = await info?.applicationInfo?.getAppIcon(); var icon = await info?.applicationInfo?.getAppIcon();
@@ -1260,14 +1300,14 @@ class AppsProvider with ChangeNotifier {
rethrow; rethrow;
} }
} }
} }));
notifyListeners(); notifyListeners();
export(isAuto: true); export(isAuto: true);
} }
Future<void> removeApps(List<String> appIds) async { Future<void> removeApps(List<String> appIds) async {
var apkFiles = APKDir.listSync(); var apkFiles = APKDir.listSync();
for (var appId in appIds) { await Future.wait(appIds.map((appId) async {
File file = File('${(await getAppsDir()).path}/$appId.json'); File file = File('${(await getAppsDir()).path}/$appId.json');
if (file.existsSync()) { if (file.existsSync()) {
file.deleteSync(recursive: true); file.deleteSync(recursive: true);
@@ -1281,7 +1321,7 @@ class AppsProvider with ChangeNotifier {
if (apps.containsKey(appId)) { if (apps.containsKey(appId)) {
apps.remove(appId); apps.remove(appId);
} }
} }));
if (appIds.isNotEmpty) { if (appIds.isNotEmpty) {
notifyListeners(); notifyListeners();
export(isAuto: true); export(isAuto: true);
@@ -1461,6 +1501,34 @@ class AppsProvider with ChangeNotifier {
return updateAppIds; return updateAppIds;
} }
Map<String, dynamic> generateExportJSON(
{List<String>? appIds, bool? overrideExportSettings}) {
Map<String, dynamic> finalExport = {};
finalExport['apps'] = apps.values
.where((e) {
if (appIds == null) {
return true;
} else {
return appIds.contains(e.app.id);
}
})
.map((e) => e.app.toJson())
.toList();
bool shouldExportSettings = settingsProvider.exportSettings;
if (overrideExportSettings != null) {
shouldExportSettings = overrideExportSettings;
}
if (shouldExportSettings) {
finalExport['settings'] = Map<String, Object?>.fromEntries(
(settingsProvider.prefs
?.getKeys()
.map((key) => MapEntry(key, settingsProvider.prefs?.get(key)))
.toList()) ??
[]);
}
return finalExport;
}
Future<String?> export( Future<String?> export(
{bool pickOnly = false, isAuto = false, SettingsProvider? sp}) async { {bool pickOnly = false, isAuto = false, SettingsProvider? sp}) async {
SettingsProvider settingsProvider = sp ?? this.settingsProvider; SettingsProvider settingsProvider = sp ?? this.settingsProvider;
@@ -1491,17 +1559,7 @@ class AppsProvider with ChangeNotifier {
} }
String? returnPath; String? returnPath;
if (!pickOnly) { if (!pickOnly) {
Map<String, dynamic> finalExport = {}; Map<String, dynamic> finalExport = generateExportJSON();
finalExport['apps'] = apps.values.map((e) => e.app.toJson()).toList();
if (settingsProvider.exportSettings) {
finalExport['settings'] = Map<String, Object?>.fromEntries(
(settingsProvider.prefs
?.getKeys()
.map((key) =>
MapEntry(key, settingsProvider.prefs?.get(key)))
.toList()) ??
[]);
}
var result = await saf.createFile(exportDir, var result = await saf.createFile(exportDir,
displayName: displayName:
'${tr('obtainiumExportHyphenatedLowercase')}-${DateTime.now().toIso8601String().replaceAll(':', '-')}${isAuto ? '-auto' : ''}.json', '${tr('obtainiumExportHyphenatedLowercase')}-${DateTime.now().toIso8601String().replaceAll(':', '-')}${isAuto ? '-auto' : ''}.json',
@@ -1516,7 +1574,7 @@ class AppsProvider with ChangeNotifier {
return returnPath; return returnPath;
} }
Future<MapEntry<int, bool>> import(String appsJSON) async { Future<MapEntry<List<App>, bool>> import(String appsJSON) async {
var decodedJSON = jsonDecode(appsJSON); var decodedJSON = jsonDecode(appsJSON);
var newFormat = decodedJSON is! List; var newFormat = decodedJSON is! List;
List<App> importedApps = List<App> importedApps =
@@ -1540,6 +1598,8 @@ class AppsProvider with ChangeNotifier {
settingsMap.forEach((key, value) { settingsMap.forEach((key, value) {
if (value is int) { if (value is int) {
settingsProvider.prefs?.setInt(key, value); settingsProvider.prefs?.setInt(key, value);
} else if (value is double) {
settingsProvider.prefs?.setDouble(key, value);
} else if (value is bool) { } else if (value is bool) {
settingsProvider.prefs?.setBool(key, value); settingsProvider.prefs?.setBool(key, value);
} else if (value is List) { } else if (value is List) {
@@ -1550,8 +1610,8 @@ class AppsProvider with ChangeNotifier {
} }
}); });
} }
return MapEntry<int, bool>( return MapEntry<List<App>, bool>(
importedApps.length, newFormat && decodedJSON['settings'] != null); importedApps, newFormat && decodedJSON['settings'] != null);
} }
@override @override
@@ -1613,7 +1673,9 @@ class _AppFilePickerState extends State<AppFilePicker> {
? tr('selectX', args: [tr('releaseAsset').toLowerCase()]) ? tr('selectX', args: [tr('releaseAsset').toLowerCase()])
: tr('pickAnAPK')), : tr('pickAnAPK')),
content: Column(children: [ content: Column(children: [
Text(tr('appHasMoreThanOnePackage', args: [widget.app.finalName])), urlsToSelectFrom.length > 1
? Text(tr('appHasMoreThanOnePackage', args: [widget.app.finalName]))
: const SizedBox.shrink(),
const SizedBox(height: 16), const SizedBox(height: 16),
...urlsToSelectFrom.map( ...urlsToSelectFrom.map(
(u) => RadioListTile<String>( (u) => RadioListTile<String>(
@@ -1726,7 +1788,9 @@ Future<void> bgUpdateCheck(String taskId, Map<String, dynamic>? params) async {
int maxRetryWaitSeconds = 5; int maxRetryWaitSeconds = 5;
var netResult = await (Connectivity().checkConnectivity()); var netResult = await (Connectivity().checkConnectivity());
if (netResult.contains(ConnectivityResult.none)) { if (netResult.contains(ConnectivityResult.none) ||
netResult.isEmpty ||
(netResult.contains(ConnectivityResult.vpn) && netResult.length == 1)) {
logs.add('BG update task: No network.'); logs.add('BG update task: No network.');
return; return;
} }

View File

@@ -354,11 +354,17 @@ preStandardizeUrl(String url) {
url.toLowerCase().indexOf('https://') != 0) { url.toLowerCase().indexOf('https://') != 0) {
url = 'https://$url'; url = 'https://$url';
} }
var uri = Uri.tryParse(url);
var trailingSlash = ((uri?.path.endsWith('/') ?? false) ||
((uri?.path.isEmpty ?? false) && url.endsWith('/'))) &&
(uri?.queryParameters.isEmpty ?? false);
url = url url = url
.split('/') .split('/')
.where((e) => e.isNotEmpty) .where((e) => e.isNotEmpty)
.join('/') .join('/')
.replaceFirst(':/', '://'); .replaceFirst(':/', '://') +
(trailingSlash ? '/' : '');
return url; return url;
} }
@@ -461,6 +467,10 @@ abstract class AppSource {
} }
} }
void runOnAddAppInputChange(String inputUrl) {
//
}
String sourceSpecificStandardizeURL(String url) { String sourceSpecificStandardizeURL(String url) {
throw NotImplementedError(); throw NotImplementedError();
} }
@@ -485,13 +495,15 @@ abstract class AppSource {
], ],
[ [
GeneratedFormTextField('versionExtractionRegEx', GeneratedFormTextField('versionExtractionRegEx',
label: tr('versionExtractionRegEx'), label: tr('trimVersionString'),
required: false, required: false,
additionalValidators: [(value) => regExValidator(value)]), additionalValidators: [(value) => regExValidator(value)]),
], ],
[ [
GeneratedFormTextField('matchGroupToUse', GeneratedFormTextField('matchGroupToUse',
label: tr('matchGroupToUse'), required: false, hint: '\$0') label: tr('matchGroupToUseForX', args: [tr('trimVersionString')]),
required: false,
hint: '\$0')
], ],
[ [
GeneratedFormSwitch('versionDetection', GeneratedFormSwitch('versionDetection',
@@ -523,8 +535,7 @@ abstract class AppSource {
[GeneratedFormTextField('appName', label: tr('appName'), required: false)], [GeneratedFormTextField('appName', label: tr('appName'), required: false)],
[ [
GeneratedFormSwitch('shizukuPretendToBeGooglePlay', GeneratedFormSwitch('shizukuPretendToBeGooglePlay',
label: tr('shizukuPretendToBeGooglePlay'), label: tr('shizukuPretendToBeGooglePlay'), defaultValue: false)
defaultValue: false)
], ],
[ [
GeneratedFormSwitch('exemptFromBackgroundUpdates', GeneratedFormSwitch('exemptFromBackgroundUpdates',
@@ -616,7 +627,7 @@ abstract class AppSource {
} }
bool canSearch = false; bool canSearch = false;
bool excludeFromMassSearch = false; bool includeAdditionalOptsInMainSearch = false;
List<GeneratedFormItem> searchQuerySettingFormItems = []; List<GeneratedFormItem> searchQuerySettingFormItems = [];
Future<Map<String, List<String>>> search(String query, Future<Map<String, List<String>>> search(String query,
{Map<String, dynamic> querySettings = const {}}) { {Map<String, dynamic> querySettings = const {}}) {
@@ -752,9 +763,9 @@ class SourceProvider {
APKPure(), APKPure(),
Aptoide(), Aptoide(),
Uptodown(), Uptodown(),
APKMirror(),
HuaweiAppGallery(), HuaweiAppGallery(),
Jenkins(), Jenkins(),
APKMirror(),
Signal(), Signal(),
VLC(), VLC(),
WhatsApp(), WhatsApp(),

View File

@@ -5,10 +5,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: android_intent_plus name: android_intent_plus
sha256: "2bfdbee8d65e7c26f88b66f0a91f2863da4d3596d8a658b4162c8de5cf04b074" sha256: "007703c1b2cac7ca98add3336b98cffa4baa11d5133cc463293dba9daa39cdf6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.2" version: "5.1.0"
android_package_installer: android_package_installer:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -47,18 +47,42 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: app_links name: app_links
sha256: "1c2b9e9c56d80d17610bcbd111b37187875c5d0ded8654caa1bda14ea753d001" sha256: ae5f9a1b7d40d26178f605414be81ed4260350b4fae8259fe5ca4f89fe70c4af
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.1" version: "6.1.4"
app_links_linux:
dependency: transitive
description:
name: app_links_linux
sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81
url: "https://pub.dev"
source: hosted
version: "1.0.3"
app_links_platform_interface:
dependency: transitive
description:
name: app_links_platform_interface
sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
app_links_web:
dependency: transitive
description:
name: app_links_web
sha256: af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555
url: "https://pub.dev"
source: hosted
version: "1.0.4"
archive: archive:
dependency: transitive dependency: transitive
description: description:
name: archive name: archive
sha256: ecf4273855368121b1caed0d10d4513c7241dfc813f7d3c8933b36622ae9b265 sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.5.1" version: "3.6.1"
args: args:
dependency: transitive dependency: transitive
description: description:
@@ -79,10 +103,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: background_fetch name: background_fetch
sha256: "2fe367c9be0e256dadb75b8b637b0b58a2a2d2317b7c8420bb1ae8b41e23fde3" sha256: b5c298c911bc2ce41152668bc72eb0488f0665d75bc6d1e69e7d8367763eddcd
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.4" version: "1.3.5"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@@ -135,26 +159,26 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: connectivity_plus name: connectivity_plus
sha256: db7a4e143dc72cc3cb2044ef9b052a7ebfe729513e6a82943bc3526f784365b8 sha256: "3e7d1d9dbae40ae82cbe6c23c518f0c4ffe32764ee9749b9a99d32cbac8734f6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.3" version: "6.0.4"
connectivity_plus_platform_interface: connectivity_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: connectivity_plus_platform_interface name: connectivity_plus_platform_interface
sha256: b6a56efe1e6675be240de39107281d4034b64ac23438026355b4234042a35adb sha256: "42657c1715d48b167930d5f34d00222ac100475f73d10162ddf43e714932f204"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "2.0.1"
cross_file: cross_file:
dependency: transitive dependency: transitive
description: description:
name: cross_file name: cross_file
sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.3.4+1" version: "0.3.4+2"
crypto: crypto:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -191,18 +215,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: device_info_plus name: device_info_plus
sha256: eead12d1a1ed83d8283ab4c2f3fca23ac4082f29f25f29dff0f758f57d06ec91 sha256: "93429694c9253d2871b3af80cf11b3cbb5c65660d402ed7bf69854ce4a089f82"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.1.0" version: "10.1.1"
device_info_plus_platform_interface: device_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: device_info_plus_platform_interface name: device_info_plus_platform_interface
sha256: d3b01d5868b50ae571cd1dc6e502fc94d956b665756180f7b16ead09e836fd64 sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.0" version: "7.0.1"
dynamic_color: dynamic_color:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -215,10 +239,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: easy_localization name: easy_localization
sha256: "432698c31a488dd64c56d4759f20d04844baba5e9e4f2cb1abb9676257918b17" sha256: fa59bcdbbb911a764aa6acf96bbb6fa7a5cf8234354fc45ec1a43a0349ef0201
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.6" version: "3.0.7"
easy_logger: easy_logger:
dependency: transitive dependency: transitive
description: description:
@@ -263,10 +287,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: file_picker name: file_picker
sha256: "29c90806ac5f5fb896547720b73b17ee9aed9bba540dc5d91fe29f8c5745b10a" sha256: "824f5b9f389bfc4dddac3dea76cd70c51092d9dff0b2ece7ef4f53db8547d258"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.0.3" version: "8.0.6"
fixnum: fixnum:
dependency: transitive dependency: transitive
description: description:
@@ -279,18 +303,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flex_color_picker name: flex_color_picker
sha256: "5c846437069fb7afdd7ade6bf37e628a71d2ab0787095ddcb1253bf9345d5f3a" sha256: "809af4ec82ede3b140ed0219b97d548de99e47aa4b99b14a10f705a2dbbcba5e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.4.1" version: "3.5.1"
flex_seed_scheme: flex_seed_scheme:
dependency: transitive dependency: transitive
description: description:
name: flex_seed_scheme name: flex_seed_scheme
sha256: "4cee2f1d07259f77e8b36f4ec5f35499d19e74e17c7dce5b819554914082bc01" sha256: cc08c81879ecfd2ab840664ce4770980da0b8a319e35f51bcf763849b7f7596b
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.5.0" version: "3.1.2"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@@ -308,10 +332,58 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_fgbg name: flutter_fgbg
sha256: "08c4d2fd229e3df26083d5aecc3dea9ff4f2d188f8cd57aaf2b3f047bd08a047" sha256: "5e61a2ff2e2e83614ae7690bea3dfa74bbd91b5c083e81ce07692411ce65e3d7"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.3.0" version: "0.4.0"
flutter_keyboard_visibility:
dependency: transitive
description:
name: flutter_keyboard_visibility
sha256: "98664be7be0e3ffca00de50f7f6a287ab62c763fc8c762e0a21584584a3ff4f8"
url: "https://pub.dev"
source: hosted
version: "6.0.0"
flutter_keyboard_visibility_linux:
dependency: transitive
description:
name: flutter_keyboard_visibility_linux
sha256: "6fba7cd9bb033b6ddd8c2beb4c99ad02d728f1e6e6d9b9446667398b2ac39f08"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
flutter_keyboard_visibility_macos:
dependency: transitive
description:
name: flutter_keyboard_visibility_macos
sha256: c5c49b16fff453dfdafdc16f26bdd8fb8d55812a1d50b0ce25fc8d9f2e53d086
url: "https://pub.dev"
source: hosted
version: "1.0.0"
flutter_keyboard_visibility_platform_interface:
dependency: transitive
description:
name: flutter_keyboard_visibility_platform_interface
sha256: e43a89845873f7be10cb3884345ceb9aebf00a659f479d1c8f4293fcb37022a4
url: "https://pub.dev"
source: hosted
version: "2.0.0"
flutter_keyboard_visibility_web:
dependency: transitive
description:
name: flutter_keyboard_visibility_web
sha256: d3771a2e752880c79203f8d80658401d0c998e4183edca05a149f5098ce6e3d1
url: "https://pub.dev"
source: hosted
version: "2.0.0"
flutter_keyboard_visibility_windows:
dependency: transitive
description:
name: flutter_keyboard_visibility_windows
sha256: fc4b0f0b6be9b93ae527f3d527fb56ee2d918cd88bbca438c478af7bcfd0ef73
url: "https://pub.dev"
source: hosted
version: "1.0.0"
flutter_launcher_icons: flutter_launcher_icons:
dependency: "direct dev" dependency: "direct dev"
description: description:
@@ -324,34 +396,34 @@ packages:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: flutter_lints name: flutter_lints
sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.2" version: "4.0.0"
flutter_local_notifications: flutter_local_notifications:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_local_notifications name: flutter_local_notifications
sha256: "84a3af6c7fb43c85c3528b434dacc7a7ed4551d1209d93773bf6045cec9ace68" sha256: dd6676d8c2926537eccdf9f72128bbb2a9d0814689527b17f92c248ff192eaf3
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "17.1.1" version: "17.2.1+2"
flutter_local_notifications_linux: flutter_local_notifications_linux:
dependency: transitive dependency: transitive
description: description:
name: flutter_local_notifications_linux name: flutter_local_notifications_linux
sha256: "33f741ef47b5f63cc7f78fe75eeeac7e19f171ff3c3df054d84c1e38bedb6a03" sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.0+1" version: "4.0.1"
flutter_local_notifications_platform_interface: flutter_local_notifications_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: flutter_local_notifications_platform_interface name: flutter_local_notifications_platform_interface
sha256: "340abf67df238f7f0ef58f4a26d2a83e1ab74c77ab03cd2b2d5018ac64db30b7" sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.1.0" version: "7.2.0"
flutter_localizations: flutter_localizations:
dependency: transitive dependency: transitive
description: flutter description: flutter
@@ -361,23 +433,31 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_markdown name: flutter_markdown
sha256: "9921f9deda326f8a885e202b1e35237eadfc1345239a0f6f0f1ff287e047547f" sha256: "2e8a801b1ded5ea001a4529c97b1f213dcb11c6b20668e081cafb23468593514"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.1" version: "0.7.3"
flutter_plugin_android_lifecycle: flutter_plugin_android_lifecycle:
dependency: transitive dependency: transitive
description: description:
name: flutter_plugin_android_lifecycle name: flutter_plugin_android_lifecycle
sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f" sha256: "9d98bd47ef9d34e803d438f17fd32b116d31009f534a6fa5ce3a1167f189a6de"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.19" version: "2.0.21"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_typeahead:
dependency: "direct main"
description:
name: flutter_typeahead
sha256: d64712c65db240b1057559b952398ebb6e498077baeebf9b0731dade62438a6d
url: "https://pub.dev"
source: hosted
version: "5.2.0"
flutter_web_plugins: flutter_web_plugins:
dependency: transitive dependency: transitive
description: flutter description: flutter
@@ -387,18 +467,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: fluttertoast name: fluttertoast
sha256: "81b68579e23fcbcada2db3d50302813d2371664afe6165bc78148050ab94bf66" sha256: "7eae679e596a44fdf761853a706f74979f8dd3cd92cf4e23cae161fda091b847"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.2.5" version: "8.2.6"
fraction: fraction:
dependency: transitive dependency: transitive
description: description:
name: fraction name: fraction
sha256: "09e9504c9177bbd77df56e5d147abfbb3b43360e64bf61510059c14d6a82d524" sha256: ac0d9904bb8211eb28606bdf623ff9f222c53240d8e9b927a07c149d356eddc2
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.2" version: "5.0.3"
gtk: gtk:
dependency: transitive dependency: transitive
description: description:
@@ -427,10 +507,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: http name: http
sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.1" version: "1.2.2"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
@@ -443,18 +523,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: image name: image
sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e" sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.1.7" version: "4.2.0"
intl: intl:
dependency: transitive dependency: transitive
description: description:
name: intl name: intl
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.18.1" version: "0.19.0"
json_annotation: json_annotation:
dependency: transitive dependency: transitive
description: description:
@@ -467,36 +547,36 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker name: leak_tracker
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.0.0" version: "10.0.4"
leak_tracker_flutter_testing: leak_tracker_flutter_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_flutter_testing name: leak_tracker_flutter_testing
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "3.0.3"
leak_tracker_testing: leak_tracker_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_testing name: leak_tracker_testing
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "3.0.1"
lints: lints:
dependency: transitive dependency: transitive
description: description:
name: lints name: lints
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.0" version: "4.0.0"
markdown: markdown:
dependency: transitive dependency: "direct main"
description: description:
name: markdown name: markdown
sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051
@@ -523,10 +603,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.11.0" version: "1.12.0"
mime: mime:
dependency: transitive dependency: transitive
description: description:
@@ -563,26 +643,26 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: path_provider name: path_provider
sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.3" version: "2.1.4"
path_provider_android: path_provider_android:
dependency: transitive dependency: transitive
description: description:
name: path_provider_android name: path_provider_android
sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d sha256: "490539678396d4c3c0b06efdaab75ae60675c3e0c66f72bc04c2e2c1e0e2abeb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.4" version: "2.2.9"
path_provider_foundation: path_provider_foundation:
dependency: transitive dependency: transitive
description: description:
name: path_provider_foundation name: path_provider_foundation
sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.2" version: "2.4.0"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
@@ -603,10 +683,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path_provider_windows name: path_provider_windows
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.3.0"
permission_handler: permission_handler:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -619,34 +699,34 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_android name: permission_handler_android
sha256: "8bb852cd759488893805c3161d0b2b5db55db52f773dbb014420b304055ba2c5" sha256: eaf2a1ec4472775451e88ca6a7b86559ef2f1d1ed903942ed135e38ea0097dca
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "12.0.6" version: "12.0.8"
permission_handler_apple: permission_handler_apple:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_apple name: permission_handler_apple
sha256: e9ad66020b89ff1b63908f247c2c6f931c6e62699b756ef8b3c4569350cd8662 sha256: e6f6d73b12438ef13e648c4ae56bd106ec60d17e90a59c4545db6781229082a0
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "9.4.4" version: "9.4.5"
permission_handler_html: permission_handler_html:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_html name: permission_handler_html
sha256: "54bf176b90f6eddd4ece307e2c06cf977fb3973719c35a93b85cc7093eb6070d" sha256: "6cac773d389e045a8d4f85418d07ad58ef9e42a56e063629ce14c4c26344de24"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.1.1" version: "0.1.2"
permission_handler_platform_interface: permission_handler_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_platform_interface name: permission_handler_platform_interface
sha256: "48d4fcf201a1dad93ee869ab0d4101d084f49136ec82a8a06ed9cfeacab9fd20" sha256: fe0ffe274d665be8e34f9c59705441a7d248edebbe5d9e3ec2665f88b79358ea
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.2.1" version: "4.2.2"
permission_handler_windows: permission_handler_windows:
dependency: transitive dependency: transitive
description: description:
@@ -667,10 +747,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: platform name: platform
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.4" version: "3.1.5"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -679,6 +759,38 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.8" version: "2.1.8"
pointer_interceptor:
dependency: transitive
description:
name: pointer_interceptor
sha256: "57210410680379aea8b1b7ed6ae0c3ad349bfd56fe845b8ea934a53344b9d523"
url: "https://pub.dev"
source: hosted
version: "0.10.1+2"
pointer_interceptor_ios:
dependency: transitive
description:
name: pointer_interceptor_ios
sha256: a6906772b3205b42c44614fcea28f818b1e5fdad73a4ca742a7bd49818d9c917
url: "https://pub.dev"
source: hosted
version: "0.10.1"
pointer_interceptor_platform_interface:
dependency: transitive
description:
name: pointer_interceptor_platform_interface
sha256: "0597b0560e14354baeb23f8375cd612e8bd4841bf8306ecb71fcd0bb78552506"
url: "https://pub.dev"
source: hosted
version: "0.10.0+1"
pointer_interceptor_web:
dependency: transitive
description:
name: pointer_interceptor_web
sha256: "7a7087782110f8c1827170660b09f8aa893e0e9a61431dbbe2ac3fc482e8c044"
url: "https://pub.dev"
source: hosted
version: "0.10.2+1"
provider: provider:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -691,74 +803,74 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: share_plus name: share_plus
sha256: ef3489a969683c4f3d0239010cc8b7a2a46543a8d139e111c06c558875083544 sha256: "59dfd53f497340a0c3a81909b220cfdb9b8973a91055c4e5ab9b9b9ad7c513c0"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "9.0.0" version: "10.0.0"
share_plus_platform_interface: share_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: share_plus_platform_interface name: share_plus_platform_interface
sha256: "0f9e4418835d1b2c3ae78fdb918251959106cefdbc4dd43526e182f80e82f6d4" sha256: "6ababf341050edff57da8b6990f11f4e99eaba837865e2e6defe16d039619db5"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.0" version: "5.0.0"
shared_preferences: shared_preferences:
dependency: "direct main" dependency: "direct main"
description: description:
name: shared_preferences name: shared_preferences
sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 sha256: c272f9cabca5a81adc9b0894381e9c1def363e980f960fa903c604c471b22f68
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.3" version: "2.3.1"
shared_preferences_android: shared_preferences_android:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_android name: shared_preferences_android
sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2" sha256: "041be4d9d2dc6079cf342bc8b761b03787e3b71192d658220a56cac9c04a0294"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.2" version: "2.3.0"
shared_preferences_foundation: shared_preferences_foundation:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_foundation name: shared_preferences_foundation
sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" sha256: "671e7a931f55a08aa45be2a13fe7247f2a41237897df434b30d2012388191833"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.5" version: "2.5.0"
shared_preferences_linux: shared_preferences_linux:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_linux name: shared_preferences_linux
sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" sha256: "2ba0510d3017f91655b7543e9ee46d48619de2a2af38e5c790423f7007c7ccc1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.2" version: "2.4.0"
shared_preferences_platform_interface: shared_preferences_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_platform_interface name: shared_preferences_platform_interface
sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b" sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.2" version: "2.4.1"
shared_preferences_web: shared_preferences_web:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_web name: shared_preferences_web
sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a" sha256: "59dc807b94d29d52ddbb1b3c0d3b9d0a67fc535a64e62a5542c8db0513fcb6c2"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" version: "2.4.1"
shared_preferences_windows: shared_preferences_windows:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_windows name: shared_preferences_windows
sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" sha256: "398084b47b7f92110683cac45c6dc4aae853db47e470e5ddcd52cab7f7196ab2"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.2" version: "2.4.0"
shared_storage: shared_storage:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -857,18 +969,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.1" version: "0.7.0"
timezone: timezone:
dependency: transitive dependency: transitive
description: description:
name: timezone name: timezone
sha256: a6ccda4a69a442098b602c44e61a1e2b4bf6f5516e875bbf0f427d5df14745d5 sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.9.3" version: "0.9.4"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@@ -881,26 +993,26 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: url_launcher name: url_launcher
sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e" sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.2.6" version: "6.3.0"
url_launcher_android: url_launcher_android:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_android name: url_launcher_android
sha256: "360a6ed2027f18b73c8d98e159dda67a61b7f2e0f6ec26e86c3ada33b0621775" sha256: "94d8ad05f44c6d4e2ffe5567ab4d741b82d62e3c8e288cc1fcea45965edf47c9"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.3.1" version: "6.3.8"
url_launcher_ios: url_launcher_ios:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_ios name: url_launcher_ios
sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5" sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.2.5" version: "6.3.1"
url_launcher_linux: url_launcher_linux:
dependency: transitive dependency: transitive
description: description:
@@ -913,10 +1025,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_macos name: url_launcher_macos
sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234 sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.0" version: "3.2.0"
url_launcher_platform_interface: url_launcher_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -929,26 +1041,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_web name: url_launcher_web
sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a" sha256: a36e2d7981122fa185006b216eb6b5b97ede3f9a54b7a511bc966971ab98d049
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.3.2"
url_launcher_windows: url_launcher_windows:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_windows name: url_launcher_windows
sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7 sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.1" version: "3.1.2"
uuid: uuid:
dependency: transitive dependency: transitive
description: description:
name: uuid name: uuid
sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8" sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.4.0" version: "4.4.2"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
@@ -961,10 +1073,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vm_service name: vm_service
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "13.0.0" version: "14.2.1"
web: web:
dependency: transitive dependency: transitive
description: description:
@@ -977,18 +1089,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: webview_flutter name: webview_flutter
sha256: "25e1b6e839e8cbfbd708abc6f85ed09d1727e24e08e08c6b8590d7c65c9a8932" sha256: "6869c8786d179f929144b4a1f86e09ac0eddfe475984951ea6c634774c16b522"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.7.0" version: "4.8.0"
webview_flutter_android: webview_flutter_android:
dependency: transitive dependency: transitive
description: description:
name: webview_flutter_android name: webview_flutter_android
sha256: dad3313c9ead95517bb1cae5e1c9d20ba83729d5a59e5e83c0a2d66203f27f91 sha256: c66651fba15f9d7ddd31daec42da8d6bce46c85610a7127e3ebcb39a4395c3c9
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.16.1" version: "3.16.6"
webview_flutter_platform_interface: webview_flutter_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -1001,26 +1113,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: webview_flutter_wkwebview name: webview_flutter_wkwebview
sha256: f12f8d8a99784b863e8b85e4a9a5e3cf1839d6803d2c0c3e0533a8f3c5a992a7 sha256: "9c62cc46fa4f2d41e10ab81014c1de470a6c6f26051a2de32111b2ee55287feb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.13.0" version: "3.14.0"
win32: win32:
dependency: transitive dependency: transitive
description: description:
name: win32 name: win32
sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb" sha256: "015002c060f1ae9f41a818f2d5640389cc05283e368be19dc8d77cecb43c40c9"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.5.0" version: "5.5.3"
win32_registry: win32_registry:
dependency: transitive dependency: transitive
description: description:
name: win32_registry name: win32_registry
sha256: "10589e0d7f4e053f2c61023a31c9ce01146656a70b7b7f0828c0b46d7da2a9bb" sha256: "723b7f851e5724c55409bb3d5a32b203b3afe8587eaf5dafb93a5fed8ecda0d6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.3" version: "1.1.4"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
@@ -1046,5 +1158,5 @@ packages:
source: hosted source: hosted
version: "3.1.2" version: "3.1.2"
sdks: sdks:
dart: ">=3.3.3 <4.0.0" dart: ">=3.4.0 <4.0.0"
flutter: ">=3.19.0" flutter: ">=3.22.0"

View File

@@ -1,5 +1,5 @@
name: obtainium name: obtainium
description: Get Android App Updates Directly From the Source. description: Get Android app updates straight from the source.
# The following line prevents the package from being accidentally published to # The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages. # pub.dev using `flutter pub publish`. This is preferred for private packages.
@@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 1.1.7+2264 version: 1.1.17+2274
environment: environment:
sdk: '>=3.0.0 <4.0.0' sdk: '>=3.0.0 <4.0.0'
@@ -37,7 +37,7 @@ dependencies:
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.5 cupertino_icons: ^1.0.5
path_provider: ^2.0.11 path_provider: ^2.0.11
flutter_fgbg: ^0.3.0 # Try removing reliance on this flutter_fgbg: ^0.4.0
flutter_local_notifications: ^17.0.0 flutter_local_notifications: ^17.0.0
provider: ^6.0.3 provider: ^6.0.3
http: ^1.0.0 http: ^1.0.0
@@ -56,7 +56,7 @@ dependencies:
url: https://github.com/ImranR98/android_package_installer url: https://github.com/ImranR98/android_package_installer
ref: main ref: main
android_package_manager: ^0.7.0 android_package_manager: ^0.7.0
share_plus: ^9.0.0 share_plus: ^10.0.0
sqflite: ^2.2.0+3 sqflite: ^2.2.0+3
easy_localization: ^3.0.1 easy_localization: ^3.0.1
android_intent_plus: ^5.0.1 android_intent_plus: ^5.0.1
@@ -79,6 +79,8 @@ dependencies:
url: https://github.com/re7gog/shizuku_apk_installer url: https://github.com/re7gog/shizuku_apk_installer
ref: master ref: master
markdown: any
flutter_typeahead: ^5.2.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
@@ -89,7 +91,7 @@ dev_dependencies:
# activated in the `analysis_options.yaml` file located at the root of your # activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint # package. See that file for information about deactivating specific lint
# rules and activating additional ones. # rules and activating additional ones.
flutter_lints: ^3.0.0 flutter_lints: ^4.0.0
flutter_launcher_icons: flutter_launcher_icons:
android: "ic_launcher" android: "ic_launcher"
@@ -143,6 +145,6 @@ flutter:
# see https://flutter.dev/custom-fonts/#from-packages # see https://flutter.dev/custom-fonts/#from-packages
fonts: fonts:
- family: Metropolis - family: Wix-Madefor-Display
fonts: fonts:
- asset: assets/fonts/Metropolis-Regular.otf - asset: assets/fonts/WixMadeforDisplay-Regular.otf