Compare commits

...

131 Commits

Author SHA1 Message Date
Imran
e157bda0eb Merge pull request #2171 from ImranR98/dev
- Make downloads faster (#580)
- Better sort options for GitHub releases (#2144)
- Enable arch-based auto-filter for intermediate HTML links (#2162)
- GitLab bugfix (#2167)
2025-03-07 18:13:35 -05:00
Imran Remtulla
adf05abfac Update Flutter + packages, increment version 2025-03-07 18:12:13 -05:00
Imran Remtulla
6a8cf0096d Merge remote-tracking branch 'origin/main' into dev 2025-03-07 18:11:52 -05:00
Imran Remtulla
5e6e3f457c Better sort options for GitHub releases (#2144) 2025-03-07 18:05:45 -05:00
Imran Remtulla
044bd7f8a0 Enable arch-based auto-filter for intermediate HTML links (#2162) 2025-03-07 16:45:32 -05:00
Imran
902f29fdcf Merge pull request #2164 from Psychosoc1al/fix-doubled-webview
Possible fix for apps webpages opened twice with "Show Source webpage in App view"
2025-03-07 16:16:36 -05:00
Imran Remtulla
6c6f256976 GitLab bugfix (#2167) 2025-03-07 16:15:01 -05:00
Imran Remtulla
fbf2330c0f Merge remote-tracking branch 'origin/main' into dev 2025-03-07 15:45:16 -05:00
Imran
86ac573edd Merge pull request #2154 from foXaCe/main
update french translation
2025-03-07 15:44:47 -05:00
Imran
6a07138389 Merge pull request #2163 from Psychosoc1al/dev
Possible fix for RuStore "Show Source webpage in App view" error
2025-03-07 15:44:30 -05:00
Imran Remtulla
23c2664ead Adjustments 2025-03-07 15:41:23 -05:00
Imran Remtulla
4200e1d954 Make downloads faster (#580) 2025-03-07 14:46:51 -05:00
Psychosoc1al
3eb3cf25bf Fix [suppress] duplicated apps webpage view 2025-03-02 19:13:15 +03:00
Psychosoc1al
1b039fb5a5 Fix [suppress] RuStore-provided apps webpage view crash 2025-03-02 07:26:26 +03:00
Psychosoc1al
6a4a15ab4d Remove duplicated line in app.dart 2025-03-02 07:25:19 +03:00
foXaCe
a70c6ef1ed Update fr.json 2025-03-01 10:42:11 +01:00
foXaCe
85e5dddd34 Update fr.json 2025-03-01 10:33:49 +01:00
Imran
0fd496e660 Merge pull request #2139 from ImranR98/dev
Allow users to override author name (#1792)
2025-02-22 19:03:39 -06:00
Imran Remtulla
b3af899ba1 Allow users to override author name (#1792) 2025-02-22 20:01:59 -05:00
Imran
9a58643088 Merge pull request #2138 from ImranR98/dev
- Fix GitLab bug that broke all repos with hyphens in their names (#2125)
- Provide "current" link in HTML source errors to help w/ troubleshooting
2025-02-22 18:47:23 -06:00
Imran Remtulla
b223522801 Update packages, increment version 2025-02-22 19:46:09 -05:00
Imran
375caa4511 Merge pull request #2137 from summoner001/main
Update hu.json
2025-02-22 18:45:18 -06:00
Imran Remtulla
92ebbd9138 Fix GitLab bug that broke all repos with hyphens in their names (#2125) 2025-02-22 19:44:28 -05:00
Imran Remtulla
a3c2761aba Provide "current" link in HTML source errors to help w/ troubleshooting 2025-02-22 19:24:00 -05:00
summoner001
68e38259bd Update hu.json
Fixing typos and misspellings

Fixing name of Tencent App Store - use the official name of Tencent Appstore instead of Tencent App Store whtat's wrong.
2025-02-22 13:33:58 +01:00
Imran
4aed749b44 Merge pull request #2135 from ImranR98/dev
Increment version
2025-02-21 16:53:40 -06:00
Imran Remtulla
e135476d86 Increment version 2025-02-21 17:53:11 -05:00
Imran
7490942fad Merge pull request #2134 from ImranR98/dev
Better file naming on selective export + updated screenshots
2025-02-21 16:39:46 -06:00
Imran Remtulla
794be438b0 Updated screenshots (#2131) 2025-02-21 17:38:00 -05:00
Imran Remtulla
f2f055ad83 Better file naming on selective export 2025-02-21 17:31:14 -05:00
Imran
4c94f278e2 Merge pull request #2133 from ImranR98/dev
Fix minor translation error (#2121)
2025-02-21 16:22:09 -06:00
Imran Remtulla
22acb6a2dd Fix minor translation error (#2121) 2025-02-21 17:16:44 -05:00
Imran
d32befb832 Merge pull request #2130 from ImranR98/dev
Bugfix - app crashes when language set to zh_Hant_TW
2025-02-21 11:52:02 -06:00
Imran Remtulla
94d8295992 Bugfix - app crashes when language set to zh_Hant_TW 2025-02-21 12:51:44 -05:00
Imran
dcf9f5732a Merge pull request #2129 from ImranR98/dev
- Correct spelling of Wi-Fi - not "WiFi" (#2121)
- Change font to Montserrat (#2122)
- Extract GitLab Asset Filenames (#2127)
- Fix "Bad State: No element" Error on Some Direct APK Links (#2128)
2025-02-21 10:05:46 -06:00
Imran Remtulla
c89790d58f Increment version, update packages 2025-02-21 11:04:25 -05:00
Imran Remtulla
3633c58bea Change font to Montserrat (#2122) 2025-02-21 11:01:38 -05:00
Imran Remtulla
9770501aec Correct spelling of Wi-Fi - not "WiFi" (#2121) 2025-02-21 10:44:49 -05:00
Imran Remtulla
167d0ccced Extract GitLab Asset Filenames (#2127) 2025-02-21 10:39:45 -05:00
Imran Remtulla
430d1f2690 Fix "Bad State: No element" Error on Some Direct APK Links (#2128) 2025-02-21 10:22:49 -05:00
Imran
eb21ba3f6e Merge pull request #2113 from ImranR98/dev
Fix RuStore characterset issue + support RuStore app  changelogs
2025-02-13 17:07:19 -05:00
Imran Remtulla
3ab14e2311 Fix RuStore characterset issue + support RuStore app changelogs 2025-02-13 17:06:48 -05:00
Imran Remtulla
fff3b22e74 Merge remote-tracking branch 'origin/dev' 2025-02-13 13:18:27 -05:00
Imran
46354e648a Merge pull request #2081 from PadowYT2/rustore
RuStore support
2025-02-13 13:09:35 -05:00
PadowYT2
4f67ba3f3b Merge pull request #1 from ImranR98/rustore
Fix RuStore PR bug + reorder items in README
2025-02-13 20:46:02 +03:00
Imran
e5db702a67 Merge pull request #2112 from ImranR98/dev
- GitLab URL parsing bugfix (#2106)
- Tencent store bugfix (#2108)
- Allow for MarkDown inside "about" app field (#2109)
2025-02-13 11:07:16 -05:00
Imran Remtulla
53451fd883 Upgrade Flutter + packages, increment version 2025-02-13 11:06:03 -05:00
Imran Remtulla
491d3cb723 Merge remote-tracking branch 'origin/main' into dev 2025-02-13 11:05:55 -05:00
Imran Remtulla
6c7644c9b3 Allow for MarkDown inside "about" app field (#2109) 2025-02-13 10:33:46 -05:00
Imran Remtulla
8539581fe9 Tencent store bugfix (#2108) 2025-02-13 10:14:46 -05:00
Imran Remtulla
f301f6cedb Fix RuStore PR bug + reorder items in README 2025-02-13 10:05:09 -05:00
Imran Remtulla
93c8bca038 GitLab URL parsing bugfix (#2106) 2025-02-13 09:55:25 -05:00
PadowYT2
0961e044a7 Merge branch 'ImranR98:main' into rustore 2025-02-02 01:14:05 +03:00
Imran
7da631e429 Merge pull request #2094 from ImranR98/dev
- Attempt to fix "double download" bug (#2073)
- Avoid JSON corruption when storage full (#2089)
- Fix error when GitLab repo is in a subgroup (#2079)
- Update screenshots in README
2025-01-27 21:13:54 -05:00
Imran Remtulla
66c08f0bfd Updated screenshots 2025-01-27 21:12:35 -05:00
Imran Remtulla
79a2484d68 Don't show debug banner in development 2025-01-27 20:29:34 -05:00
Imran Remtulla
c3c7c844dc Update Flutter submodule 2025-01-27 20:21:44 -05:00
Imran Remtulla
075d0a0854 Enable Korean, update Flutter + packages, increment version 2025-01-27 20:20:37 -05:00
Imran Remtulla
cc0416e344 Merge remote-tracking branch 'origin/main' into dev 2025-01-27 20:16:04 -05:00
Imran
af7088b754 Merge pull request #2090 from ColorfulRhino/patch-2
Fix and improve German translation
2025-01-27 20:14:53 -05:00
Imran Remtulla
ba21137da7 Fix error when GitLab repo is in a subgroup (#2079) 2025-01-27 20:14:11 -05:00
Imran Remtulla
a7a5749d4f Avoid JSON corruption when storage full (#2089) 2025-01-27 19:55:12 -05:00
Imran Remtulla
fcf3c8b635 Attempt to fix "double download" bug (#2073) 2025-01-27 19:51:02 -05:00
Imran
69f578652c Merge pull request #2080 from tkgo11/main
Added Korean translation.
2025-01-26 23:46:47 -05:00
ColorfulRhino
7593af25b9 Improve German translation
- Increase consistency for certain terms
- Address concerns for the translation of _author_ containing a colon by using a different wording
- Minor improvements
2025-01-26 13:32:35 +00:00
ColorfulRhino
1e8fd33469 Restore two lines in de.json accidentally removed during merge conflict
Two lines were accidentally reverted in #2057 due to a merge conflict.
2025-01-26 13:13:41 +00:00
PadowYT2
03f50e501e This was removed by accident 2025-01-20 22:04:41 +03:00
PadowYT2
21dacb6171 Revert "Debug the response"
This reverts commit 16ecc88fcd.
2025-01-20 22:03:06 +03:00
PadowYT2
16ecc88fcd Debug the response 2025-01-20 21:47:43 +03:00
PadowYT2
1f829289ed Fix the API URL having www 2025-01-20 21:36:02 +03:00
PadowYT2
be739b7639 Call the function properly 2025-01-20 21:06:08 +03:00
PadowYT2
4b66aefb33 Initial progress of RuStore
almost ran out of storage space while trying to build
2025-01-20 21:04:51 +03:00
tkgo11
3f948ae73c Create ko.json 2025-01-20 13:53:32 +09:00
Imran
de2e881e82 Merge pull request #2075 from ImranR98/dev
- Fix categories UI bug (#2064)
- Fix how changelog quotes look in dark theme (#2065)
2025-01-14 17:38:54 +03:00
Imran Remtulla
9af3aaa82a Increment version 2025-01-14 17:37:46 +03:00
Imran Remtulla
3a5157ced0 Fix how changelog quotes look in dark theme (#2065) 2025-01-14 17:36:14 +03:00
Imran Remtulla
e16320f995 Fix categories UI bug (#2064) 2025-01-14 17:23:49 +03:00
Imran Remtulla
aac01885f1 Update Flutter version 2025-01-14 16:54:35 +03:00
Imran
7d330cd074 Merge pull request #2062 from ImranR98/dev
Update Flutter submodule
2025-01-11 22:19:15 +02:00
Imran Remtulla
8b0e2aaef1 Update Flutter submodule 2025-01-11 23:18:27 +03:00
Imran
5db53d9c71 Merge pull request #2044 from ArcticFoxPro/main
feat(i18n): Add Tencent App Store zh-Hans translations and add zh-Hans version of Obtainium badge
2025-01-11 22:03:44 +02:00
Imran
ff5bba933b Merge branch 'main' into main 2025-01-11 22:03:36 +02:00
Imran
2b48ee81b7 Merge pull request #2048 from mxhdee/main
Update fa.json
2025-01-11 22:02:10 +02:00
Imran
fe6d0040c4 Merge pull request #2050 from Kevinr99089/main
Update fr.json
2025-01-11 22:01:59 +02:00
Imran
17d32cd1c6 Merge pull request #2057 from DwainZwerg/patch-2
Update de.json
2025-01-11 22:01:50 +02:00
Imran
c6a62fe15a Merge branch 'main' into patch-2 2025-01-11 22:01:41 +02:00
Imran
2b22de585e Merge pull request #2059 from ColorfulRhino/patch-1
Improve German translation
2025-01-11 22:00:53 +02:00
Imran
346c670488 Merge pull request #2061 from ImranR98/dev
- Upgrade to latest Flutter version (fix errors that were preventing this)
- Fix button highlight visibility on black theme (#2039)
2025-01-11 22:00:30 +02:00
Imran Remtulla
2137335e56 Increment version 2025-01-11 22:59:29 +03:00
Imran Remtulla
cea96275b7 Fix button highlight visibility on black theme (#2039) 2025-01-11 22:54:47 +03:00
Imran Remtulla
9954b68332 Upgrade to latest Flutter version (fix Gradle and other errors) 2025-01-11 22:35:40 +03:00
ColorfulRhino
974a822b29 Improve German translation 2025-01-10 12:32:56 +00:00
DwainZwerg
48b89335fa Update de.json
Hopefully more understandable
2025-01-09 10:31:06 +01:00
Kévin
e834630688 Update fr.json
- Correction of some translations (French)
- Line: 94, 97
2025-01-01 03:42:04 +01:00
Kévin
3dd1ef076f Update fr.json
- Correction of some translations (French)
- Line: 28, 32, 63, 81, 102, 316
2025-01-01 03:29:31 +01:00
Mxhdee
e70edae831 Update fa.json 2024-12-29 02:31:39 +01:00
有鲫雪狐
d9b2d18d85 feat: Add Simplified Chinese version of Obtainium badge
- Add an image of the Obtainium badge in Simplified Chinese
- File path: assets/graphics/badge_obtainium_i18n/badge_obtainium_zh-Hans.png
- Font used from Noto Sans CJK
2024-12-22 16:03:52 +08:00
有鲫雪狐
96b260e431 feat(i18n): Add Tencent App Store zh-Hans translations
- Add zh-Hans translations for Tencent App Store(腾讯应用宝) in the multilingual files
- Update the display name for Tencent App Store to use localized translations
2024-12-21 17:46:46 +08:00
Imran
18ccd01186 Merge pull request #2043 from ImranR98/dev
APKPure bugfix, Restore "Telegram App" source (#2025)
2024-12-20 19:13:02 +03:00
Imran Remtulla
c84f51b6ce Update packages, increment version 2024-12-20 19:11:34 +03:00
Imran Remtulla
48958748f6 Minor bugfix 2024-12-20 19:08:41 +03:00
Imran Remtulla
966b1ee6e3 Revert "Removed Telegram App"
This reverts commit 29bb5cc8cd.
2024-12-20 19:00:26 +03:00
Imran Remtulla
7432ee867f APKPure bugfix 2024-12-20 18:58:31 +03:00
Imran
3ebbd2a4a5 Merge pull request #2033 from ImranR98/dev
Bugfix: GitHub fallback option was broken (#2032)
2024-12-12 11:05:30 -05:00
Imran Remtulla
82207a1b3b Increment version 2024-12-12 11:04:46 -05:00
Imran Remtulla
2ec5c7db11 Bugfix: GitHub fallback option was broken (#2032) 2024-12-12 11:04:31 -05:00
Imran
ab949af700 Merge pull request #2031 from ImranR98/dev
Hardcode Flutter version in GitHub action for now (until new Flutter works)
2024-12-12 04:02:41 -05:00
Imran Remtulla
5c9a35c4f0 Hardcode Flutter version in GitHub action for now (until new Flutter works) 2024-12-12 04:01:59 -05:00
Imran
8651f58744 Merge pull request #2030 from ImranR98/dev
- Avoid OS version reconciliation for pseudo-versioned apps (#2023)
- When importing configs via link, don't show dialog twice
- GitHub - do not use filtered asset release dates (#2012)
2024-12-12 03:53:27 -05:00
Imran Remtulla
d93798a8df Increment version 2024-12-12 03:52:10 -05:00
Imran Remtulla
0822f991ff Remove unused function 2024-12-12 03:34:47 -05:00
Imran Remtulla
fde63a0f05 GitHub - do not use filtered asset release dates (#2012) 2024-12-12 03:27:17 -05:00
Imran Remtulla
523e1151b2 When importing configs via link, don't show dialog twice 2024-12-12 02:58:01 -05:00
Imran Remtulla
d5d6825ed9 Avoid OS version reconciliation for pseudo-versioned apps (#2023) 2024-12-12 02:40:04 -05:00
Imran
79c4d3b9fe Merge pull request #2026 from summoner001/main
Update hu.json
2024-12-12 02:21:19 -05:00
Imran Remtulla
d6b99b903f Prevent pseudo-versioning method from changing on load (#2022) 2024-12-12 02:20:56 -05:00
summoner001
335752ee7c Update hu.json
Correcting hungarian translation
2024-12-10 15:55:12 +01:00
Imran
e5afe75213 Merge pull request #2021 from ImranR98/dev
Catch errors when running JSON compat mods - app breaking bug (#2015, #2019)
2024-12-09 17:21:40 -05:00
Imran Remtulla
0df1c1c512 Increment version 2024-12-09 17:21:00 -05:00
Imran Remtulla
bd2ac73b9f Catch errors when running JSON compat mods (#2015, #2019) 2024-12-09 17:18:25 -05:00
Imran Remtulla
26b5a2d976 Catch errors when running JSON compat mods (#2015, #2019) 2024-12-09 17:04:49 -05:00
Imran
c0968e8991 Merge pull request #2008 from ImranR98/dev
- Fix broken "Download Asset" function for HTML source (#1998)
- Add "refresh before download" (#1943)
- Remove WhatsApp, VLC, and Telegram App sources - no longer needed as HTML source sufficient (#1943)
2024-12-08 16:41:24 -05:00
Imran Remtulla
243b1eb2ac Update packages, increment version 2024-12-08 16:39:26 -05:00
Imran Remtulla
c6c61d1c83 Merge remote-tracking branch 'origin/main' into dev 2024-12-08 16:37:08 -05:00
Imran
f207967411 Merge pull request #1995 from ygxbnet/patch-2
Update zh.json
2024-12-08 16:36:56 -05:00
Imran Remtulla
29bb5cc8cd Removed Telegram App 2024-12-08 16:36:46 -05:00
Imran Remtulla
dbbc2ff19c Removed VLC (#1943) 2024-12-08 16:21:36 -05:00
Imran Remtulla
c012b016f9 Add "refresh before download" + remove WhatsApp (#1943) 2024-12-08 15:58:44 -05:00
Imran Remtulla
22815b8209 Minor bug 2024-12-08 14:53:31 -05:00
Imran Remtulla
619d4f1a51 Fix broken "Download Asset" function for HTML source (#1998) 2024-12-08 13:47:32 -05:00
YGXB_net
50e8929763 Update zh.json 2024-11-30 21:49:58 +08:00
69 changed files with 1587 additions and 811 deletions

View File

@@ -15,6 +15,8 @@ jobs:
- uses: actions/checkout@v3
- uses: subosito/flutter-action@v2
with:
channel: stable
- uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options

3
.gitignore vendored
View File

@@ -5,9 +5,11 @@
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/
.vscode/
@@ -43,6 +45,7 @@ app.*.map.json
/android/app/debug
/android/app/profile
/android/app/release
/android/app/.cxx
# Custom
TODO.txt

View File

@@ -1,11 +1,11 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled.
# This file should be version controlled and should not be manually edited.
version:
revision: 543dac2f35de563fcb6905e9146bdce712c44000
channel: master
revision: "17025dd88227cd9532c33fa78f5250d548d87e9a"
channel: "stable"
project_type: app
@@ -13,14 +13,26 @@ project_type: app
migration:
platforms:
- platform: root
create_revision: 543dac2f35de563fcb6905e9146bdce712c44000
base_revision: 543dac2f35de563fcb6905e9146bdce712c44000
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
- platform: android
create_revision: 543dac2f35de563fcb6905e9146bdce712c44000
base_revision: 543dac2f35de563fcb6905e9146bdce712c44000
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
- platform: ios
create_revision: 543dac2f35de563fcb6905e9146bdce712c44000
base_revision: 543dac2f35de563fcb6905e9146bdce712c44000
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
- platform: linux
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
- platform: macos
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
- platform: web
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
- platform: windows
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
# User provided section

View File

@@ -29,14 +29,12 @@ Currently supported App sources:
- [Uptodown](https://uptodown.com/)
- [Huawei AppGallery](https://appgallery.huawei.com/)
- [Tencent App Store](https://sj.qq.com/)
- [RuStore](https://rustore.ru/)
- Jenkins Jobs
- [APKMirror](https://apkmirror.com/) (Track-Only)
- Open Source - App-Specific:
- [VLC](https://videolan.org/)
- Other - App-Specific:
- [WhatsApp](https://whatsapp.com)
- [Telegram App](https://telegram.org)
- [Neutron Code](https://neutroncode.com)
- [Telegram App](https://telegram.org/)
- [Neutron Code](https://neutroncode.com/)
- Direct APK Link
- "HTML" (Fallback): Any other URL that returns an HTML page with links to APK files

View File

@@ -13,8 +13,7 @@ linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html.
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code

2
android/.gitignore vendored
View File

@@ -7,7 +7,7 @@ gradle-wrapper.jar
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
# See https://flutter.dev/to/reference-keystore
key.properties
**/*.keystore
**/*.jks

View File

@@ -1,6 +1,7 @@
plugins {
id "com.android.application"
id "kotlin-android"
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id "dev.flutter.flutter-gradle-plugin"
}
@@ -29,33 +30,30 @@ if (keystorePropertiesFile.exists()) {
}
android {
namespace "dev.imranr.obtainium"
compileSdk flutter.compileSdkVersion
ndkVersion flutter.ndkVersion
namespace = "dev.imranr.obtainium"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
jvmTarget = JavaVersion.VERSION_1_8
}
defaultConfig {
applicationId "dev.imranr.obtainium"
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "dev.imranr.obtainium"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
minSdkVersion 24
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = 24
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
flavorDimensions "flavor"
productFlavors {
@@ -77,6 +75,7 @@ android {
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
@@ -89,11 +88,7 @@ android {
}
flutter {
source '../..'
}
repositories {
maven { url 'https://jitpack.io' }
source = "../.."
}
ext.abiCodes = ["x86_64": 1, "armeabi-v7a": 2, "arm64-v8a": 3]

View File

@@ -12,6 +12,7 @@
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
@@ -21,12 +22,12 @@
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action
@@ -39,7 +40,6 @@
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="obtainium" />
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
@@ -71,6 +71,17 @@
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />\
android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>

View File

@@ -9,12 +9,12 @@ allprojects {
}
}
rootProject.buildDir = '../build'
rootProject.buildDir = "../build"
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
project.evaluationDependsOn(":app")
}
tasks.register("clean", Delete) {

View File

@@ -1,3 +1,3 @@
org.gradle.jvmargs=-Xmx2048M
org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true

View File

@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip

View File

@@ -18,8 +18,8 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.4.2" apply false
id "org.jetbrains.kotlin.android" version "1.8.10" apply false
id "com.android.application" version "8.1.0" apply false
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
}
include ":app"

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

After

Width:  |  Height:  |  Size: 346 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 238 KiB

After

Width:  |  Height:  |  Size: 354 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 KiB

After

Width:  |  Height:  |  Size: 264 KiB

View File

@@ -255,7 +255,7 @@
"intermediateLinkNotFound": "Intermediate veza nije nađena",
"intermediateLink": "Intermediate veza",
"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 Wi-Fi-ju",
"bgUpdatesWhileChargingOnly": "Disable background updates when not charging",
"autoSelectHighestVersionCode": "Automatski izaberite najveću (verziju) versionCode APK-a",
"versionExtractionRegEx": "RegEx ekstrakcija verzije",
@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
"allowInsecure": "Allow insecure HTTP requests",
"stayOneVersionBehind": "Stay one version behind latest",
"refreshBeforeDownload": "Refresh app details before download",
"tencentAppStore": "Tencent App Store",
"name": "Name",
"smartname": "Name (Smart)",
"sortMethod": "Sort Method",
"removeAppQuestion": {
"one": "Želite li ukloniti aplikaciju?",
"other": "Želite li ukloniti aplikacije?"

View File

@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "Konfigurace aplikací s využitím crowdsourcingu",
"allowInsecure": "Povolení nezabezpečených požadavků HTTP",
"stayOneVersionBehind": "Zůstaňte o jednu verzi pozadu za nejnovější",
"refreshBeforeDownload": "Obnovení údajů o aplikaci před stažením",
"tencentAppStore": "Tencent App Store",
"name": "Název",
"smartname": "Název (Smart)",
"sortMethod": "Metoda třídění",
"removeAppQuestion": {
"one": "Odstranit Apku?",
"other": "Odstranit Apky?"

View File

@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "Crowdsourcede app-konfigurationer",
"allowInsecure": "Tillad usikre HTTP-anmodninger",
"stayOneVersionBehind": "Forbliv én version bagud den seneste",
"refreshBeforeDownload": "Opdater app-detaljer før download",
"tencentAppStore": "Tencent App Store",
"name": "Navn",
"smartname": "Navn (Smart)",
"sortMethod": "Sorteringsmetode",
"removeAppQuestion": {
"one": "Fjern app?",
"other": "Fjern apps?"

View File

@@ -32,8 +32,8 @@
"source": "Quelle",
"app": "App",
"appsFromSourceAreTrackOnly": "Apps aus dieser Quelle sind nur zur Nachverfolgung.",
"youPickedTrackOnly": "Sie haben die Option „Nur nachverfolgen“ gewählt.",
"trackOnlyAppDescription": "Die App wird auf Aktualisierungen überwacht, aber Obtainium wird sie nicht herunterladen oder installieren.",
"youPickedTrackOnly": "Du hast die Option „Nur nachverfolgen“ gewählt.",
"trackOnlyAppDescription": "Die App wird auf neue verfügbare Versionen überwacht, aber Obtainium wird sie nicht herunterladen oder installieren.",
"cancelled": "Abgebrochen",
"appAlreadyAdded": "App bereits hinzugefügt",
"alreadyUpToDateQuestion": "App bereits auf dem neuesten Stand?",
@@ -85,8 +85,8 @@
"filter": "Filter",
"filterApps": "Apps filtern",
"appName": "App-Name",
"author": "Autor",
"upToDateApps": "Apps mit aktueller Version",
"author": "Herausgebende",
"upToDateApps": "Apps mit aktuellster Version",
"nonInstalledApps": "Nicht installierte Apps",
"importExport": "Import/Export",
"settings": "Einstellungen",
@@ -102,22 +102,22 @@
"searchX": "{} suchen",
"noResults": "Keine Ergebnisse gefunden",
"importX": "{} importieren",
"importedAppsIdDisclaimer": "Importierte Apps werden manchmal fälschlicherweise als „Nicht installiert“ angezeigt. Um dies zu beheben, installieren Sie sie erneut über Obtainium. Dies hat keine Auswirkungen auf App-Daten. Es betrifft nur URL- und Drittanbieter-Importmethoden.",
"importedAppsIdDisclaimer": "Importierte Apps werden manchmal fälschlicherweise als „Nicht installiert“ angezeigt. Um dies zu beheben, installiere sie erneut über Obtainium. Dies hat keine Auswirkungen auf App-Daten. Es betrifft nur URL- und Drittanbieter-Importmethoden.",
"importErrors": "Importfehler",
"importedXOfYApps": "{} von {} Apps importiert.",
"followingURLsHadErrors": "Bei folgenden URLs traten Fehler auf:",
"selectURL": "URL auswählen",
"selectURLs": "URLs auswählen",
"pick": "Auswählen",
"theme": "Theme",
"theme": "Design",
"dark": "Dunkel",
"light": "Hell",
"followSystem": "System folgen",
"followSystemThemeExplanation": "Das Folgen des Systemthemes ist unter Android < 10 nur mit Hilfe von Drittanbieterapps möglich",
"followSystem": "Systemstandard",
"followSystemThemeExplanation": "Das Abrufen des Systemdesigns ist unter Android < 10 nur mit Hilfe von Drittanbieterapps möglich",
"useBlackTheme": "Rein schwarzen Hintergrund verwenden",
"appSortBy": "App sortieren nach",
"authorName": "Autor/Name",
"nameAuthor": "Name/Autor",
"authorName": "Hrsg./Name",
"nameAuthor": "Name/Hrsg.",
"asAdded": "Wie hinzugefügt",
"appSortOrder": "App sortieren nach",
"ascending": "Aufsteigend",
@@ -138,30 +138,30 @@
"obtainiumExportHyphenatedLowercase": "Obtainium-Export",
"pickAnAPK": "APK auswählen",
"appHasMoreThanOnePackage": "{} verfügt über mehr als ein Paket:",
"deviceSupportsXArch": "Ihr Gerät unterstützt die CPU-Architektur {}.",
"deviceSupportsFollowingArchs": "Ihr Gerät unterstützt die folgenden CPU-Architekturen:",
"deviceSupportsXArch": "Dein Gerät unterstützt die CPU-Architektur {}.",
"deviceSupportsFollowingArchs": "Dein Gerät unterstützt die folgenden CPU-Architekturen:",
"warning": "Warnung",
"sourceIsXButPackageFromYPrompt": "Die App-Quelle ist '{}', aber das Release-Paket stammt von '{}'. Fortfahren?",
"updatesAvailable": "Aktualisierungen verfügbar",
"updatesAvailableNotifDescription": "Benachrichtigt den Nutzer, dass Aktualisierungen für eine oder mehrere von Obtainium verfolgte Apps verfügbar sind",
"updatesAvailableNotifDescription": "Benachrichtigt, wenn Aktualisierungen für eine oder mehrere von Obtainium verfolgte Apps verfügbar sind",
"noNewUpdates": "Keine neuen Aktualisierungen.",
"xHasAnUpdate": "{} hat eine Aktualisierung.",
"appsUpdated": "App wurde aktualisiert",
"appsNotUpdated": "Aktualisierung der Apps fehlgeschlagen",
"appsUpdatedNotifDescription": "Benachrichtigt den Benutzer, dass Aktualisierungen für eine oder mehrere Apps im Hintergrund durchgeführt wurden",
"appsUpdatedNotifDescription": "Benachrichtigt, wenn Aktualisierungen für eine oder mehrere Apps im Hintergrund durchgeführt wurden",
"xWasUpdatedToY": "{} wurde auf {} aktualisiert.",
"xWasNotUpdatedToY": "Die Aktualisierung von {} auf {} ist fehlgeschlagen.",
"errorCheckingUpdates": "Fehler beim Prüfen auf Aktualisierungen",
"errorCheckingUpdatesNotifDescription": "Eine Benachrichtigung, die angezeigt wird, wenn die Prüfung der Hintergrundaktualisierung fehlschlägt",
"errorCheckingUpdatesNotifDescription": "Benachrichtigt, wenn die Prüfung der Hintergrundaktualisierung fehlgeschlagen ist",
"appsRemoved": "Apps entfernt",
"appsRemovedNotifDescription": "Benachrichtigt den Benutzer, dass eine oder mehrere Apps aufgrund von Fehlern beim Laden entfernt wurden",
"appsRemovedNotifDescription": "Benachrichtigt, wenn eine oder mehrere Apps aufgrund von Fehlern beim Laden entfernt wurden",
"xWasRemovedDueToErrorY": "{} wurde aufgrund des folgenden Fehlers entfernt: {}",
"completeAppInstallation": "App-Installation abschließen",
"obtainiumMustBeOpenToInstallApps": "Obtainium muss geöffnet sein, um Apps zu installieren",
"completeAppInstallationNotifDescription": "Aufforderung an den Benutzer, zu Obtainium zurückzukehren, um die Installation einer App abzuschließen",
"completeAppInstallationNotifDescription": "Aufforderung zu Obtainium zurückzukehren, um die Installation einer App abzuschließen",
"checkingForUpdates": "Nach Aktualisierungen suchen",
"checkingForUpdatesNotifDescription": "Vorübergehende Benachrichtigung, die bei der Suche nach Aktualisierungen angezeigt wird",
"pleaseAllowInstallPerm": "Bitte erlauben Sie Obtainium die Installation von Apps",
"pleaseAllowInstallPerm": "Bitte erlaube Obtainium die Installation von Apps",
"trackOnly": "Nur nachverfolgen",
"errorWithHttpStatusCode": "Fehler {}",
"versionCorrectionDisabled": "Versionskorrektur deaktiviert (Plugin scheint nicht zu funktionieren)",
@@ -190,7 +190,7 @@
"downloadX": "{} herunterladen",
"downloadedX": "{} heruntergeladen",
"releaseAsset": "Release-Asset",
"downloadNotifDescription": "Benachrichtigt den Nutzer über den Fortschritt beim Herunterladen einer App",
"downloadNotifDescription": "Zeigt den Fortschritt beim Herunterladen einer App",
"noAPKFound": "Keine APK gefunden",
"noVersionDetection": "Keine Versionserkennung",
"categorize": "Kategorisieren",
@@ -223,7 +223,7 @@
"autoApkFilterByArch": "Nach Möglichkeit versuchen, APKs nach CPU-Architektur zu filtern",
"overrideSource": "Quelle überschreiben",
"dontShowAgain": "Nicht noch einmal anzeigen",
"dontShowTrackOnlyWarnings": "Warnung für 'Nur nachverfolgen' nicht anzeigen",
"dontShowTrackOnlyWarnings": "Warnung für Nur nachverfolgen nicht anzeigen",
"dontShowAPKOriginWarnings": "Warnung für APK-Herkunft nicht anzeigen",
"moveNonInstalledAppsToBottom": "Nicht installierte Apps ans Ende der App-Ansicht verschieben",
"gitlabPATLabel": "Persönlicher Zugangstoken für GitLab",
@@ -231,7 +231,7 @@
"requiresCredentialsInSettings": "{}: Benötigt zusätzliche Anmeldedaten (in den Einstellungen)",
"checkOnStart": "Einmalig beim Start überprüfen",
"tryInferAppIdFromCode": "Versuchen, die App-ID aus dem Quellcode zu ermitteln",
"removeOnExternalUninstall": "Automatisches Entfernen von extern deinstallierten Apps",
"removeOnExternalUninstall": "Extern deinstallierte Apps automatische entfernen",
"pickHighestVersionCode": "Automatische Auswahl des APK mit höchstem Versionscode",
"checkUpdateOnDetailPage": "Nach Aktualisierungen suchen, wenn eine App-Detailseite geöffnet wird",
"disablePageTransitions": "Animationen für Seitenübergänge deaktivieren",
@@ -241,26 +241,26 @@
"addInfoInSettings": "Diese Information in den Einstellungen hinzufügen.",
"githubSourceNote": "Die GitHub-Ratenbegrenzung kann mit einem API-Schlüssel umgangen werden.",
"sortByLastLinkSegment": "Nur nach dem letzten Teil des Links sortieren",
"filterReleaseNotesByRegEx": "Versionshinweise nach regulärem Ausdruck filtern",
"filterReleaseNotesByRegEx": "Versionshinweise nach regulärem Ausdruck\nfiltern",
"customLinkFilterRegex": "Benutzerdefinierter APK-Linkfilter durch regulären Ausdruck (Standard '.apk$')",
"appsPossiblyUpdated": "App-Aktualisierungen wurden versucht",
"appsPossiblyUpdatedNotifDescription": "Benachrichtigt den Benutzer, dass Aktualisierungen für eine oder mehrere Apps möglicherweise im Hintergrund durchgeführt wurden",
"xWasPossiblyUpdatedToY": "{} wurde möglicherweise aktualisiert auf {}.",
"appsPossiblyUpdatedNotifDescription": "Benachrichtigt, dass möglicherweise eine oder mehrere Apps im Hintergrund aktualisiert wurden",
"xWasPossiblyUpdatedToY": "{} wurde eventuell auf Version {} aktualisiert.",
"enableBackgroundUpdates": "Hintergrundaktualisierungen aktivieren",
"backgroundUpdateReqsExplanation": "Die Hintergrundaktualisierung ist möglicherweise nicht für alle Apps möglich.",
"backgroundUpdateReqsExplanation": "Die Hintergrundaktualisierung ist unter Umständen nicht für alle Apps möglich.",
"backgroundUpdateLimitsExplanation": "Der Erfolg einer Hintergrundinstallation kann nur festgestellt werden, wenn Obtainium geöffnet wird.",
"verifyLatestTag": "„Latest“-Tag überprüfen",
"intermediateLinkRegex": "Filter für einen „Zwischen“-Link, der zuerst besucht werden soll",
"filterByLinkText": "Links durch Linktext filtern",
"intermediateLinkNotFound": "„Zwischen“-Link nicht gefunden",
"intermediateLink": "„Zwischen“-Link",
"exemptFromBackgroundUpdates": "Ausschluss von Hintergrundaktualisierungen (falls aktiviert)",
"bgUpdatesOnWiFiOnly": "Hintergrundaktualisierungen deaktivieren, wenn kein WLAN vorhanden ist",
"bgUpdatesWhileChargingOnly": "Hintergrundaktualisierungen deaktivieren, wenn nicht geladen wird",
"exemptFromBackgroundUpdates": "Von Hintergrundaktualisierungen (falls aktiviert) ausschließen",
"bgUpdatesOnWiFiOnly": "Hintergrundaktualisierungen nur im WLAN ausführen",
"bgUpdatesWhileChargingOnly": "Hintergrundaktualisierungen nur ausführen, während das Gerät geladen wird",
"autoSelectHighestVersionCode": "Automatisch höchste APK-Version auswählen",
"versionExtractionRegEx": "Versionsextraktion per RegEx",
"trimVersionString": "Versionszeichenfolge mit RegEx kürzen",
"matchGroupToUseForX": "Zu verwendende Abgleichsgruppe für „{}“",
"matchGroupToUseForX": "Zu verwendende Abgleichsgruppe für\n„{}“",
"matchGroupToUse": "Zu verwendende Gruppe abgleichen",
"highlightTouchTargets": "Weniger offensichtliche Touch-Ziele hervorheben",
"pickExportDir": "Export-Verzeichnis wählen",
@@ -268,7 +268,7 @@
"includeSettings": "Einstellungen einbeziehen",
"filterVersionsByRegEx": "Versionen nach regulären Ausdrücken filtern",
"trySelectingSuggestedVersionCode": "Versuchen, den vorgeschlagenen APK-Versionscode auszuwählen",
"dontSortReleasesList": "Freigaberelease von der API ordern",
"dontSortReleasesList": "Releases-Sortierung der API beibehalten",
"reverseSort": "Umgekehrtes Sortieren",
"takeFirstLink": "Ersten Link verwenden",
"skipSort": "Sortieren überspringen",
@@ -292,12 +292,12 @@
"parallelDownloads": "Parallele Downloads erlauben",
"useShizuku": "Shizuku oder Sui zur Installation verwenden",
"shizukuBinderNotFound": "Kompatibler Shizuku-Dienst wurde nicht gefunden",
"shizukuOld": "Alte Shizuku-Version (< 11) - aktualisieren Sie sie",
"shizukuOldAndroidWithADB": "Shizuku läuft auf Android < 8.1 mit ADB - aktualisieren Sie Android oder verwenden Sie stattdessen Sui",
"shizukuPretendToBeGooglePlay": "Google Play als Installationsquelle festlegen (wenn Shizuku verwendet wird)",
"shizukuOld": "Veraltete Shizuku-Version (< 11) - bitte aktualisiere sie",
"shizukuOldAndroidWithADB": "Shizuku läuft auf Android < 8.1 mit ADB - aktualisiere die Android-Version oder verwende stattdessen Sui",
"shizukuPretendToBeGooglePlay": "(Mittels Shizuku) Google Play als Installationsquelle registrieren",
"useSystemFont": "Systemschriftart verwenden",
"useVersionCodeAsOSVersion": "App-Version als erkannte Version vom Betriebssystem verwenden",
"requestHeader": "Kopfzeile anfordern",
"useVersionCodeAsOSVersion": "Versionscode (versionCode) als erkannte Version vom Betriebssystem verwenden",
"requestHeader": "Kopfzeile („Header“) anfordern",
"useLatestAssetDateAsReleaseDate": "Letzten Asset-Upload als Veröffentlichungsdatum verwenden",
"defaultPseudoVersioningMethod": "Standardmäßiges Verfahren zur Pseudo-Versionierung",
"partialAPKHash": "Partieller APK-Hash",
@@ -309,29 +309,34 @@
"invertRegEx": "Regulären Ausdruck invertieren",
"note": "Hinweis",
"selfHostedNote": "Das „{}“-Drop-down-Menü kann verwendet werden, um selbst gehostete/angepasste Instanzen einer beliebigen Quelle zu erreichen.",
"badDownload": "Die APK konnte nicht geparst werden (inkompatibler oder teilweiser Download)",
"badDownload": "Die APK konnte nicht gelesen werden (inkompatibler oder unfertiger Download)",
"beforeNewInstallsShareToAppVerifier": "Neue Apps mit AppVerifier teilen (falls verfügbar)",
"appVerifierInstructionToast": "Geben Sie die Daten an AppVerifier weiter und kehren Sie dann hierher zurück, wenn Sie fertig sind.",
"appVerifierInstructionToast": "Teile die Daten mit AppVerifier und kehre im Anschluss hierher zurück.",
"wiki": "Hilfe/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App-Konfigurationen (Verwendung auf eigene Gefahr)",
"crowdsourcedConfigsShort": "Crowdsourced App-Konfigurationen",
"allowInsecure": "Unsichere HTTP-Anfragen zulassen",
"stayOneVersionBehind": "Eine Version hinter der neuesten Version bleiben",
"refreshBeforeDownload": "App-Details vor dem Download aktualisieren",
"tencentAppStore": "Tencent App Store",
"name": "Name",
"smartname": "Name (Smart)",
"sortMethod": "Sortierverfahren",
"removeAppQuestion": {
"one": "App entfernen?",
"other": "Apps entfernen?"
},
"tooManyRequestsTryAgainInMinutes": {
"one": "Zu viele Anfragen (Rate begrenzt) versuchen Sie es in {} Minute erneut",
"other": "Zu viele Anfragen (Rate begrenzt) versuchen Sie es in {} Minuten erneut"
"one": "Zu viele Anfragen (Rate begrenzt) versuche es in {} Minute erneut",
"other": "Zu viele Anfragen (Rate begrenzt) versuche es in {} Minuten erneut"
},
"bgUpdateGotErrorRetryInMinutes": {
"one": "Bei der Aktualisierungsprüfung im Hintergrund wurde ein {} festgestellt, eine erneute Prüfung wird in {} Minute geplant",
"other": "Bei der Aktualisierungsprüfung im Hintergrund wurde ein {} festgestellt, eine erneute Prüfung wird in {} Minuten geplant"
},
"bgCheckFoundUpdatesWillNotifyIfNeeded": {
"one": "Die Hintergrundaktualisierungsprüfung fand {} Aktualisierung benachrichtigt den Benutzer, falls erforderlich",
"other": "Die Hintergrundaktualisierungsprüfung fand {} Aktualisierungen benachrichtigt den Benutzer, falls erforderlich"
"one": "Die Aktualisierungsprüfung fand {} Aktualisierung benachrichtigt, falls erforderlich",
"other": "Die Aktualisierungsprüfung fand {} Aktualisierungen benachrichtigt, falls erforderlich"
},
"apps": {
"one": "{} App",
@@ -358,8 +363,8 @@
"other": "{n} Logs gelöscht (vorher = {before}, nachher = {after})"
},
"xAndNMoreUpdatesAvailable": {
"one": "{} und 1 weitere App haben Aktualisierungen.",
"other": "{} und {} weitere Apps haben Aktualisierungen."
"one": "{} und 1 weitere App können aktualisiert werden.",
"other": "{} und {} weitere Apps können aktualisiert werden."
},
"xAndNMoreUpdatesInstalled": {
"one": "{} und 1 weitere App wurden aktualisiert.",

View File

@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
"allowInsecure": "Allow insecure HTTP requests",
"stayOneVersionBehind": "Stay one version behind latest",
"refreshBeforeDownload": "Refresh app details before download",
"tencentAppStore": "Tencent App Store",
"name": "Name",
"smartname": "Name (Smart)",
"sortMethod": "Sort Method",
"removeAppQuestion": {
"one": "Forigi la aplikaĵon?",
"other": "Forigi la aplikaĵojn?"

View File

@@ -255,7 +255,7 @@
"intermediateLinkNotFound": "Intermediate link not found",
"intermediateLink": "Intermediate link",
"exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)",
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
"bgUpdatesOnWiFiOnly": "Disable background updates when not on Wi-Fi",
"bgUpdatesWhileChargingOnly": "Disable background updates when not charging",
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
"versionExtractionRegEx": "Version String Extraction RegEx",
@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
"allowInsecure": "Allow insecure HTTP requests",
"stayOneVersionBehind": "Stay one version behind latest",
"refreshBeforeDownload": "Refresh app details before download",
"tencentAppStore": "Tencent App Store",
"name": "Name",
"smartname": "Name (Smart)",
"sortMethod": "Sort Method",
"removeAppQuestion": {
"one": "Remove App?",
"other": "Remove Apps?"

View File

@@ -255,7 +255,7 @@
"intermediateLinkNotFound": "Enlace intermedio no encontrado",
"intermediateLink": "Enlace intermedio",
"exemptFromBackgroundUpdates": "Exenta de actualizciones en segundo plano (si están habilitadas)",
"bgUpdatesOnWiFiOnly": "Deshabilitar las actualizaciones en segundo plano sin WiFi",
"bgUpdatesOnWiFiOnly": "Deshabilitar las actualizaciones en segundo plano sin Wi-Fi",
"bgUpdatesWhileChargingOnly": "Desactiva las actualizaciones en segundo plano cuando no estés cargando",
"autoSelectHighestVersionCode": "Auto selección del paquete APK con versión más reciente",
"versionExtractionRegEx": "Versión de extracción RegEx",
@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "Configuración de aplicaciones por crowdsourcing",
"allowInsecure": "Permitir peticiones HTTP inseguras",
"stayOneVersionBehind": "Mantenerse una versión por detrás de la última",
"refreshBeforeDownload": "Actualiza los datos de la aplicación antes de descargarla",
"tencentAppStore": "Tencent App Store",
"name": "Nombre",
"smartname": "Nombre (Smart)",
"sortMethod": "Método de clasificación",
"removeAppQuestion": {
"one": "¿Eliminar aplicación?",
"other": "¿Eliminar aplicaciones?"

View File

@@ -211,7 +211,7 @@
"uninstallFromDevice": "حذف نصب از دستگاه",
"onlyWorksWithNonVersionDetectApps": "فقط برای برنامه‌هایی کار می‌کند که تشخیص نسخه غیرفعال است.",
"releaseDateAsVersion": "از تاریخ انتشار به عنوان نسخه استفاده کنید",
"releaseTitleAsVersion": "Use release title as version string",
"releaseTitleAsVersion": "از عنوان انتشار به عنوان رشته نسخه استفاده کنید",
"releaseDateAsVersionExplanation": "این گزینه فقط باید برای برنامه هایی استفاده شود که تشخیص نسخه به درستی کار نمی کند، اما تاریخ انتشار در دسترس است.",
"changes": "تغییرات",
"releaseDate": "تاریخ انتشار",
@@ -255,8 +255,8 @@
"intermediateLinkNotFound": "لینک میانی پیدا نشد",
"intermediateLink": "پیوند میانی",
"exemptFromBackgroundUpdates": "معاف از به‌روزرسانی‌های پس‌زمینه (در صورت فعال بودن)",
"bgUpdatesOnWiFiOnly": "به‌روزرسانی‌های پس‌زمینه را در صورت عدم اتصال به WiFi غیرفعال کنید",
"bgUpdatesWhileChargingOnly": "Disable background updates when not charging",
"bgUpdatesOnWiFiOnly": "به‌روزرسانی‌های پس‌زمینه را در صورت عدم اتصال به Wi-Fi غیرفعال کنید",
"bgUpdatesWhileChargingOnly": "به‌روزرسانی‌های پس‌زمینه را هنگام شارژ نشدن غیرفعال کنید",
"autoSelectHighestVersionCode": "انتخاب خودکار بالاترین نسخه کد APK",
"versionExtractionRegEx": "نسخه استخراج RegEx",
"trimVersionString": "برش رشته نسخه با RegEx",
@@ -313,10 +313,15 @@
"beforeNewInstallsShareToAppVerifier": "اشتراک‌گذاری برنامه‌های جدید با AppVerifier (در صورت وجود)",
"appVerifierInstructionToast": "در AppVerifier به اشتراک بگذارید، سپس پس از آماده شدن به اینجا برگردید.",
"wiki": "راهنما/ویکی",
"crowdsourcedConfigsLabel": "تنظیمات برنامه Crowdsourced (با مسئولیت خود استفاده کنید)",
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
"crowdsourcedConfigsLabel": "تنظیمات برنامه های مشارکت جمعی (با مسئولیت خود استفاده کنید)",
"crowdsourcedConfigsShort": "تنظیمات برنامه های مشارکت جمعی",
"allowInsecure": "درخواست های HTTP ناامن را مجاز کنید",
"stayOneVersionBehind": "Stay one version behind latest",
"stayOneVersionBehind": "یک نسخه از آخرین نسخه پشت سر بگذارید",
"refreshBeforeDownload": "قبل از دانلود، جزئیات برنامه را بازخوانی کنید",
"tencentAppStore": "Tencent App Store",
"name": "Name",
"smartname": "Name (Smart)",
"sortMethod": "Sort Method",
"removeAppQuestion": {
"one": "برنامه حذف شود؟",
"other": "برنامه ها حذف شوند؟"

View File

@@ -9,11 +9,11 @@
"placeholder": "Espace réservé",
"someErrors": "Des erreurs sont survenues",
"unexpectedError": "Erreur inattendue",
"ok": "Ok",
"ok": "OK",
"and": "et",
"githubPATLabel": "Jeton d'accès personnel GitHub (augmente la limite de débit)",
"includePrereleases": "Inclure les versions préliminaires",
"fallbackToOlderReleases": "Retour aux anciennes versions",
"fallbackToOlderReleases": "Revenir aux anciennes versions",
"filterReleaseTitlesByRegEx": "Filtrer les titres de version par expression régulière",
"invalidRegEx": "Expression régulière invalide",
"noDescription": "Aucune description",
@@ -25,18 +25,18 @@
"standard": "Standard",
"custom": "Personnalisé",
"useMaterialYou": "Utiliser Material You",
"githubStarredRepos": "Dépôts étoilés GitHub",
"githubStarredRepos": "dépôts étoilés GitHub",
"uname": "Nom d'utilisateur",
"wrongArgNum": "Nombre incorrect des arguments fournis",
"xIsTrackOnly": "{} en Suivi uniquement",
"source": "Source",
"app": "Application",
"source": "source",
"app": "Appli",
"appsFromSourceAreTrackOnly": "Les applications de cette source sont en '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.",
"cancelled": "Annulé",
"appAlreadyAdded": "Application déjà ajoutée",
"alreadyUpToDateQuestion": "L'application est à jour?",
"alreadyUpToDateQuestion": "L'application est déjà à jour?",
"addApp": "Ajouter appli",
"appSourceURL": "URL source de l'application",
"error": "Erreur",
@@ -47,30 +47,30 @@
"supportedSources": "Sources prises en charge",
"trackOnlyInBrackets": "(Suivi uniquement)",
"searchableInBrackets": "(Interrogeable)",
"appsString": "Applications",
"appsString": "Applis",
"noApps": "Aucune application",
"noAppsForFilter": "Aucune application à filtrer",
"noAppsForFilter": "Aucune application correspondant au filtre",
"byX": "Par {}",
"percentProgress": "Progression : {}%",
"pleaseWait": "Veuillez patienter",
"updateAvailable": "Mise à jour disponible",
"notInstalled": "Non installé",
"notInstalled": "Non installée",
"pseudoVersion": "Version fictive",
"selectAll": "Tout sélectionner",
"deselectX": "Déselectionner {}",
"deselectX": "Désélectionner {}",
"xWillBeRemovedButRemainInstalled": "{} sera supprimée d'Obtainium mais restera installée sur l'appareil.",
"removeSelectedAppsQuestion": "Supprimer les applications sélectionnées ?",
"removeSelectedApps": "Les applications sélectionnées ont été supprimées",
"removeSelectedApps": "Supprimer les applications sélectionnées",
"updateX": "Mettre à jour {}",
"installX": "Installer {}",
"markXTrackOnlyAsUpdated": "Marquer {}\n(Suivi uniquement)\ncomme étant à jour",
"changeX": "Changer {}",
"changeX": "Modifier {}",
"installUpdateApps": "Installer/Mettre à jour les applications",
"installUpdateSelectedApps": "Installer/Mettre à jour les applications sélectionnées",
"markXSelectedAppsAsUpdated": "Marquer les {} applications sélectionnées comme étant à jour ?",
"no": "Non",
"yes": "Oui",
"markSelectedAppsUpdated": "Marquer les application sélectionnées comme étant à jour",
"markSelectedAppsUpdated": "Marquer les applications sélectionnées comme étant à jour",
"pinToTop": "Épingler en haut",
"unpinFromTop": "Désépingler du haut",
"resetInstallStatusForSelectedAppsQuestion": "Réinitialiser l'état d'installation des applications sélectionnées ?",
@@ -78,7 +78,7 @@
"customLinkMessage": "Ces liens fonctionnent sur les appareils sur lesquels Obtainium est installé",
"shareAppConfigLinks": "Partager la configuration de l'application sous forme de lien HTML",
"shareSelectedAppURLs": "Partager les URL des applications sélectionnées",
"resetInstallStatus": "L'état d'installation des applications a été réinitialisé",
"resetInstallStatus": "Réinitialiser l'état d'installation des applications",
"more": "Plus",
"removeOutdatedFilter": "Supprimer le filtre des applications obsolètes",
"showOutdatedOnly": "Afficher uniquement les applications obsolètes",
@@ -88,33 +88,33 @@
"author": "Auteur",
"upToDateApps": "Applications à jour",
"nonInstalledApps": "Applications non installées",
"importExport": "Importer/exporter",
"importExport": "Import/Export",
"settings": "Paramètres",
"exportedTo": "Exporté vers {}",
"obtainiumExport": "Exporter Obtainium",
"obtainiumExport": "Exporter la configuration d'Obtainium",
"invalidInput": "Entrée invalide",
"importedX": "Importé {}",
"obtainiumImport": "Importer sur Obtainium",
"obtainiumImport": "Importer la configuration sur Obtainium",
"importFromURLList": "Importer depuis une liste d'URL",
"searchQuery": "Requête de recherche",
"appURLList": "Liste d'URL de l'application",
"appURLList": "Liste d'URL des applications",
"line": "Ligne",
"searchX": "Rechercher {}",
"noResults": "Aucun résultat",
"importX": "Importation de {}",
"importedAppsIdDisclaimer": "Les applications importées peuvent s'afficher de manière incorrecte comme étant \"Non installées\".\nPour résoudre ce problème, réinstallez-les via Obtainium.\nCela n'affectera pas les données des applications.\n\nN'affecte que les méthodes d'importation d'URL et par des tiers.",
"importedAppsIdDisclaimer": "Les applications importées peuvent s'afficher de manière incorrecte comme étant \"Non installées\".\nPour résoudre ce problème, réinstallez-les via Obtainium.\nCela n'affectera pas les données des applications.\n\nCela n'affecte que les méthodes d'importation d'URL et par des tiers.",
"importErrors": "Erreurs lors de l'importation",
"importedXOfYApps": "{} applications sur {} ont été importés.",
"followingURLsHadErrors": "Les URL suivants comportent des erreurs :",
"importedXOfYApps": "{} applications sur {} ont été importées.",
"followingURLsHadErrors": "Les URL suivantes comportent des erreurs :",
"selectURL": "Sélectionner l'URL",
"selectURLs": "Sélectionner les URL",
"pick": "Choisir",
"theme": "Thème",
"dark": "Sombre",
"light": "Clair",
"followSystem": "Correspondre au système",
"followSystemThemeExplanation": "Correspondre au thème du système est possible en utilisant des applications tierces.",
"useBlackTheme": "Utiliser un thème Noir",
"followSystem": "Suivre le système",
"followSystemThemeExplanation": "Suivre le thème du système est possible en utilisant des applications tierces.",
"useBlackTheme": "Utiliser un thème noir",
"appSortBy": "Trier les applications par",
"authorName": "Auteur/Nom",
"nameAuthor": "Nom/Auteur",
@@ -136,10 +136,10 @@
"share": "Partager",
"appNotFound": "Application introuvable",
"obtainiumExportHyphenatedLowercase": "export-obtainium",
"pickAnAPK": "Selectionner un APK",
"appHasMoreThanOnePackage": "{} a plus d'un paquet:",
"pickAnAPK": "Sélectionner un APK",
"appHasMoreThanOnePackage": "{} a plus d'un paquet :",
"deviceSupportsXArch": "Votre appareil prend en charge l'architecture CPU {}.",
"deviceSupportsFollowingArchs": "Votre appareil prend en charge les architectures CPU suivants: ",
"deviceSupportsFollowingArchs": "Votre appareil prend en charge les architectures CPU suivantes : ",
"warning": "Avertissement",
"sourceIsXButPackageFromYPrompt": "La source de l'application est '{}' mais le paquet de mise à jour provient de '{}'. Continuer ?",
"updatesAvailable": "Mises à jour disponibles",
@@ -149,7 +149,7 @@
"appsUpdated": "Applications mises à jour",
"appsNotUpdated": "Échec de la mise à jour des applications",
"appsUpdatedNotifDescription": "Notifie à l'utilisateur que des mises à jour d'une ou plusieurs applications ont été installées en arrière-plan.",
"xWasUpdatedToY": "{} a été mis à jour en {}.",
"xWasUpdatedToY": "{} a été mise à jour vers {}.",
"xWasNotUpdatedToY": "Échec de la mise à jour de {} vers {}.",
"errorCheckingUpdates": "Erreur lors de la recherche de mises à jour",
"errorCheckingUpdatesNotifDescription": "Notifie l'utilisateur lorsque la recherche de mises à jour en arrière-plan échoue.",
@@ -180,26 +180,26 @@
"reposHaveMultipleApps": "Les dépôts peuvent contenir plusieurs applications",
"fdroidThirdPartyRepo": "Dépôt tiers F-Droid",
"install": "Installer",
"markInstalled": "Marquer comme étant installé",
"markInstalled": "Marquer comme installée",
"update": "Mettre à jour",
"markUpdated": "Marquer comme étant à jour",
"markUpdated": "Marquer comme à jour",
"additionalOptions": "Options supplémentaires",
"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 la version ne fonctionne pas correctement.",
"downloadingX": "Téléchargement {}",
"downloadingX": "Téléchargement de {}",
"downloadX": "Télécharger {}",
"downloadedX": "Téléchargé {}",
"releaseAsset": "Version active",
"releaseAsset": "Élément de version",
"downloadNotifDescription": "Notifie l'utilisateur sur l'avancement du téléchargement d'une application",
"noAPKFound": "Aucun APK trouvé",
"noVersionDetection": "Aucune version trouvée",
"noVersionDetection": "Aucune détection de version",
"categorize": "Catégoriser",
"categories": "Catégories",
"category": "Catégorie",
"noCategory": "Aucune catégorie",
"noCategories": "Aucune catégories",
"deleteCategoriesQuestion": "Supprimer les catégories?",
"categoryDeleteWarning": "Toutes les applications des catégories supprimées seront définies comme non catégorisées .",
"noCategories": "Aucune catégorie",
"deleteCategoriesQuestion": "Supprimer les catégories ?",
"categoryDeleteWarning": "Toutes les applications des catégories supprimées seront définies comme non catégorisées.",
"addCategory": "Ajouter une catégorie",
"label": "Nom",
"language": "Langue",
@@ -209,26 +209,26 @@
"filterAPKsByRegEx": "Filtrer les APK par expression régulière",
"removeFromObtainium": "Supprimer d'Obtainium",
"uninstallFromDevice": "Désinstaller de l'appareil",
"onlyWorksWithNonVersionDetectApps": "Ne fonctionne que pour les applications dont la détection de la version est désactivée.",
"onlyWorksWithNonVersionDetectApps": "Ne fonctionne qu'avec les applications dont la détection de la version est désactivée.",
"releaseDateAsVersion": "Utiliser la date de sortie comme version",
"releaseTitleAsVersion": "Utiliser le titre de la version comme chaîne de caractères de la version",
"releaseTitleAsVersion": "Utiliser le titre de la version comme chaîne de version",
"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 dont une date de sortie est disponible.",
"changes": "Modifications",
"releaseDate": "Date de sortie",
"importFromURLsInFile": "Importer à partir des URLs d'un fichier (comme OPML)",
"versionDetectionExplanation": "Reporter la chaîne de version selon la version détectée par le système d'exploitation",
"versionDetectionExplanation": "Réconcilier la chaîne de version avec la version détectée par le système d'exploitation",
"versionDetection": "Détection de la version",
"standardVersionDetection": "Détection de la version standard",
"groupByCategory": "Grouper par catégorie",
"autoApkFilterByArch": "Essayer de filtrer les APKs par architecture CPU si possible",
"overrideSource": "Remplacer la source",
"dontShowAgain": "Ne plus afficher",
"dontShowTrackOnlyWarnings": "Ne plus afficher les erreurs 'Suivi uniquement'",
"dontShowAPKOriginWarnings": "Ne plus afficher les erreurs sur l'origine de l'APK",
"dontShowTrackOnlyWarnings": "Ne plus afficher les avertissements 'Suivi uniquement'",
"dontShowAPKOriginWarnings": "Ne plus afficher les avertissements sur l'origine de l'APK",
"moveNonInstalledAppsToBottom": "Déplacer les applications non installées vers le bas de la vue Applications",
"gitlabPATLabel": "Jeton d'accès personnel GitLab",
"about": "À propos",
"requiresCredentialsInSettings": "{} a besoin d'un complément d'information (dans les Paramètres)",
"requiresCredentialsInSettings": "{} a besoin d'informations d'identification supplémentaires (dans les Paramètres)",
"checkOnStart": "Rechercher les mises à jour au démarrage",
"tryInferAppIdFromCode": "Essayer de déduire l'identifiant de l'application à partir du code source",
"removeOnExternalUninstall": "Supprimer automatiquement les applications désinstallées en externe",
@@ -243,67 +243,67 @@
"sortByLastLinkSegment": "Trier par le dernier segment du lien",
"filterReleaseNotesByRegEx": "Filtrer les notes de version par expression régulière",
"customLinkFilterRegex": "Filtre de lien APK personnalisé par expression régulière (par défaut '.apk$')",
"appsPossiblyUpdated": "Tentative de mise à jour des applications",
"appsPossiblyUpdated": "Tentatives de mise à jour d'applications",
"appsPossiblyUpdatedNotifDescription": "Notifie à l'utilisateur que des mises à jour d'une ou plusieurs applications ont potentiellement été appliquées en arrière-plan",
"xWasPossiblyUpdatedToY": "{} peut être mis à jour en {}.",
"xWasPossiblyUpdatedToY": "{} a peut-être été mise à jour vers {}.",
"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.",
"backgroundUpdateLimitsExplanation": "Le résultat d'une installation en arrière-plan ne peut être déterminé qu'à l'ouverture d'Obtainium.",
"backgroundUpdateLimitsExplanation": "Le succès d'une installation en arrière-plan ne peut être déterminé qu'à l'ouverture d'Obtainium.",
"verifyLatestTag": "Vérifier la balise 'latest'",
"intermediateLinkRegex": "Filtrer un lien 'intermédiaire' à visiter",
"filterByLinkText": "Filtrer les liens par texte du lien",
"intermediateLinkNotFound": "Lien intermédiaire introuvable",
"intermediateLink": "Lien intermédiaire",
"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 en WiFi",
"bgUpdatesWhileChargingOnly": "Désactiver les mises à jour en arrière-plan lorsque le véhicule n'est pas en charge",
"exemptFromBackgroundUpdates": "Exclure des mises à jour en arrière-plan (si activées)",
"bgUpdatesOnWiFiOnly": "Désactiver les mises à jour en arrière-plan lorsque vous n'êtes pas en Wi-Fi",
"bgUpdatesWhileChargingOnly": "Désactiver les mises à jour en arrière-plan lorsque l'appareil n'est pas en charge",
"autoSelectHighestVersionCode": "Sélectionner automatiquement la version la plus récente du code APK",
"versionExtractionRegEx": "Extraire la version par Expression régulière",
"trimVersionString": "Découper la version par Expression régulière",
"versionExtractionRegEx": "Expression régulière d'extraction de version",
"trimVersionString": "Découper la chaîne de version avec une expression régulière",
"matchGroupToUseForX": "Groupe de correspondance à utiliser pour \"{}\"",
"matchGroupToUse": "Groupe de correspondance à utiliser pour l'extraction de la version par Expression régulière",
"highlightTouchTargets": "Mettre en évidence les touches moins évidentes",
"pickExportDir": "Selectionner le dossier d'exportation",
"matchGroupToUse": "Groupe de correspondance à utiliser pour l'extraction de la version par expression régulière",
"highlightTouchTargets": "Mettre en évidence les zones tactiles moins évidentes",
"pickExportDir": "Sélectionner le dossier d'exportation",
"autoExportOnChanges": "Exporter automatiquement lors de modifications",
"includeSettings": "Inclure les paramètres",
"filterVersionsByRegEx": "Filtrer les versions par expression régulière",
"trySelectingSuggestedVersionCode": "Essayer de sélectionner la version suggérée du code APK",
"dontSortReleasesList": "Conserver l'ordre de la version de l'API",
"trySelectingSuggestedVersionCode": "Essayer de sélectionner le code de version APK suggéré",
"dontSortReleasesList": "Conserver l'ordre de version de l'API",
"reverseSort": "Tri inversé",
"takeFirstLink": "Utiliser le premier lien",
"skipSort": "Ignorer le tri",
"debugMenu": "Menu de déboggage",
"debugMenu": "Menu de débogage",
"bgTaskStarted": "Tâche en arrière-plan démarrée - vérifier les journaux.",
"runBgCheckNow": "Exécuter la recherche de mise à jour en arrière-plan maintenant",
"versionExtractWholePage": "Appliquer l'extraction de la version par expression régulière à l'ensemble de la page",
"runBgCheckNow": "Exécuter la recherche de mises à jour en arrière-plan maintenant",
"versionExtractWholePage": "Appliquer l'expression régulière d'extraction de version à l'ensemble de la page",
"installing": "Installation",
"skipUpdateNotifications": "Ignorer les notifications de mise à jour",
"skipUpdateNotifications": "Désactiver les notifications de mise à jour",
"updatesAvailableNotifChannel": "Mises à jour disponibles",
"appsUpdatedNotifChannel": "Applications mises à jour",
"appsPossiblyUpdatedNotifChannel": "Essayer de mettre à jour les applications",
"appsPossiblyUpdatedNotifChannel": "Tentatives de mise à jour d'applications",
"errorCheckingUpdatesNotifChannel": "Erreur lors de la recherche de mises à jour",
"appsRemovedNotifChannel": "Applications supprimées",
"downloadingXNotifChannel": "Téléchargement {}",
"completeAppInstallationNotifChannel": "Installation complète de l'application",
"downloadingXNotifChannel": "Téléchargement de {}",
"completeAppInstallationNotifChannel": "Terminer l'installation de l'application",
"checkingForUpdatesNotifChannel": "Recherche de mises à jour",
"onlyCheckInstalledOrTrackOnlyApps": "Rechercher uniquement les mises à jour des applications installées et des applications 'Suivi uniquement'",
"supportFixedAPKURL": "Prise en charge des URL APK fixes",
"selectX": "Sélectionner {}",
"parallelDownloads": "Autoriser les téléchargements simultanés",
"useShizuku": "Utiliser Shizuku ou Sui pour l'installation",
"shizukuBinderNotFound": "Le service Shizuku est introuvable",
"shizukuBinderNotFound": "Le service Shizuku n'est pas en cours d'exécution",
"shizukuOld": "Ancienne version de Shizuku (<11) - veuillez le mettre à jour",
"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é)",
"useSystemFont": "Utiliser la police du système",
"useVersionCodeAsOSVersion": "Utiliser le code de version de l'application détectée par le système d'exploitation",
"requestHeader": "Intitulé de la demande",
"useLatestAssetDateAsReleaseDate": "Utiliser le dernier élément mis en ligne comme date de sortie",
"defaultPseudoVersioningMethod": "Méthode de version fictive par défaut",
"requestHeader": "En-tête de requête",
"useLatestAssetDateAsReleaseDate": "Utiliser la date du dernier élément mis en ligne comme date de sortie",
"defaultPseudoVersioningMethod": "Méthode de versionnage fictif par défaut",
"partialAPKHash": "Hash partiel de l'APK",
"APKLinkHash": "Hash du lien APK",
"directAPKLink": "Lien direct de l'APK",
"pseudoVersionInUse": "Version fictive utilisé",
"pseudoVersionInUse": "Une version fictive est utilisée",
"installed": "Installée",
"latest": "Dernière version",
"invertRegEx": "Inverser l'expression régulière",
@@ -313,25 +313,30 @@
"beforeNewInstallsShareToAppVerifier": "Partager les nouvelles applications avec AppVerifier (si disponible)",
"appVerifierInstructionToast": "Partagez avec AppVerifier, puis revenez ici lorsque tout est prêt.",
"wiki": "Aide/Wiki",
"crowdsourcedConfigsLabel": "Configuration d'applis communautaire (à utiliser à vos risques et périls)",
"crowdsourcedConfigsShort": "Applis communautaires",
"crowdsourcedConfigsLabel": "Configurations d'applications communautaires (à utiliser à vos risques et périls)",
"crowdsourcedConfigsShort": "Applications communautaires",
"allowInsecure": "Autoriser les requêtes HTTP non sécurisées",
"stayOneVersionBehind": "Rester à une version de la dernière",
"stayOneVersionBehind": "Rester une version en arrière de la dernière",
"refreshBeforeDownload": "Actualiser les détails de l'application avant de la télécharger",
"tencentAppStore": "Tencent App Store",
"name": "Nom",
"smartname": "Nom (Smart)",
"sortMethod": "Méthode de tri",
"removeAppQuestion": {
"one": "Supprimer l'application?",
"other": "Supprimer les applications?"
"one": "Supprimer l'application ?",
"other": "Supprimer les applications ?"
},
"tooManyRequestsTryAgainInMinutes": {
"one": "Trop de requêtes (taux limité) - réessayez dans {} minute",
"other": "Trop de requêtes (taux limité) - réessayez dans {} minutes"
},
"bgUpdateGotErrorRetryInMinutes": {
"one": "La recherche de mise à jour en arrière-plan a rencontré un {}, une nouvelle tentative programmée dans {} minute",
"other": "La recherche de mise à jour en arrière-plan a rencontré un {}, une nouvelle tentative programmée dans {} minutes"
"one": "La recherche de mise à jour en arrière-plan a rencontré une erreur {}, une nouvelle tentative programmée dans {} minute",
"other": "La recherche de mise à jour en arrière-plan a rencontré une erreur {}, une nouvelle tentative programmée dans {} minutes"
},
"bgCheckFoundUpdatesWillNotifyIfNeeded": {
"one": "La recherche de mises à jour en arrière-plan à trouvée {} mise à 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"
"one": "La recherche de mises à jour en arrière-plan a trouvé {} mise à jour - l'utilisateur sera notifié si nécessaire",
"other": "La recherche de mises à jour en arrière-plan a trouvé {} mises à jour - l'utilisateur sera notifié si nécessaire"
},
"apps": {
"one": "{} Application",
@@ -339,7 +344,7 @@
},
"url": {
"one": "{} URL",
"other": "{} URL"
"other": "{} URLs"
},
"minute": {
"one": "{} Minute",
@@ -363,7 +368,7 @@
},
"xAndNMoreUpdatesInstalled": {
"one": "{} et 1 autre application ont été mises à jour.",
"other": "{} et {} autres applications ont étés mis à jour."
"other": "{} et {} autres applications ont été mises à jour."
},
"xAndNMoreUpdatesFailed": {
"one": "Échec de la mise à jour de {} et 1 autre application.",
@@ -371,7 +376,7 @@
},
"xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} et 1 autre application ont peut-être été mises à jour.",
"other": "{} et {} autres applications ont peut-être étés mis à jour."
"other": "{} et {} autres applications ont peut-être été mises à jour."
},
"apk": {
"one": "{} APK",

View File

@@ -28,11 +28,11 @@
"githubStarredRepos": "Csillagozott GitHub tárolók",
"uname": "Felhasználónév",
"wrongArgNum": "A megadott argumentumok száma nem megfelelő",
"xIsTrackOnly": "A(z) {} csak nyomonkövethető",
"xIsTrackOnly": "A(z) {} csak nyomon-követhető",
"source": "Forrás",
"app": "Alkalmazás",
"appsFromSourceAreTrackOnly": "Az ebből a forrásból származó alkalmazások „csak nyomonkövethetők”.",
"youPickedTrackOnly": "„Csak nyomonkövetés” opciót választotta.",
"appsFromSourceAreTrackOnly": "Az ebből a forrásból származó alkalmazások „csak nyomon-követhetők”.",
"youPickedTrackOnly": "„Csak nyomon-követés” opciót választotta.",
"trackOnlyAppDescription": "Az alkalmazás frissítéseit nyomon követi, de az Obtainium nem tudja letölteni vagy telepíteni.",
"cancelled": "Visszavonva",
"appAlreadyAdded": "Az alkalmazás már hozzá van adva",
@@ -45,7 +45,7 @@
"search": "Keresés",
"additionalOptsFor": "További lehetőségek a következőhöz: {}",
"supportedSources": "Támogatott források",
"trackOnlyInBrackets": "(Csak nyomonkövetés)",
"trackOnlyInBrackets": "(Csak nyomon-követés)",
"searchableInBrackets": "(Kereshető)",
"appsString": "Alkalmazások",
"noApps": "Nincsenek alkalmazások",
@@ -63,7 +63,7 @@
"removeSelectedApps": "A kiválasztott alkalmazások eltávolítása",
"updateX": "{} frissítése",
"installX": "{} telepítése",
"markXTrackOnlyAsUpdated": "Megjelölés: {}\n(Csak nyomonkövetés)\nFrissítettként",
"markXTrackOnlyAsUpdated": "Megjelölés: {}\n(Csak nyomon-követés)\nFrissítettként",
"changeX": "{}-változás",
"installUpdateApps": "Alkalmazások telepítése/frissítése",
"installUpdateSelectedApps": "A kiválasztott alkalmazások telepítése/frissítése",
@@ -88,13 +88,13 @@
"author": "Szerző",
"upToDateApps": "Naprakész alkalmazások",
"nonInstalledApps": "Nem telepített alkalmazások",
"importExport": "Import/Export",
"importExport": "Adatmozgatás",
"settings": "Beállítások",
"exportedTo": "Exportálva ide: {}",
"obtainiumExport": "Obtainium adatok exportálása",
"obtainiumExport": "Obtainium-adatok exportálása",
"invalidInput": "Hibás bemenet",
"importedX": "Importálva innen: {}",
"obtainiumImport": "Obtainium adatok importálása",
"obtainiumImport": "Obtainium-adatok importálása",
"importFromURLList": "Importálás webcímlistából",
"searchQuery": "Keresési lekérdezés",
"appURLList": "Alkalmazás-webcímlista",
@@ -143,7 +143,7 @@
"warning": "Figyelem",
"sourceIsXButPackageFromYPrompt": "Az alkalmazás forrása a(z) „{}” tároló, de a kiadási csomag innen származik: „{}”. Folytatja?",
"updatesAvailable": "Frissítések érhetők el",
"updatesAvailableNotifDescription": "Értesíti a felhasználót, hogy egy vagy több, az Obtainium által nyomonkövetett alkalmazáshoz frissítések állnak rendelkezésre",
"updatesAvailableNotifDescription": "Értesíti a felhasználót, hogy egy vagy több, az Obtainium által nyomon-követett alkalmazáshoz frissítések állnak rendelkezésre",
"noNewUpdates": "Nincsenek új frissítések.",
"xHasAnUpdate": "A(z) {} frissítést kapott.",
"appsUpdated": "Alkalmazások frissítve",
@@ -154,15 +154,15 @@
"errorCheckingUpdates": "Hiba a frissítések ellenőrzésekor",
"errorCheckingUpdatesNotifDescription": "Értesítés, amely akkor jelenik meg, amikor a frissítések ellenőrzése a háttérben nem sikerül",
"appsRemoved": "Alkalmazások eltávolítva",
"appsRemovedNotifDescription": "Értesíti a felhasználót, hogy egy vagy több alkalmazás betöltés közbeni hiba miatt eltávolításra került",
"xWasRemovedDueToErrorY": "A(z) {} eltávolításra került a következő hiba miatt: {}",
"appsRemovedNotifDescription": "Értesíti a felhasználót, hogy egy vagy több alkalmazás egy betöltés közbeni hiba miatt el lesz(nek) távolítva",
"xWasRemovedDueToErrorY": "A(z) {} el lett távolítva a következő hiba miatt: {}",
"completeAppInstallation": "Teljes alkalmazástelepítés",
"obtainiumMustBeOpenToInstallApps": "Az alkalmazások telepítéséhez az Obtainiumnak megnyitva kell lennie",
"completeAppInstallationNotifDescription": "Megkéri a felhasználót, hogy térjen vissza az Obtainiumhoz, hogy befejezze az alkalmazás telepítését",
"checkingForUpdates": "Frissítések ellenőrzése",
"checkingForUpdatesNotifDescription": "Átmeneti értesítés, amely a frissítések ellenőrzésekor jelenik meg",
"pleaseAllowInstallPerm": "Engedélyezze az Obtainiumnak az alkalmazások telepítését",
"trackOnly": "Csak nyomonkövetés",
"trackOnly": "Csak nyomon-követés",
"errorWithHttpStatusCode": "Hiba {}",
"versionCorrectionDisabled": "Verzió-korrekció letiltva (úgy tűnik, hogy a bővítmény nem működik)",
"unknown": "Ismeretlen",
@@ -223,7 +223,7 @@
"autoApkFilterByArch": "Ha lehetséges, próbálja CPU architektúra szerint szűrni az APK-kat",
"overrideSource": "Forrás felülírása",
"dontShowAgain": "Ne jelenítse meg ezt többé",
"dontShowTrackOnlyWarnings": "Ne jelenítse meg a „Csak nyomonkövetés” figyelmeztetést",
"dontShowTrackOnlyWarnings": "Ne jelenítse meg a „Csak nyomon-követés” figyelmeztetést",
"dontShowAPKOriginWarnings": "Ne jelenítse meg az APK eredetére vonatkozó figyelmeztetéseket",
"moveNonInstalledAppsToBottom": "Helyezze át a nem telepített alkalmazásokat az alkalmazásnézet aljára",
"gitlabPATLabel": "GitLab személyes hozzáférési token",
@@ -261,7 +261,7 @@
"versionExtractionRegEx": "Verzió-karakterlánc kivonatolása reguláris kifejezéssel",
"trimVersionString": "Verzió-karakterlánc levágása reguláris kifejezéssel",
"matchGroupToUseForX": "A(z) „{}” esetén használandó csoport egyeztetése",
"matchGroupToUse": "Verziókarakterlánc-kivonatoláshoz használandó csoport reguláris kifejezéssel való egyeztetése",
"matchGroupToUse": "A verzió-karakterlánc kivonatolásához használandó csoport reguláris kifejezéssel való egyeztetése",
"highlightTouchTargets": "A kevésbé nyilvánvaló érintési pontok kiemelése",
"pickExportDir": "Válassza ki a könyvtárat, ahová exportálni szeretne",
"autoExportOnChanges": "Automatikus exportálás a változtatások után",
@@ -286,7 +286,7 @@
"downloadingXNotifChannel": "A(z) {} letöltése",
"completeAppInstallationNotifChannel": "Teljes alkalmazás telepítés",
"checkingForUpdatesNotifChannel": "Frissítések ellenőrzése",
"onlyCheckInstalledOrTrackOnlyApps": "Csak a telepített és a csak nyomonkövethető alkalmazások frissítéseinek ellenőrzése",
"onlyCheckInstalledOrTrackOnlyApps": "Csak a telepített és a csak nyomon-követhető alkalmazások frissítéseinek ellenőrzése",
"supportFixedAPKURL": "Támogatja a rögzített APK webcímeket",
"selectX": "{} kiválasztása",
"parallelDownloads": "Párhuzamos letöltések engedélyezése",
@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
"allowInsecure": "Nem biztonságos HTTP-kérések engedélyezése",
"stayOneVersionBehind": "Maradjon egy verzióval a legújabb mögött",
"refreshBeforeDownload": "Az alkalmazás adatainak frissítése a letöltés előtt",
"tencentAppStore": "Tencent Appstore",
"name": "Név",
"smartname": "Név (Smart)",
"sortMethod": "Rendezési módszer",
"removeAppQuestion": {
"one": "Eltávolítja az alkalmazást?",
"other": "Eltávolítja az alkalmazásokat?"

View File

@@ -255,7 +255,7 @@
"intermediateLinkNotFound": "Tautan perantara tidak ditemukan",
"intermediateLink": "Tautan perantara",
"exemptFromBackgroundUpdates": "Dikecualikan dari pembaruan latar belakang (jika diaktifkan)",
"bgUpdatesOnWiFiOnly": "Nonaktifkan pembaruan latar belakang saat tidak menggunakan WiFi",
"bgUpdatesOnWiFiOnly": "Nonaktifkan pembaruan latar belakang saat tidak menggunakan Wi-Fi",
"bgUpdatesWhileChargingOnly": "Menonaktifkan pembaruan latar belakang saat tidak mengisi daya",
"autoSelectHighestVersionCode": "Pilih otomatis APK dengan versi kode tertinggi",
"versionExtractionRegEx": "Reguler ekspresi terkait ekstraksi versi string",
@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "Konfigurasi Aplikasi Crowdsourced",
"allowInsecure": "Izinkan permintaan HTTP yang tidak aman",
"stayOneVersionBehind": "Tetap satu versi di belakang versi terbaru",
"refreshBeforeDownload": "Segarkan detail aplikasi sebelum mengunduh",
"tencentAppStore": "Tencent App Store",
"name": "Nama",
"smartname": "Nama (Cerdas)",
"sortMethod": "Metode Penyortiran",
"removeAppQuestion": {
"one": "Hapus aplikasi?",
"other": "Hapus aplikasi?"

View File

@@ -255,7 +255,7 @@
"intermediateLinkNotFound": "Link intermedio non trovato",
"intermediateLink": "Collegamento intermedio",
"exemptFromBackgroundUpdates": "Esente da aggiornamenti in secondo piano (se attivo)",
"bgUpdatesOnWiFiOnly": "Disattiva aggiornamenti in secondo piano quando non si usa il WiFi",
"bgUpdatesOnWiFiOnly": "Disattiva aggiornamenti in secondo piano quando non si usa il Wi-Fi",
"bgUpdatesWhileChargingOnly": "Disabilita gli aggiornamenti in background quando non è in carica",
"autoSelectHighestVersionCode": "Auto-seleziona APK con versionCode più alto",
"versionExtractionRegEx": "RegEx di estrazione versione",
@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "Configurazioni di app in crowdsourcing",
"allowInsecure": "Consentire le richieste HTTP non sicure",
"stayOneVersionBehind": "Rimanere una versione indietro rispetto alla più recente",
"refreshBeforeDownload": "Aggiornare i dettagli dell'app prima del download",
"tencentAppStore": "Tencent App Store",
"name": "Nome",
"smartname": "Nome (intelligente)",
"sortMethod": "Metodo di ordinamento",
"removeAppQuestion": {
"one": "Rimuovere l'app?",
"other": "Rimuovere le app?"

View File

@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "クラウドソーシングによるアプリの設定",
"allowInsecure": "安全でないHTTPリクエストを許可する",
"stayOneVersionBehind": "最新のバージョンから1つ前のものを使用する",
"refreshBeforeDownload": "ダウンロード前にアプリの詳細を更新する",
"tencentAppStore": "Tencent App Store",
"name": "Name",
"smartname": "名前(スマート)",
"sortMethod": "ソート方法",
"removeAppQuestion": {
"one": "アプリを削除しますか?",
"other": "アプリを削除しますか?"

385
assets/translations/ko.json Normal file
View File

@@ -0,0 +1,385 @@
{
"invalidURLForSource": "유효한 {} 앱 URL이 아닙니다",
"noReleaseFound": "적절한 릴리스를 찾을 수 없습니다",
"noVersionFound": "릴리스 버전을 결정할 수 없습니다",
"urlMatchesNoSource": "URL이 알려진 소스와 일치하지 않습니다",
"cantInstallOlderVersion": "앱의 이전 버전을 설치할 수 없습니다",
"appIdMismatch": "다운로드된 패키지 ID가 기존 앱 ID와 일치하지 않습니다",
"functionNotImplemented": "이 클래스는 이 기능을 구현하지 않았습니다",
"placeholder": "플레이스홀더",
"someErrors": "일부 오류가 발생했습니다",
"unexpectedError": "예기치 않은 오류",
"ok": "확인",
"and": "그리고",
"githubPATLabel": "GitHub 개인 액세스 토큰 (속도 제한 증가)",
"includePrereleases": "사전 릴리스 포함",
"fallbackToOlderReleases": "이전 릴리스로 대체",
"filterReleaseTitlesByRegEx": "정규 표현식으로 릴리스 제목 필터링",
"invalidRegEx": "잘못된 정규 표현식",
"noDescription": "설명 없음",
"cancel": "취소",
"continue": "계속",
"requiredInBrackets": "(필수)",
"dropdownNoOptsError": "오류: 드롭다운에는 최소 하나의 옵션이 있어야 합니다",
"colour": "색상",
"standard": "표준",
"custom": "사용자 정의",
"useMaterialYou": "Material You 사용",
"githubStarredRepos": "GitHub 즐겨찾기 저장소",
"uname": "사용자 이름",
"wrongArgNum": "잘못된 인수 수 제공",
"xIsTrackOnly": "{}는 추적 전용입니다",
"source": "소스",
"app": "앱",
"appsFromSourceAreTrackOnly": "이 소스의 앱은 '추적 전용'입니다.",
"youPickedTrackOnly": "당신은 '추적 전용' 옵션을 선택했습니다.",
"trackOnlyAppDescription": "앱은 업데이트를 위해 추적되지만 Obtainium은 다운로드하거나 설치할 수 없습니다.",
"cancelled": "취소됨",
"appAlreadyAdded": "앱이 이미 추가되었습니다",
"alreadyUpToDateQuestion": "앱이 이미 최신 상태입니까?",
"addApp": "앱 추가",
"appSourceURL": "앱 소스 URL",
"error": "오류",
"add": "추가",
"searchSomeSourcesLabel": "검색 (일부 소스만)",
"search": "검색",
"additionalOptsFor": "{}에 대한 추가 옵션",
"supportedSources": "지원되는 소스",
"trackOnlyInBrackets": "(추적 전용)",
"searchableInBrackets": "(검색 가능)",
"appsString": "앱",
"noApps": "앱 없음",
"noAppsForFilter": "필터에 대한 앱 없음",
"byX": "{}에 의해",
"percentProgress": "진행률: {}%",
"pleaseWait": "기다려 주세요",
"updateAvailable": "업데이트 가능",
"notInstalled": "설치되지 않음",
"pseudoVersion": "의사 버전",
"selectAll": "모두 선택",
"deselectX": "{} 선택 해제",
"xWillBeRemovedButRemainInstalled": "{}는 Obtainium에서 제거되지만 장치에 설치된 상태로 남아 있습니다.",
"removeSelectedAppsQuestion": "선택한 앱을 제거하시겠습니까?",
"removeSelectedApps": "선택한 앱 제거",
"updateX": "{} 업데이트",
"installX": "{} 설치",
"markXTrackOnlyAsUpdated": "{}\n(추적 전용)\n업데이트됨으로 표시",
"changeX": "{} 변경",
"installUpdateApps": "앱 설치/업데이트",
"installUpdateSelectedApps": "선택한 앱 설치/업데이트",
"markXSelectedAppsAsUpdated": "{} 선택한 앱을 업데이트됨으로 표시하시겠습니까?",
"no": "아니요",
"yes": "예",
"markSelectedAppsUpdated": "선택한 앱을 업데이트됨으로 표시",
"pinToTop": "상단에 고정",
"unpinFromTop": "상단에서 고정 해제",
"resetInstallStatusForSelectedAppsQuestion": "선택한 앱의 설치 상태를 재설정하시겠습니까?",
"installStatusOfXWillBeResetExplanation": "선택한 앱의 설치 상태가 재설정됩니다.\n\n이것은 실패한 업데이트나 기타 문제로 인해 Obtainium에 표시된 앱 버전이 잘못된 경우에 도움이 될 수 있습니다.",
"customLinkMessage": "이 링크는 Obtainium이 설치된 장치에서 작동합니다",
"shareAppConfigLinks": "앱 구성 HTML 링크로 공유",
"shareSelectedAppURLs": "선택한 앱 URL 공유",
"resetInstallStatus": "설치 상태 재설정",
"more": "더보기",
"removeOutdatedFilter": "구식 앱 필터 제거",
"showOutdatedOnly": "구식 앱만 표시",
"filter": "필터",
"filterApps": "앱 필터",
"appName": "앱 이름",
"author": "저자",
"upToDateApps": "최신 상태의 앱",
"nonInstalledApps": "설치되지 않은 앱",
"importExport": "가져오기/내보내기",
"settings": "설정",
"exportedTo": "{}로 내보내기 완료",
"obtainiumExport": "Obtainium 내보내기",
"invalidInput": "잘못된 입력",
"importedX": "{} 가져오기 완료",
"obtainiumImport": "Obtainium 가져오기",
"importFromURLList": "URL 목록에서 가져오기",
"searchQuery": "검색 쿼리",
"appURLList": "앱 URL 목록",
"line": "줄",
"searchX": "{} 검색",
"noResults": "결과가 없습니다",
"importX": "{} 가져오기",
"importedAppsIdDisclaimer": "가져온 앱은 \"설치되지 않음\"으로 잘못 표시될 수 있습니다.\n이를 수정하려면 Obtainium을 통해 다시 설치하십시오.\n앱 데이터에는 영향을 미치지 않습니다.\n\nURL 및 타사 가져오기 방법에만 영향을 미칩니다.",
"importErrors": "가져오기 오류",
"importedXOfYApps": "{}개의 앱 중 {}개 가져오기 완료.",
"followingURLsHadErrors": "다음 URL에 오류가 있었습니다:",
"selectURL": "URL 선택",
"selectURLs": "URL 선택",
"pick": "선택",
"theme": "테마",
"dark": "다크",
"light": "라이트",
"followSystem": "시스템 따르기",
"followSystemThemeExplanation": "시스템 테마를 따르려면 타사 애플리케이션을 사용해야 합니다",
"useBlackTheme": "순수한 검은색 다크 테마 사용",
"appSortBy": "앱 정렬 기준",
"authorName": "저자/이름",
"nameAuthor": "이름/저자",
"asAdded": "추가된 순서대로",
"appSortOrder": "앱 정렬 순서",
"ascending": "오름차순",
"descending": "내림차순",
"bgUpdateCheckInterval": "백그라운드 업데이트 확인 간격",
"neverManualOnly": "절대 - 수동만",
"appearance": "외관",
"showWebInAppView": "앱 보기에서 소스 웹페이지 표시",
"pinUpdates": "앱 보기 상단에 업데이트 고정",
"updates": "업데이트",
"sourceSpecific": "소스별",
"appSource": "앱 소스",
"noLogs": "로그 없음",
"appLogs": "앱 로그",
"close": "닫기",
"share": "공유",
"appNotFound": "앱을 찾을 수 없습니다",
"obtainiumExportHyphenatedLowercase": "obtainium-export",
"pickAnAPK": "APK 선택",
"appHasMoreThanOnePackage": "{}에는 둘 이상의 패키지가 있습니다:",
"deviceSupportsXArch": "장치는 {} CPU 아키텍처를 지원합니다.",
"deviceSupportsFollowingArchs": "장치는 다음 CPU 아키텍처를 지원합니다:",
"warning": "경고",
"sourceIsXButPackageFromYPrompt": "앱 소스는 '{}'이지만 릴리스 패키지는 '{}'에서 제공됩니다. 계속하시겠습니까?",
"updatesAvailable": "업데이트 가능",
"updatesAvailableNotifDescription": "Obtainium이 추적하는 하나 이상의 앱에 대한 업데이트가 있음을 사용자에게 알립니다",
"noNewUpdates": "새로운 업데이트가 없습니다.",
"xHasAnUpdate": "{}에 업데이트가 있습니다.",
"appsUpdated": "앱 업데이트됨",
"appsNotUpdated": "앱 업데이트 실패",
"appsUpdatedNotifDescription": "백그라운드에서 하나 이상의 앱에 대한 업데이트가 적용되었음을 사용자에게 알립니다",
"xWasUpdatedToY": "{}가 {}로 업데이트되었습니다.",
"xWasNotUpdatedToY": "{}를 {}로 업데이트하지 못했습니다.",
"errorCheckingUpdates": "업데이트 확인 오류",
"errorCheckingUpdatesNotifDescription": "백그라운드 업데이트 확인이 실패할 때 표시되는 알림",
"appsRemoved": "앱 제거됨",
"appsRemovedNotifDescription": "로드 중 오류로 인해 하나 이상의 앱이 제거되었음을 사용자에게 알립니다",
"xWasRemovedDueToErrorY": "{}가 다음 오류로 인해 제거되었습니다: {}",
"completeAppInstallation": "앱 설치 완료",
"obtainiumMustBeOpenToInstallApps": "앱을 설치하려면 Obtainium이 열려 있어야 합니다",
"completeAppInstallationNotifDescription": "앱 설치를 완료하려면 Obtainium으로 돌아가도록 사용자에게 요청합니다",
"checkingForUpdates": "업데이트 확인 중",
"checkingForUpdatesNotifDescription": "업데이트 확인 시 나타나는 일시적인 알림",
"pleaseAllowInstallPerm": "Obtainium이 앱을 설치할 수 있도록 허용해 주세요",
"trackOnly": "추적 전용",
"errorWithHttpStatusCode": "오류 {}",
"versionCorrectionDisabled": "버전 수정 비활성화됨 (플러그인이 작동하지 않는 것 같습니다)",
"unknown": "알 수 없음",
"none": "없음",
"never": "절대",
"latestVersionX": "최신: {}",
"installedVersionX": "설치됨: {}",
"lastUpdateCheckX": "마지막 업데이트 확인: {}",
"remove": "제거",
"yesMarkUpdated": "예, 업데이트됨으로 표시",
"fdroid": "F-Droid 공식",
"appIdOrName": "앱 ID 또는 이름",
"appId": "앱 ID",
"appWithIdOrNameNotFound": "해당 ID 또는 이름의 앱을 찾을 수 없습니다",
"reposHaveMultipleApps": "저장소에는 여러 앱이 포함될 수 있습니다",
"fdroidThirdPartyRepo": "F-Droid 타사 저장소",
"install": "설치",
"markInstalled": "설치됨으로 표시",
"update": "업데이트",
"markUpdated": "업데이트됨으로 표시",
"additionalOptions": "추가 옵션",
"disableVersionDetection": "버전 감지 비활성화",
"noVersionDetectionExplanation": "이 옵션은 버전 감지가 올바르게 작동하지 않는 앱에만 사용해야 합니다.",
"downloadingX": "{} 다운로드 중",
"downloadX": "{} 다운로드",
"downloadedX": "{} 다운로드 완료",
"releaseAsset": "릴리스 자산",
"downloadNotifDescription": "앱 다운로드 진행 상황을 사용자에게 알립니다",
"noAPKFound": "APK를 찾을 수 없습니다",
"noVersionDetection": "버전 감지 없음",
"categorize": "분류",
"categories": "카테고리",
"category": "카테고리",
"noCategory": "카테고리 없음",
"noCategories": "카테고리 없음",
"deleteCategoriesQuestion": "카테고리를 삭제하시겠습니까?",
"categoryDeleteWarning": "삭제된 카테고리의 모든 앱은 미분류로 설정됩니다.",
"addCategory": "카테고리 추가",
"label": "레이블",
"language": "언어",
"copiedToClipboard": "클립보드에 복사됨",
"storagePermissionDenied": "저장소 권한 거부됨",
"selectedCategorizeWarning": "이 작업은 선택한 앱의 기존 카테고리 설정을 대체합니다.",
"filterAPKsByRegEx": "정규 표현식으로 APK 필터링",
"removeFromObtainium": "Obtainium에서 제거",
"uninstallFromDevice": "장치에서 제거",
"onlyWorksWithNonVersionDetectApps": "버전 감지가 비활성화된 앱에만 작동합니다.",
"releaseDateAsVersion": "릴리스 날짜를 버전 문자열로 사용",
"releaseTitleAsVersion": "릴리스 제목을 버전 문자열로 사용",
"releaseDateAsVersionExplanation": "이 옵션은 버전 감지가 올바르게 작동하지 않지만 릴리스 날짜가 있는 앱에만 사용해야 합니다.",
"changes": "변경 사항",
"releaseDate": "릴리스 날짜",
"importFromURLsInFile": "파일의 URL에서 가져오기 (OPML과 같은)",
"versionDetectionExplanation": "OS에서 감지된 버전과 버전 문자열 조정",
"versionDetection": "버전 감지",
"standardVersionDetection": "표준 버전 감지",
"groupByCategory": "카테고리별 그룹화",
"autoApkFilterByArch": "가능한 경우 CPU 아키텍처별로 APK 필터링 시도",
"overrideSource": "소스 재정의",
"dontShowAgain": "다시 표시하지 않기",
"dontShowTrackOnlyWarnings": "'추적 전용' 경고 표시 안 함",
"dontShowAPKOriginWarnings": "APK 출처 경고 표시 안 함",
"moveNonInstalledAppsToBottom": "설치되지 않은 앱을 앱 보기 하단으로 이동",
"gitlabPATLabel": "GitLab 개인 액세스 토큰",
"about": "정보",
"requiresCredentialsInSettings": "{}는 추가 자격 증명이 필요합니다 (설정에서)",
"checkOnStart": "시작 시 업데이트 확인",
"tryInferAppIdFromCode": "소스 코드에서 앱 ID 추론 시도",
"removeOnExternalUninstall": "외부에서 제거된 앱 자동 제거",
"pickHighestVersionCode": "가장 높은 버전 코드 APK 자동 선택",
"checkUpdateOnDetailPage": "앱 세부 정보 페이지 열 때 업데이트 확인",
"disablePageTransitions": "페이지 전환 애니메이션 비활성화",
"reversePageTransitions": "페이지 전환 애니메이션 반전",
"minStarCount": "최소 별 개수",
"addInfoBelow": "아래에 이 정보를 추가하십시오.",
"addInfoInSettings": "설정에 이 정보를 추가하십시오.",
"githubSourceNote": "GitHub 속도 제한은 API 키를 사용하여 피할 수 있습니다.",
"sortByLastLinkSegment": "링크의 마지막 세그먼트로만 정렬",
"filterReleaseNotesByRegEx": "정규 표현식으로 릴리스 노트 필터링",
"customLinkFilterRegex": "정규 표현식으로 사용자 정의 APK 링크 필터링 (기본값 '.apk$')",
"appsPossiblyUpdated": "앱 업데이트 시도됨",
"appsPossiblyUpdatedNotifDescription": "백그라운드에서 하나 이상의 앱에 대한 업데이트가 잠재적으로 적용되었음을 사용자에게 알립니다",
"xWasPossiblyUpdatedToY": "{}가 {}로 업데이트되었을 수 있습니다.",
"enableBackgroundUpdates": "백그라운드 업데이트 활성화",
"backgroundUpdateReqsExplanation": "모든 앱에 대해 백그라운드 업데이트가 가능하지 않을 수 있습니다.",
"backgroundUpdateLimitsExplanation": "백그라운드 설치의 성공 여부는 Obtainium이 열릴 때만 확인할 수 있습니다.",
"verifyLatestTag": "'최신' 태그 확인",
"intermediateLinkRegex": "'중간' 링크 방문 필터",
"filterByLinkText": "링크 텍스트로 링크 필터링",
"intermediateLinkNotFound": "중간 링크를 찾을 수 없습니다",
"intermediateLink": "중간 링크",
"exemptFromBackgroundUpdates": "백그라운드 업데이트에서 제외 (활성화된 경우)",
"bgUpdatesOnWiFiOnly": "WiFi가 아닐 때 백그라운드 업데이트 비활성화",
"bgUpdatesWhileChargingOnly": "충전 중이 아닐 때 백그라운드 업데이트 비활성화",
"autoSelectHighestVersionCode": "가장 높은 versionCode APK 자동 선택",
"versionExtractionRegEx": "버전 문자열 추출 정규 표현식",
"trimVersionString": "정규 표현식으로 버전 문자열 자르기",
"matchGroupToUseForX": "\"{}\"에 사용할 일치 그룹",
"matchGroupToUse": "버전 문자열 추출 정규 표현식에 사용할 일치 그룹",
"highlightTouchTargets": "덜 명확한 터치 대상 강조",
"pickExportDir": "내보내기 디렉토리 선택",
"autoExportOnChanges": "변경 시 자동 내보내기",
"includeSettings": "설정 포함",
"filterVersionsByRegEx": "정규 표현식으로 버전 필터링",
"trySelectingSuggestedVersionCode": "제안된 versionCode APK 선택 시도",
"dontSortReleasesList": "API에서 릴리스 순서 유지",
"reverseSort": "정렬 반전",
"takeFirstLink": "첫 번째 링크 선택",
"skipSort": "정렬 건너뛰기",
"debugMenu": "디버그 메뉴",
"bgTaskStarted": "백그라운드 작업 시작됨 - 로그를 확인하세요.",
"runBgCheckNow": "지금 백그라운드 업데이트 확인 실행",
"versionExtractWholePage": "전체 페이지에 버전 문자열 추출 정규 표현식 적용",
"installing": "설치 중",
"skipUpdateNotifications": "업데이트 알림 건너뛰기",
"updatesAvailableNotifChannel": "업데이트 가능",
"appsUpdatedNotifChannel": "앱 업데이트됨",
"appsPossiblyUpdatedNotifChannel": "앱 업데이트 시도됨",
"errorCheckingUpdatesNotifChannel": "업데이트 확인 오류",
"appsRemovedNotifChannel": "앱 제거됨",
"downloadingXNotifChannel": "{} 다운로드 중",
"completeAppInstallationNotifChannel": "앱 설치 완료",
"checkingForUpdatesNotifChannel": "업데이트 확인 중",
"onlyCheckInstalledOrTrackOnlyApps": "설치된 앱과 추적 전용 앱만 업데이트 확인",
"supportFixedAPKURL": "고정 APK URL 지원",
"selectX": "{} 선택",
"parallelDownloads": "병렬 다운로드 허용",
"useShizuku": "Shizuku 또는 Sui를 사용하여 설치",
"shizukuBinderNotFound": "Shizuku 서비스가 실행 중이 아닙니다",
"shizukuOld": "오래된 Shizuku 버전 (<11) - 업데이트 필요",
"shizukuOldAndroidWithADB": "ADB로 Android < 8.1에서 실행 중인 Shizuku - Android를 업데이트하거나 대신 Sui를 사용하세요",
"shizukuPretendToBeGooglePlay": "설치 소스로 Google Play 설정 (Shizuku 사용 시)",
"useSystemFont": "시스템 글꼴 사용",
"useVersionCodeAsOSVersion": "앱 versionCode를 OS에서 감지된 버전으로 사용",
"requestHeader": "요청 헤더",
"useLatestAssetDateAsReleaseDate": "최신 자산 업로드를 릴리스 날짜로 사용",
"defaultPseudoVersioningMethod": "기본 의사 버전 관리 방법",
"partialAPKHash": "부분 APK 해시",
"APKLinkHash": "APK 링크 해시",
"directAPKLink": "직접 APK 링크",
"pseudoVersionInUse": "의사 버전 사용 중",
"installed": "설치됨",
"latest": "최신",
"invertRegEx": "정규 표현식 반전",
"note": "노트",
"selfHostedNote": "\"{}\" 드롭다운을 사용하여 소스의 자체 호스팅/사용자 정의 인스턴스에 도달할 수 있습니다.",
"badDownload": "APK를 구문 분석할 수 없습니다 (호환되지 않거나 부분 다운로드)",
"beforeNewInstallsShareToAppVerifier": "새 앱을 AppVerifier와 공유 (가능한 경우)",
"appVerifierInstructionToast": "AppVerifier에 공유한 후 준비가 되면 여기로 돌아오세요.",
"wiki": "도움말/위키",
"crowdsourcedConfigsLabel": "크라우드소싱 앱 구성 (자신의 책임 하에 사용)",
"crowdsourcedConfigsShort": "크라우드소싱 앱 구성",
"allowInsecure": "안전하지 않은 HTTP 요청 허용",
"stayOneVersionBehind": "최신 버전보다 한 버전 뒤에 머무르기",
"refreshBeforeDownload": "다운로드 전에 앱 세부 정보 새로 고침",
"tencentAppStore": "텐센트 앱 스토어",
"name": "이름",
"smartname": "이름(스마트)",
"sortMethod": "정렬 방법",
"removeAppQuestion": {
"one": "앱을 제거하시겠습니까?",
"other": "앱을 제거하시겠습니까?"
},
"tooManyRequestsTryAgainInMinutes": {
"one": "요청이 너무 많습니다 (속도 제한) - {}분 후에 다시 시도하세요",
"other": "요청이 너무 많습니다 (속도 제한) - {}분 후에 다시 시도하세요"
},
"bgUpdateGotErrorRetryInMinutes": {
"one": "BG 업데이트 확인 중 {} 오류가 발생했습니다. {}분 후에 다시 확인을 예약합니다",
"other": "BG 업데이트 확인 중 {} 오류가 발생했습니다. {}분 후에 다시 확인을 예약합니다"
},
"bgCheckFoundUpdatesWillNotifyIfNeeded": {
"one": "BG 업데이트 확인에서 {}개의 업데이트를 발견했습니다 - 필요 시 사용자에게 알립니다",
"other": "BG 업데이트 확인에서 {}개의 업데이트를 발견했습니다 - 필요 시 사용자에게 알립니다"
},
"apps": {
"one": "{} 앱",
"other": "{} 앱"
},
"url": {
"one": "{} URL",
"other": "{} URL"
},
"minute": {
"one": "{} 분",
"other": "{} 분"
},
"hour": {
"one": "{} 시간",
"other": "{} 시간"
},
"day": {
"one": "{} 일",
"other": "{} 일"
},
"clearedNLogsBeforeXAfterY": {
"one": "{n}개의 로그가 지워졌습니다 (이전 = {before}, 이후 = {after})",
"other": "{n}개의 로그가 지워졌습니다 (이전 = {before}, 이후 = {after})"
},
"xAndNMoreUpdatesAvailable": {
"one": "{} 및 1개의 앱에 업데이트가 있습니다.",
"other": "{} 및 {}개의 앱에 업데이트가 있습니다."
},
"xAndNMoreUpdatesInstalled": {
"one": "{} 및 1개의 앱이 업데이트되었습니다.",
"other": "{} 및 {}개의 앱이 업데이트되었습니다."
},
"xAndNMoreUpdatesFailed": {
"one": "{} 및 1개의 앱 업데이트에 실패했습니다.",
"other": "{} 및 {}개의 앱 업데이트에 실패했습니다."
},
"xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} 및 1개의 앱이 업데이트되었을 수 있습니다.",
"other": "{} 및 {}개의 앱이 업데이트되었을 수 있습니다."
},
"apk": {
"one": "{} APK",
"other": "{} APK"
}
}

View File

@@ -255,7 +255,7 @@
"intermediateLinkNotFound": "Intermediaire link niet gevonden",
"intermediateLink": "Intermediaire link",
"exemptFromBackgroundUpdates": "Vrijgesteld van achtergrond-updates (indien ingeschakeld)",
"bgUpdatesOnWiFiOnly": "Achtergrond-updates uitschakelen wanneer niet verbonden met WiFi",
"bgUpdatesOnWiFiOnly": "Achtergrond-updates uitschakelen wanneer niet verbonden met Wi-Fi",
"bgUpdatesWhileChargingOnly": "Achtergrondupdates uitschakelen als er niet wordt opgeladen",
"autoSelectHighestVersionCode": "De APK met de hoogste versiecode automatisch selecteren",
"versionExtractionRegEx": "Reguliere expressie voor versie-extractie",
@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "App-configuraties door menigte",
"allowInsecure": "Onveilige HTTP-verzoeken toestaan",
"stayOneVersionBehind": "Blijf een versie achter op de nieuwste",
"refreshBeforeDownload": "Vernieuw app details voor download",
"tencentAppStore": "Tencent App Store",
"name": "Naam",
"smartname": "Naam (Slim)",
"sortMethod": "Sorteermethode",
"removeAppQuestion": {
"one": "App verwijderen?",
"other": "Apps verwijderen?"

View File

@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "Baza konfiguracji",
"allowInsecure": "Zezwalaj na niezabezpieczone żądania HTTP",
"stayOneVersionBehind": "Pozostań jedną wersję w tyle za najnowszą",
"refreshBeforeDownload": "Odśwież szczegóły aplikacji przed pobraniem",
"tencentAppStore": "Tencent App Store",
"name": "Nazwa",
"smartname": "Nazwa (Smart)",
"sortMethod": "Metoda sortowania",
"removeAppQuestion": {
"one": "Usunąć aplikację?",
"few": "Usunąć aplikacje?",

View File

@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "Configurações de aplicações com base em crowdsourcing",
"allowInsecure": "Permitir pedidos HTTP inseguros",
"stayOneVersionBehind": "Manter-se uma versão atrás da mais recente",
"refreshBeforeDownload": "Atualizar os detalhes da aplicação antes da transferência",
"tencentAppStore": "Tencent App Store",
"name": "Nome",
"smartname": "Nome (Smart)",
"sortMethod": "Método de ordenação",
"removeAppQuestion": {
"one": "Remover aplicativo?",
"other": "Remover aplicativos?"

View File

@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "Конфиги приложений с помощью краудсорсинга",
"allowInsecure": "Разрешить небезопасные HTTP-запросы",
"stayOneVersionBehind": "Не отставайте от последней версии",
"refreshBeforeDownload": "Обновляйте информацию о приложении перед загрузкой",
"tencentAppStore": "Tencent App Store",
"name": "Имя",
"smartname": "Имя (умное)",
"sortMethod": "Метод сортировки",
"removeAppQuestion": {
"one": "Удалить приложение?",
"other": "Удалить приложения?"

View File

@@ -13,7 +13,10 @@ const neverAutoTranslate = {
obtainiumExportHyphenatedLowercase: ['*'],
theme: ['de'],
appId: ['de'],
placeholder: ['pl']
placeholder: ['pl'],
importExport: ['fr'],
url: ['fr'],
tencentAppStore: ['*']
}
const translateText = async (text, targetLang, authKey) => {
@@ -76,40 +79,49 @@ const main = async () => {
const translationKeys = Object.keys(templateTranslation)
for (let j in translationKeys) {
const k = translationKeys[j]
if (JSON.stringify(thisTranslation[k]) == JSON.stringify(templateTranslation[k])) {
const lang = file.split('/').pop().split('.')[0]
if (!neverAutoTranslate[k] || (neverAutoTranslate[k].indexOf('*') < 0 && neverAutoTranslate[k].indexOf(lang) < 0)) {
const reportLine = `${file} :::: ${k} :::: ${JSON.stringify(thisTranslation[k])}`
if (deeplAPIKey) {
const translateFunc = async (str) => {
const response = await translateText(str, lang, deeplAPIKey)
if (response.translations) {
return response.translations[0].text
} else {
throw JSON.stringify(response)
}
}
try {
if (typeof templateTranslation[k] == 'string') {
thisTranslation[k] = await translateFunc(thisTranslation[k])
} else {
const subKeys = Object.keys(templateTranslation[k])
for (let n in subKeys) {
const kk = subKeys[n]
thisTranslation[k][kk] = await translateFunc(thisTranslation[k][kk])
try {
if (JSON.stringify(thisTranslation[k]) == JSON.stringify(templateTranslation[k])) {
const lang = file.split('/').pop().split('.')[0]
if (!neverAutoTranslate[k] || (neverAutoTranslate[k].indexOf('*') < 0 && neverAutoTranslate[k].indexOf(lang) < 0)) {
const reportLine = `${file} :::: ${k} :::: ${JSON.stringify(thisTranslation[k])}`
if (deeplAPIKey) {
const translateFunc = async (str) => {
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, Math.random() * 1000); // Try to avoid rate limit
})
const response = await translateText(str, lang, deeplAPIKey)
if (response.translations) {
return response.translations[0].text
} else {
throw JSON.stringify(response)
}
}
} catch (e) {
if (typeof e == 'string') {
console.log(`${reportLine} :::: ${e}`)
} else {
throw e
try {
if (typeof templateTranslation[k] == 'string') {
thisTranslation[k] = await translateFunc(thisTranslation[k])
} else {
const subKeys = Object.keys(templateTranslation[k])
for (let n in subKeys) {
const kk = subKeys[n]
thisTranslation[k][kk] = await translateFunc(thisTranslation[k][kk])
}
}
} catch (e) {
if (typeof e == 'string') {
console.log(`${reportLine} :::: ${e}`)
} else {
throw e
}
}
} else {
console.log(reportLine)
}
} else {
console.log(reportLine)
}
}
} catch (err) {
console.error(err)
}
}
fs.writeFileSync(file, `${JSON.stringify(thisTranslation, null, ' ')}\n`)

View File

@@ -255,7 +255,7 @@
"intermediateLinkNotFound": "Mellanlänk hittades inte",
"intermediateLink": "Mellanlänk",
"exemptFromBackgroundUpdates": "Undta från bakgrundsuppdateringar (om aktiverad)",
"bgUpdatesOnWiFiOnly": "Inaktivera Bakgrundsuppdateringar utan WiFi",
"bgUpdatesOnWiFiOnly": "Inaktivera Bakgrundsuppdateringar utan Wi-Fi",
"bgUpdatesWhileChargingOnly": "Inaktivera bakgrundsuppdateringar när du inte laddar",
"autoSelectHighestVersionCode": "Välj automatiskt högsta versionskod APK",
"versionExtractionRegEx": "Version Extraction RegEx",
@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "Appkonfigurationer med hjälp av crowdsourcing",
"allowInsecure": "Tillåt osäkra HTTP-förfrågningar",
"stayOneVersionBehind": "Håll dig en version bakom den senaste",
"refreshBeforeDownload": "Uppdatera appdetaljerna före nedladdning",
"tencentAppStore": "Tencent App Store",
"name": "Namn",
"smartname": "Namn (Smart)",
"sortMethod": "Sorteringsmetod",
"removeAppQuestion": {
"one": "Ta Bort App?",
"other": "Ta Bort Appar?"

View File

@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "Kitle Kaynaklı Uygulama Yapılandırmaları",
"allowInsecure": "Güvensiz HTTP isteklerine izin ver",
"stayOneVersionBehind": "En son sürümün bir sürüm gerisinde kalın",
"refreshBeforeDownload": "İndirmeden önce uygulama ayrıntılarını yenileyin",
"tencentAppStore": "Tencent App Store",
"name": "İsim",
"smartname": "İsim (Akıllı)",
"sortMethod": "Sıralama Yöntemi",
"removeAppQuestion": {
"one": "Uygulamayı Kaldır?",
"other": "Uygulamaları Kaldır?"

View File

@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "Налаштування краудсорсингових додатків",
"allowInsecure": "Дозволити незахищені HTTP-запити",
"stayOneVersionBehind": "Залишайтеся на одну версію актуальнішою",
"refreshBeforeDownload": "Оновіть інформацію про програму перед завантаженням",
"tencentAppStore": "Tencent App Store",
"name": "Ім'я",
"smartname": "Ім'я (Smart)",
"sortMethod": "Метод сортування",
"removeAppQuestion": {
"one": "Видалити застосунок?",
"other": "Видалити застосунки?"

View File

@@ -255,7 +255,7 @@
"intermediateLinkNotFound": "Không tìm thấy liên kết trung gian",
"intermediateLink": "Liên kết trung gian",
"exemptFromBackgroundUpdates": "Miễn cập nhật nền (nếu được bật)",
"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ó Wi-Fi",
"bgUpdatesWhileChargingOnly": "Disable background updates when not charging",
"autoSelectHighestVersionCode": "Tự động chọn APK mã phiên bản cao nhất",
"versionExtractionRegEx": "Trích xuất phiên bản RegEx",
@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
"allowInsecure": "Allow insecure HTTP requests",
"stayOneVersionBehind": "Stay one version behind latest",
"refreshBeforeDownload": "Refresh app details before download",
"tencentAppStore": "Tencent App Store",
"name": "Name",
"smartname": "Name (Smart)",
"sortMethod": "Sort Method",
"removeAppQuestion": {
"one": "Gỡ ứng dụng?",
"other": "Gỡ ứng dụng?"

View File

@@ -255,7 +255,7 @@
"intermediateLinkNotFound": "沒有找到中間連結",
"intermediateLink": "中間連結",
"exemptFromBackgroundUpdates": "免除背景更新(若已啟用)",
"bgUpdatesOnWiFiOnly": "停用非 WiFi 的背景更新",
"bgUpdatesOnWiFiOnly": "停用非 Wi-Fi 的背景更新",
"bgUpdatesWhileChargingOnly": "Disable background updates when not charging",
"autoSelectHighestVersionCode": "自動選擇最高 versionCode 的 APK",
"versionExtractionRegEx": "版本字串提取正則表達式",
@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
"allowInsecure": "Allow insecure HTTP requests",
"stayOneVersionBehind": "Stay one version behind latest",
"refreshBeforeDownload": "Refresh app details before download",
"tencentAppStore": "騰訊應用寶",
"name": "Name",
"smartname": "Name (Smart)",
"sortMethod": "Sort Method",
"removeAppQuestion": {
"one": "移除應用程式?",
"other": "移除應用程式?"

View File

@@ -186,10 +186,10 @@
"additionalOptions": "附加选项",
"disableVersionDetection": "禁用版本检测",
"noVersionDetectionExplanation": "此选项应该仅用于无法进行版本检测的应用。",
"downloadingX": "正在下载{}",
"downloadingX": "正在下载 {}",
"downloadX": "下载 {}",
"downloadedX": "下载 {}",
"releaseAsset": "发行版附件",
"downloadedX": "下载 {}",
"releaseAsset": "发行件",
"downloadNotifDescription": "提示应用的下载进度",
"noAPKFound": "未找到 APK 文件",
"noVersionDetection": "禁用版本检测",
@@ -317,6 +317,11 @@
"crowdsourcedConfigsShort": "众包应用程序配置",
"allowInsecure": "允许不安全的 HTTP 请求",
"stayOneVersionBehind": "比最新版本晚一个版本",
"refreshBeforeDownload": "下载前刷新应用程序详细信息",
"tencentAppStore": "腾讯应用宝",
"name": "名称",
"smartname": "姓名(智能)",
"sortMethod": "排序方法",
"removeAppQuestion": {
"one": "是否删除应用?",
"other": "是否删除应用?"

View File

@@ -13,7 +13,6 @@
<li>F-Droid</li>
<li>Third Party F-Droid Repos</li>
<li>IzzyOnDroid</li>
<li>SourceForge</li>
<li>SourceHut</li>
</ul>
</li>
@@ -22,24 +21,17 @@
<ul>
<li>APKPure</li>
<li>Aptoide</li>
<li>Uptodowng</li>
<li>Uptodown</li>
<li>APKMirror (Track-Only)</li>
<li>Huawei AppGallery</li>
<li>Tencent App Store</li>
<li>Jenkins Jobs</li>
</ul>
</li>
<li>
<p>Open Source - App-Specific:</p>
<ul>
<li>Mullvad</li>
<li>Signal</li>
<li>VLC</li>
<li>RuStore</li>
</ul>
</li>
<li>
<p>Other - App-Specific:</p>
<ul>
<li>WhatsApp</li>
<li>Telegram App</li>
<li>Neutron Code</li>
</ul>

View File

@@ -13,7 +13,6 @@
<li>F-Droid</li>
<li>Third Party F-Droid Repos</li>
<li>IzzyOnDroid</li>
<li>SourceForge</li>
<li>SourceHut</li>
</ul>
</li>
@@ -22,24 +21,17 @@
<ul>
<li>APKPure</li>
<li>Aptoide</li>
<li>Uptodowng</li>
<li>Uptodown</li>
<li>APKMirror (Track-Only)</li>
<li>Huawei AppGallery</li>
<li>Tencent App Store</li>
<li>Jenkins Jobs</li>
</ul>
</li>
<li>
<p>Свободное ПО - Для отдельных приложений:</p>
<ul>
<li>Mullvad</li>
<li>Signal</li>
<li>VLC</li>
<li>RuStore</li>
</ul>
</li>
<li>
<p>Другие - Для отдельных приложений:</p>
<ul>
<li>WhatsApp</li>
<li>Telegram App</li>
<li>Neutron Code</li>
</ul>

View File

@@ -131,12 +131,18 @@ class APKPure extends AppSource {
throw NoAPKError();
}
String version = Uri.parse(link).pathSegments.last;
String author = html
.querySelector('span.info-sdk')
?.text
.trim()
.substring(version.length + 4) ??
Uri.parse(standardUrl).pathSegments.reversed.last;
String? author;
try {
author = html
.querySelector('span.info-sdk')
?.text
.trim()
.substring(version.length + 4) ??
Uri.parse(standardUrl).pathSegments.reversed.last;
} catch (e) {
author = html.querySelector('span.info-sdk')?.text.trim() ??
Uri.parse(standardUrl).pathSegments.reversed.last;
}
String appName =
html.querySelector('h1.info-title')?.text.trim() ?? appId;
String? changeLog = html

View File

@@ -75,8 +75,18 @@ class GitHub extends AppSource {
],
[GeneratedFormSwitch('verifyLatestTag', label: tr('verifyLatestTag'))],
[
GeneratedFormSwitch('dontSortReleasesList',
label: tr('dontSortReleasesList'))
GeneratedFormDropdown(
'sortMethodChoice',
[
MapEntry('date', tr('releaseDate')),
MapEntry('smartname', tr('smartname')),
MapEntry('none', tr('none')),
MapEntry('smartname-datefallback',
'${tr('smartname')} x ${tr('releaseDate')}'),
MapEntry('name', tr('name')),
],
label: tr('sortMethod'),
defaultValue: 'date')
],
[
GeneratedFormSwitch('useLatestAssetDateAsReleaseDate',
@@ -244,10 +254,10 @@ class GitHub extends AppSource {
? additionalSettings['filterReleaseNotesByRegEx']
: null;
bool verifyLatestTag = additionalSettings['verifyLatestTag'] == true;
bool dontSortReleasesList =
additionalSettings['dontSortReleasesList'] == true;
bool useLatestAssetDateAsReleaseDate =
additionalSettings['useLatestAssetDateAsReleaseDate'] == true;
String sortMethod =
additionalSettings['sortMethodChoice'] ?? 'smartname-datefallback';
dynamic latestRelease;
if (verifyLatestTag) {
var temp = requestUrl.split('?');
@@ -275,14 +285,15 @@ class GitHub extends AppSource {
}
}
List<MapEntry<String, String>> getReleaseAssetUrls(dynamic release) =>
findReleaseAssetUrls(dynamic release) =>
(release['assets'] as List<dynamic>?)?.map((e) {
var url = !e['name'].toString().toLowerCase().endsWith('.apk')
? (e['browser_download_url'] ?? e['url'])
: (e['url'] ?? e['browser_download_url']);
return (e['name'] != null) && (url != null)
e['final_url'] = (e['name'] != null) && (url != null)
? MapEntry(e['name'] as String, url as String)
: const MapEntry('', '');
return e;
}).toList() ??
[];
@@ -293,7 +304,9 @@ class GitHub extends AppSource {
? DateTime.parse(rel['commit']['created'])
: null;
DateTime? getNewestAssetDateFromRelease(dynamic rel) {
var t = (rel['assets'] as List<dynamic>?)
var allAssets = rel['assets'] as List<dynamic>?;
var filteredAssets = rel['filteredAssets'] as List<dynamic>?;
var t = (filteredAssets ?? allAssets)
?.map((e) {
return e?['updated_at'] != null
? DateTime.parse(e['updated_at'])
@@ -313,7 +326,7 @@ class GitHub extends AppSource {
? getPublishDateFromRelease(rel)
: getNewestAssetDateFromRelease(rel);
if (dontSortReleasesList) {
if (sortMethod == 'none') {
releases = releases.reversed.toList();
} else {
releases.sort((a, b) {
@@ -327,22 +340,30 @@ class GitHub extends AppSource {
} else {
var nameA = a['tag_name'] ?? a['name'];
var nameB = b['tag_name'] ?? b['name'];
var stdFormats = findStandardFormatsForVersion(nameA, true)
.intersection(findStandardFormatsForVersion(nameB, true));
if (stdFormats.isNotEmpty) {
var reg = RegExp(stdFormats.first);
var matchA = reg.firstMatch(nameA);
var matchB = reg.firstMatch(nameB);
return compareAlphaNumeric(
(nameA as String).substring(matchA!.start, matchA.end),
(nameB as String).substring(matchB!.start, matchB.end));
} else {
var stdFormats = findStandardFormatsForVersion(nameA, false)
.intersection(findStandardFormatsForVersion(nameB, false));
if (sortMethod == 'date' ||
(sortMethod == 'smartname-datefallback' &&
stdFormats.isEmpty)) {
return (getReleaseDateFromRelease(
a, useLatestAssetDateAsReleaseDate) ??
DateTime(1))
.compareTo(getReleaseDateFromRelease(
b, useLatestAssetDateAsReleaseDate) ??
DateTime(0));
} else {
if (sortMethod != 'name' && stdFormats.isNotEmpty) {
var reg = RegExp(stdFormats.last);
var matchA = reg.firstMatch(nameA);
var matchB = reg.firstMatch(nameB);
return compareAlphaNumeric(
(nameA as String).substring(matchA!.start, matchA.end),
(nameB as String).substring(matchB!.start, matchB.end));
} else {
// 'name'
return compareAlphaNumeric(
(nameA as String), (nameB as String));
}
}
}
});
@@ -387,18 +408,37 @@ class GitHub extends AppSource {
.hasMatch(((releases[i]['body'] as String?) ?? '').trim())) {
continue;
}
var allAssetUrls = getReleaseAssetUrls(releases[i]);
List<MapEntry<String, String>> apkUrls = allAssetUrls
.where((element) => element.key.toLowerCase().endsWith('.apk'))
var allAssetsWithUrls = findReleaseAssetUrls(releases[i]);
List<MapEntry<String, String>> allAssetUrls = allAssetsWithUrls
.map((e) => e['final_url'] as MapEntry<String, String>)
.toList();
var apkAssetsWithUrls = allAssetsWithUrls
.where((element) =>
(element['final_url'] as MapEntry<String, String>)
.key
.toLowerCase()
.endsWith('.apk'))
.toList();
apkUrls = filterApks(apkUrls, additionalSettings['apkFilterRegEx'],
var filteredApkUrls = filterApks(
apkAssetsWithUrls
.map((e) => e['final_url'] as MapEntry<String, String>)
.toList(),
additionalSettings['apkFilterRegEx'],
additionalSettings['invertAPKFilter']);
if (apkUrls.isEmpty && additionalSettings['trackOnly'] != true) {
var filteredApks = apkAssetsWithUrls
.where((e) => filteredApkUrls
.where((e2) =>
e2.key == (e['final_url'] as MapEntry<String, String>).key)
.isNotEmpty)
.toList();
if (filteredApks.isEmpty && additionalSettings['trackOnly'] != true) {
continue;
}
targetRelease = releases[i];
targetRelease['apkUrls'] = apkUrls;
targetRelease['apkUrls'] = filteredApkUrls;
targetRelease['filteredAssets'] = filteredApks;
targetRelease['version'] =
additionalSettings['releaseTitleAsVersion'] == true
? nameToFilter
@@ -420,6 +460,7 @@ class GitHub extends AppSource {
throw NoReleasesError();
}
String? version = targetRelease['version'];
DateTime? releaseDate = getReleaseDateFromRelease(
targetRelease, useLatestAssetDateAsReleaseDate);
if (version == null) {
@@ -478,7 +519,7 @@ class GitHub extends AppSource {
AppNames getAppNames(String standardUrl) {
String temp = standardUrl.substring(standardUrl.indexOf('://') + 3);
List<String> names = temp.substring(temp.indexOf('/') + 1).split('/');
return AppNames(names[0], names[1]);
return AppNames(names[0], names.sublist(1).join('/'));
}
Future<Map<String, List<String>>> searchCommon(

View File

@@ -53,8 +53,12 @@ class GitLab extends AppSource {
@override
String sourceSpecificStandardizeURL(String url, {bool forSelection = false}) {
var urlSegments = url.split('/');
var cutOffIndex = urlSegments.indexWhere((s) => s == '-');
url =
urlSegments.sublist(0, cutOffIndex <= 0 ? null : cutOffIndex).join('/');
RegExp standardUrlRegEx = RegExp(
'^https?://(www\\.)?${getSourceRegex(hosts)}/[^/]+/[^/]+',
'^https?://(www\\.)?${getSourceRegex(hosts)}/[^/]+(/[^((\b/\b)|(\b/-/\b))]+){1,20}',
caseSensitive: false);
RegExpMatch? match = standardUrlRegEx.firstMatch(url);
if (match == null) {
@@ -116,7 +120,7 @@ class GitLab extends AppSource {
Map<String, dynamic> additionalSettings) async {
String? PAT = await getPATIfAny(hostChanged ? additionalSettings : {});
String optionalAuth = (PAT != null) ? 'private_token=$PAT' : '';
return '$apkUrl?$optionalAuth';
return '$apkUrl${(Uri.parse(apkUrl).query.isEmpty ? '?' : '&')}$optionalAuth';
}
@override
@@ -126,6 +130,8 @@ class GitLab extends AppSource {
) async {
// Prepare request params
var names = GitHub().getAppNames(standardUrl);
String projectUriComponent =
'${Uri.encodeComponent(names.author)}%2F${Uri.encodeComponent(names.name)}';
String? PAT = await getPATIfAny(hostChanged ? additionalSettings : {});
String optionalAuth = (PAT != null) ? 'private_token=$PAT' : '';
@@ -133,7 +139,7 @@ class GitLab extends AppSource {
// Get project ID
Response res0 = await sourceRequest(
'https://${hosts[0]}/api/v4/projects/${names.author}%2F${names.name}?$optionalAuth',
'https://${hosts[0]}/api/v4/projects/$projectUriComponent?$optionalAuth',
additionalSettings);
if (res0.statusCode != 200) {
throw getObtainiumHttpError(res0);
@@ -145,7 +151,7 @@ class GitLab extends AppSource {
// Request data from REST API
Response res = await sourceRequest(
'https://${hosts[0]}/api/v4/projects/${names.author}%2F${names.name}/${trackOnly ? 'repository/tags' : 'releases'}?$optionalAuth',
'https://${hosts[0]}/api/v4/projects/$projectUriComponent/${trackOnly ? 'repository/tags' : 'releases'}?$optionalAuth',
additionalSettings);
if (res.statusCode != 200) {
throw getObtainiumHttpError(res);
@@ -157,30 +163,40 @@ class GitLab extends AppSource {
apkDetailsList = json.map((e) {
var apkUrlsFromAssets = (e['assets']?['links'] as List<dynamic>? ?? [])
.map((e) {
return (e['direct_asset_url'] ?? e['url'] ?? '') as String;
var url = (e['direct_asset_url'] ?? e['url'] ?? '') as String;
var parsedUrl = url.isNotEmpty ? Uri.parse(url) : null;
return MapEntry(
(e['name'] ??
(parsedUrl != null && parsedUrl.pathSegments.isNotEmpty
? parsedUrl.pathSegments.last
: 'unknown')) as String,
(e['direct_asset_url'] ?? e['url'] ?? '') as String);
})
.where((s) => s.isNotEmpty)
.where((s) => s.key.isNotEmpty)
.toList();
List<String> uploadedAPKsFromDescription =
((e['description'] ?? '') as String)
.split('](')
.join('\n')
.split('.apk)')
.join('.apk\n')
.split('\n')
.where((s) => s.startsWith('/uploads/') && s.endsWith('apk'))
.map((s) => 'https://${hosts[0]}/-/project/$projectId$s')
.toList();
var apkUrlsSet = apkUrlsFromAssets.toSet();
apkUrlsSet.addAll(uploadedAPKsFromDescription);
var uploadedAPKsFromDescription = ((e['description'] ?? '') as String)
.split('](')
.join('\n')
.split('.apk)')
.join('.apk\n')
.split('\n')
.where((s) => s.startsWith('/uploads/') && s.endsWith('apk'))
.map((s) => 'https://${hosts[0]}/-/project/$projectId$s')
.map((l) => MapEntry(Uri.parse(l).pathSegments.last, l))
.toList();
Map<String, String> apkUrls = {};
for (var entry in apkUrlsFromAssets) {
apkUrls[entry.key] = entry.value;
}
for (var entry in uploadedAPKsFromDescription) {
apkUrls[entry.key] = entry.value;
}
var releaseDateString =
e['released_at'] ?? e['created_at'] ?? e['commit']?['created_at'];
DateTime? releaseDate =
releaseDateString != null ? DateTime.parse(releaseDateString) : null;
return APKDetails(
e['tag_name'] ?? e['name'],
getApkUrlsFromUrls(apkUrlsSet.toList()),
GitHub().getAppNames(standardUrl),
return APKDetails(e['tag_name'] ?? e['name'], apkUrls.entries.toList(),
AppNames(names.author, names.name.split('/').last),
releaseDate: releaseDate);
});
if (apkDetailsList.isEmpty) {

View File

@@ -7,6 +7,9 @@ import 'package:obtainium/providers/apps_provider.dart';
import 'package:obtainium/providers/source_provider.dart';
String ensureAbsoluteUrl(String ambiguousUrl, Uri referenceAbsoluteUrl) {
if (ambiguousUrl.startsWith('//')) {
ambiguousUrl = '${referenceAbsoluteUrl.scheme}:$ambiguousUrl';
}
try {
Uri.parse(ambiguousUrl).origin;
return ambiguousUrl;
@@ -209,6 +212,10 @@ class HTML extends AppSource {
required: true,
additionalValidators: [(value) => regExValidator(value)])
],
[
GeneratedFormSwitch('autoApkFilterByArch',
label: tr('autoApkFilterByArch'), defaultValue: false)
],
];
HTML() {
additionalSourceAppSpecificSettingFormItems = [
@@ -310,8 +317,12 @@ class HTML extends AppSource {
await sourceRequest(currentUrl, additionalSettings),
additionalSettings['intermediateLink'][i]);
if (intLinks.isEmpty) {
throw NoReleasesError();
throw NoReleasesError(note: currentUrl);
} else {
if (additionalSettings['intermediateLink'][i]['autoApkFilterByArch'] ==
true) {
intLinks = await filterApksByArch(intLinks);
}
currentUrl = intLinks.last.key;
}
}
@@ -326,7 +337,7 @@ class HTML extends AppSource {
links = filterApks(links, additionalSettings['apkFilterRegEx'],
additionalSettings['invertAPKFilter']);
if (links.isEmpty) {
throw NoReleasesError();
throw NoReleasesError(note: currentUrl);
}
} else {
links = [MapEntry(currentUrl, currentUrl)];
@@ -353,7 +364,14 @@ class HTML extends AppSource {
forAPKDownload: true),
allowInsecure: additionalSettings['allowInsecure'] == true))
.toString();
return APKDetails(version, [rel].map((e) => MapEntry(e, e)).toList(),
return APKDetails(
version,
[rel].map((e) {
var uri = Uri.parse(e);
var fileName =
uri.pathSegments.isNotEmpty ? uri.pathSegments.last : uri.origin;
return MapEntry('${e.hashCode}-$fileName', e);
}).toList(),
AppNames(uri.host, tr('app')));
}
}

View File

@@ -0,0 +1,98 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_charset_detector/flutter_charset_detector.dart';
import 'package:http/http.dart';
import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/providers/source_provider.dart';
class RuStore extends AppSource {
RuStore() {
hosts = ['rustore.ru'];
name = 'RuStore';
naiveStandardVersionDetection = true;
showReleaseDateAsVersionToggle = true;
}
@override
String sourceSpecificStandardizeURL(String url, {bool forSelection = false}) {
RegExp standardUrlRegEx = RegExp(
'^https?://(www\\.)?${getSourceRegex(hosts)}/catalog/app/+[^/]+',
caseSensitive: false);
RegExpMatch? match = standardUrlRegEx.firstMatch(url);
if (match == null) {
throw InvalidURLError(name);
}
return match.group(0)!;
}
@override
Future<String?> tryInferringAppId(String standardUrl,
{Map<String, dynamic> additionalSettings = const {}}) async {
return Uri.parse(standardUrl).pathSegments.last;
}
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl,
Map<String, dynamic> additionalSettings,
) async {
String? appId = await tryInferringAppId(standardUrl);
Response res0 = await sourceRequest(
'https://backapi.rustore.ru/applicationData/overallInfo/$appId',
additionalSettings);
if (res0.statusCode != 200) {
throw getObtainiumHttpError(res0);
}
var appDetails = jsonDecode(res0.body)['body'];
if (appDetails['appId'] == null) {
throw NoReleasesError();
}
String appName = appDetails['appName'] ?? tr('app');
String author = appDetails['companyName'] ?? name;
String? dateStr = appDetails['updatedAt'];
String? version = appDetails['versionName'];
String? changeLog = appDetails['whatsNew'];
if (version == null) {
throw NoVersionError();
}
DateTime? relDate;
if (dateStr != null) {
relDate = DateTime.parse(dateStr);
}
Response res1 = await sourceRequest(
'https://backapi.rustore.ru/applicationData/download-link',
additionalSettings,
followRedirects: false,
postBody: {"appId": appDetails['appId'], "firstInstall": true});
var downloadDetails = jsonDecode(res1.body)['body'];
if (res1.statusCode != 200 || downloadDetails['apkUrl'] == null) {
throw NoAPKError();
}
appName = (await CharsetDetector.autoDecode(
Uint8List.fromList(appName.codeUnits)))
.string;
author =
(await CharsetDetector.autoDecode(Uint8List.fromList(author.codeUnits)))
.string;
changeLog = changeLog != null
? (await CharsetDetector.autoDecode(
Uint8List.fromList(changeLog.codeUnits)))
.string
: null;
return APKDetails(
version,
getApkUrlsFromUrls([
(downloadDetails['apkUrl'] as String)
.replaceAll(RegExp('\\.zip\$'), '.apk')
]),
AppNames(author, appName),
releaseDate: relDate,
changeLog: changeLog);
}
}

View File

@@ -33,7 +33,9 @@ class TelegramApp extends AppSource {
throw NoVersionError();
}
String? apkUrl = 'https://telegram.org/dl/android/apk';
return APKDetails(version, getApkUrlsFromUrls([apkUrl]),
return APKDetails(
version,
[MapEntry<String, String>('telegram-$version.apk', apkUrl)],
AppNames('Telegram', 'Telegram'));
} else {
throw getObtainiumHttpError(res);

View File

@@ -1,11 +1,12 @@
import 'dart:convert';
import 'package:easy_localization/easy_localization.dart';
import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/providers/source_provider.dart';
class Tencent extends AppSource {
Tencent() {
name = 'Tencent App Store';
name = tr('tencentAppStore');
hosts = ['sj.qq.com'];
naiveStandardVersionDetection = true;
showReleaseDateAsVersionToggle = true;
@@ -63,11 +64,11 @@ class Tencent extends AppSource {
var author = json['app_detail_records'][appId]['app_info']['author'];
var releaseDate =
json['app_detail_records'][appId]['app_info']['update_time'];
var apkName = Uri.parse(apkUrl).queryParameters['fsname'] ??
'${appId}_${version}.apk';
return APKDetails(
version,
[MapEntry(Uri.parse(apkUrl).queryParameters['fsname']!, apkUrl)],
AppNames(author, appName),
version, [MapEntry(apkName, apkUrl)], AppNames(author, appName),
releaseDate: releaseDate != null
? DateTime.fromMillisecondsSinceEpoch(releaseDate * 1000)
: null);

View File

@@ -1,110 +0,0 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:html/parser.dart';
import 'package:http/http.dart';
import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/providers/source_provider.dart';
class VLC extends AppSource {
VLC() {
hosts = ['videolan.org'];
}
get dwUrlBase => 'https://get.${hosts[0]}/vlc-android/';
@override
Future<Map<String, String>?> getRequestHeaders(
Map<String, dynamic> additionalSettings,
{bool forAPKDownload = false}) async {
return {
"User-Agent":
"Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36"
};
}
@override
String sourceSpecificStandardizeURL(String url, {bool forSelection = false}) {
return 'https://${hosts[0]}';
}
Future<String?> getLatestVersion(
String standardUrl, Map<String, dynamic> additionalSettings) async {
Response res = await sourceRequest(dwUrlBase, additionalSettings);
if (res.statusCode == 200) {
var dwLinks = parse(res.body)
.querySelectorAll('a')
.where((element) => element.attributes['href'] != 'last/')
.map((e) => e.attributes['href']?.split('/')[0])
.toList();
String? version = dwLinks.isNotEmpty ? dwLinks.last : null;
if (version == null) {
throw NoVersionError();
}
return version;
} else {
throw getObtainiumHttpError(res);
}
}
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl,
Map<String, dynamic> additionalSettings,
) async {
Response res = await get(
Uri.parse('https://www.videolan.org/vlc/download-android.html'));
if (res.statusCode == 200) {
var dwUrlBase = 'get.videolan.org/vlc-android';
var dwLinks = parse(res.body)
.querySelectorAll('a')
.where((element) =>
element.attributes['href']?.contains(dwUrlBase) ?? false)
.toList();
String? version = dwLinks.isNotEmpty
? dwLinks.first.attributes['href']
?.split('/')
.where((s) => s.isNotEmpty)
.last
: null;
if (version == null) {
throw NoVersionError();
}
String? targetUrl = 'https://$dwUrlBase/$version/';
var apkUrls = ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64']
.map((e) => '${targetUrl}VLC-Android-$version-$e.apk')
.toList();
return APKDetails(
version, getApkUrlsFromUrls(apkUrls), AppNames('VideoLAN', 'VLC'));
} else {
throw getObtainiumHttpError(res);
}
}
@override
Future<String> apkUrlPrefetchModifier(String apkUrl, String standardUrl,
Map<String, dynamic> additionalSettings) async {
Response res = await sourceRequest(apkUrl, additionalSettings);
if (res.statusCode == 200) {
String? apkUrl =
parse(res.body).querySelector('#alt_link')?.attributes['href'];
if (apkUrl == null) {
throw NoAPKError();
}
return apkUrl;
} else if (res.statusCode == 500 &&
res.body.toLowerCase().indexOf('mirror') > 0) {
var html = parse(res.body);
var err = '';
html.body?.nodes.forEach((element) {
if (element.text != null) {
err += '${element.text}\n';
}
});
err = err.trim();
if (err.isEmpty) {
err = tr('err');
}
throw ObtainiumError(err);
} else {
throw getObtainiumHttpError(res);
}
}
}

View File

@@ -1,55 +0,0 @@
import 'package:html/parser.dart';
import 'package:http/http.dart';
import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/providers/source_provider.dart';
class WhatsApp extends AppSource {
WhatsApp() {
hosts = ['whatsapp.com'];
versionDetectionDisallowed = true;
}
@override
String sourceSpecificStandardizeURL(String url, {bool forSelection = false}) {
return 'https://${hosts[0]}';
}
@override
Future<String> apkUrlPrefetchModifier(String apkUrl, String standardUrl,
Map<String, dynamic> additionalSettings) async {
Response res =
await sourceRequest('$standardUrl/android', additionalSettings);
if (res.statusCode == 200) {
var targetLinks = parse(res.body)
.querySelectorAll('a')
.map((e) => e.attributes['href'] ?? '')
.where((e) => e.isNotEmpty)
.where((e) => e.contains('WhatsApp.apk'))
.toList();
if (targetLinks.isEmpty) {
throw NoAPKError();
}
return targetLinks[0];
} else {
throw getObtainiumHttpError(res);
}
}
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl,
Map<String, dynamic> additionalSettings,
) async {
// This is a CDN link that is consistent per version
// But it has query params that change constantly
Uri apkUri = Uri.parse(await apkUrlPrefetchModifier(
standardUrl, standardUrl, additionalSettings));
var unusableApkUrl = '${apkUri.origin}/${apkUri.path}';
// So we use the param-less URL is a pseudo-version to add the app and check for updates
// See #357 for why we can't scrape the version number directly
// But we re-fetch the URL again with its latest query params at the actual download time
String version = unusableApkUrl.hashCode.toString();
return APKDetails(version, getApkUrlsFromUrls([unusableApkUrl]),
AppNames('Meta', 'WhatsApp'));
}
}

View File

@@ -23,7 +23,7 @@ import 'package:easy_localization/src/localization.dart';
List<MapEntry<Locale, String>> supportedLocales = const [
MapEntry(Locale('en'), 'English'),
MapEntry(Locale('zh'), '简体中文'),
MapEntry(Locale('zh_Hant_TW'), '臺灣話'),
MapEntry(Locale('zh', 'Hant_TW'), '臺灣話'),
MapEntry(Locale('it'), 'Italiano'),
MapEntry(Locale('ja'), '日本語'),
MapEntry(Locale('hu'), 'Magyar'),
@@ -44,7 +44,8 @@ List<MapEntry<Locale, String>> supportedLocales = const [
MapEntry(Locale('da'), 'Dansk'),
MapEntry(Locale('en', 'EO'),
'Esperanto'), // https://github.com/aissat/easy_localization/issues/220#issuecomment-846035493
MapEntry(Locale('in'), 'Bahasa Indonesia')
MapEntry(Locale('in'), 'Bahasa Indonesia'),
MapEntry(Locale('ko'), '한국어'),
];
const fallbackLocale = Locale('en');
const localeDir = 'assets/translations';
@@ -60,11 +61,11 @@ Future<void> loadTranslations() async {
var forceLocale = s.forcedLocale;
final controller = EasyLocalizationController(
saveLocale: true,
forceLocale: forceLocale != null ? Locale(forceLocale) : null,
forceLocale: forceLocale,
fallbackLocale: fallbackLocale,
supportedLocales: supportedLocales.map((e) => e.key).toList(),
assetLoader: const RootBundleAssetLoader(),
useOnlyLangCode: true,
useOnlyLangCode: false,
useFallbackTranslations: true,
path: localeDir,
onLoadError: (FlutterError e) {
@@ -118,7 +119,7 @@ void main() async {
supportedLocales: supportedLocales.map((e) => e.key).toList(),
path: localeDir,
fallbackLocale: fallbackLocale,
useOnlyLangCode: true,
useOnlyLangCode: false,
child: const Obtainium()),
));
BackgroundFetch.registerHeadlessTask(backgroundFetchHeadlessTask);
@@ -202,12 +203,9 @@ class _ObtainiumState extends State<Obtainium> {
});
}
}
if (!supportedLocales
.map((e) => e.key.languageCode)
.contains(context.locale.languageCode) ||
if (!supportedLocales.map((e) => e.key).contains(context.locale) ||
(settingsProvider.forcedLocale == null &&
context.deviceLocale.languageCode !=
context.locale.languageCode)) {
context.deviceLocale != context.locale)) {
settingsProvider.resetLocaleSafe(context);
}
}
@@ -244,22 +242,21 @@ class _ObtainiumState extends State<Obtainium> {
supportedLocales: context.supportedLocales,
locale: context.locale,
navigatorKey: globalNavigatorKey,
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
colorScheme: settingsProvider.theme == ThemeSettings.dark
? darkColorScheme
: lightColorScheme,
fontFamily: settingsProvider.useSystemFont
? 'SystemFont'
: 'Wix-Madefor-Display'),
fontFamily:
settingsProvider.useSystemFont ? 'SystemFont' : 'Montserrat'),
darkTheme: ThemeData(
useMaterial3: true,
colorScheme: settingsProvider.theme == ThemeSettings.light
? lightColorScheme
: darkColorScheme,
fontFamily: settingsProvider.useSystemFont
? 'SystemFont'
: 'Wix-Madefor-Display'),
fontFamily:
settingsProvider.useSystemFont ? 'SystemFont' : 'Montserrat'),
home: Shortcuts(shortcuts: <LogicalKeySet, Intent>{
LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(),
}, child: const HomePage()));

View File

@@ -1,6 +1,7 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:obtainium/components/generated_form_modal.dart';
import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/main.dart';
@@ -12,6 +13,7 @@ import 'package:obtainium/providers/source_provider.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:provider/provider.dart';
import 'package:markdown/markdown.dart' as md;
class AppPage extends StatefulWidget {
const AppPage({super.key, required this.appId});
@@ -23,9 +25,32 @@ class AppPage extends StatefulWidget {
}
class _AppPageState extends State<AppPage> {
late final WebViewController _webViewController;
bool _wasWebViewOpened = false;
AppInMemory? prevApp;
bool updating = false;
@override
void initState() {
super.initState();
_webViewController = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(
NavigationDelegate(
onWebResourceError: (WebResourceError error) {
if (error.isForMainFrame == true) {
showError(
ObtainiumError(error.description, unexpected: true), context);
}
},
onNavigationRequest: (NavigationRequest request) =>
request.url.startsWith("rustore://")
? NavigationDecision.prevent
: NavigationDecision.navigate,
),
);
}
@override
Widget build(BuildContext context) {
var appsProvider = context.watch<AppsProvider>();
@@ -79,6 +104,11 @@ class _AppPageState extends State<AppPage> {
(app?.app.installedVersion != null &&
app?.app.additionalSettings['versionDetection'] != true);
if (app != null && !_wasWebViewOpened) {
_wasWebViewOpened = true;
_webViewController.loadRequest(Uri.parse(app.app.url));
}
getInfoColumn() {
String versionLines = '';
bool installed = app?.app.installedVersion != null;
@@ -182,7 +212,10 @@ class _AppPageState extends State<AppPage> {
Brightness.light
? Theme.of(context).primaryColor
: Theme.of(context).primaryColorLight)
.withAlpha(20)
.withAlpha(Theme.of(context).brightness ==
Brightness.light
? 20
: 40)
: null),
padding: settingsProvider.highlightTouchTargets
? const EdgeInsetsDirectional.fromSTEB(12, 6, 12, 6)
@@ -218,24 +251,41 @@ class _AppPageState extends State<AppPage> {
if (app?.app.additionalSettings['about'] is String &&
app?.app.additionalSettings['about'].isNotEmpty)
Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(
height: 48,
),
GestureDetector(
onLongPress: () {
Clipboard.setData(ClipboardData(
text: app?.app.additionalSettings['about'] ?? ''));
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(tr('copiedToClipboard')),
));
},
child: Text(
app?.app.additionalSettings['about'],
textAlign: TextAlign.center,
style: const TextStyle(fontStyle: FontStyle.italic),
),
)
onLongPress: () {
Clipboard.setData(ClipboardData(
text: app?.app.additionalSettings['about'] ?? ''));
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(tr('copiedToClipboard')),
));
},
child: Markdown(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
styleSheet: MarkdownStyleSheet(
blockquoteDecoration:
BoxDecoration(color: Theme.of(context).cardColor),
textAlign: WrapAlignment.center),
data: app?.app.additionalSettings['about'],
onTapLink: (text, href, title) {
if (href != null) {
launchUrlString(href,
mode: LaunchMode.externalApplication);
}
},
extensionSet: md.ExtensionSet(
md.ExtensionSet.gitHubFlavored.blockSyntaxes,
[
md.EmojiSyntax(),
...md.ExtensionSet.gitHubFlavored.inlineSyntaxes
],
),
))
],
),
],
@@ -278,7 +328,7 @@ class _AppPageState extends State<AppPage> {
? Theme.of(context).textTheme.displaySmall
: Theme.of(context).textTheme.displayLarge,
),
Text(tr('byX', args: [app?.app.author ?? tr('unknown')]),
Text(tr('byX', args: [app?.author ?? tr('unknown')]),
textAlign: TextAlign.center,
style: small
? Theme.of(context).textTheme.headlineSmall
@@ -318,22 +368,9 @@ class _AppPageState extends State<AppPage> {
getAppWebView() => app != null
? WebViewWidget(
controller: WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(Theme.of(context).colorScheme.surface)
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(
NavigationDelegate(
onWebResourceError: (WebResourceError error) {
if (error.isForMainFrame == true) {
showError(
ObtainiumError(error.description, unexpected: true),
context);
}
},
),
)
..loadRequest(Uri.parse(app.app.url)))
key: ObjectKey(_webViewController),
controller: _webViewController
..setBackgroundColor(Theme.of(context).colorScheme.surface))
: Container();
showMarkUpdatedDialog() {

View File

@@ -60,6 +60,9 @@ showChangeLogDialog(BuildContext context, App app, String? changesUrl,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height - 350,
child: Markdown(
styleSheet: MarkdownStyleSheet(
blockquoteDecoration: BoxDecoration(
color: Theme.of(context).cardColor)),
data: changeLog,
onTapLink: (text, href, title) {
if (href != null) {
@@ -213,7 +216,7 @@ class AppsPageState extends State<AppsPage> {
}
}
for (var t in authorTokens) {
if (!app.app.author.toLowerCase().contains(t.toLowerCase())) {
if (!app.author.toLowerCase().contains(t.toLowerCase())) {
return false;
}
}
@@ -244,11 +247,11 @@ class AppsPageState extends State<AppsPage> {
listedApps.sort((a, b) {
int result = 0;
if (settingsProvider.sortColumn == SortColumnSettings.authorName) {
result = ((a.app.author + a.name).toLowerCase())
.compareTo((b.app.author + b.name).toLowerCase());
result = ((a.author + a.name).toLowerCase())
.compareTo((b.author + b.name).toLowerCase());
} else if (settingsProvider.sortColumn == SortColumnSettings.nameAuthor) {
result = ((a.name + a.app.author).toLowerCase())
.compareTo((b.name + b.app.author).toLowerCase());
result = ((a.name + a.author).toLowerCase())
.compareTo((b.name + b.author).toLowerCase());
} else if (settingsProvider.sortColumn ==
SortColumnSettings.releaseDate) {
result = (a.app.releaseDate)?.compareTo(
@@ -481,7 +484,10 @@ class AppsPageState extends State<AppsPage> {
? (Theme.of(context).brightness == Brightness.light
? Theme.of(context).primaryColor
: Theme.of(context).primaryColorLight)
.withAlpha(20)
.withAlpha(Theme.of(context).brightness ==
Brightness.light
? 20
: 40)
: null),
padding: settingsProvider.highlightTouchTargets
? const EdgeInsetsDirectional.fromSTEB(12, 0, 12, 0)
@@ -521,12 +527,12 @@ class AppsPageState extends State<AppsPage> {
var transparent =
Theme.of(context).colorScheme.surface.withAlpha(0).value;
List<double> stops = [
...listedApps[index].app.categories.asMap().entries.map(
(e) => ((e.key / (listedApps[index].app.categories.length - 1)))),
...listedApps[index].app.categories.asMap().entries.map((e) =>
((e.key / (listedApps[index].app.categories.length - 1)) - 0.0001)),
1
];
if (stops.length == 2) {
stops[0] = 1;
stops[0] = 0.9999;
}
return Container(
decoration: BoxDecoration(
@@ -564,7 +570,7 @@ class AppsPageState extends State<AppsPage> {
: FontWeight.normal,
),
),
subtitle: Text(tr('byX', args: [listedApps[index].app.author]),
subtitle: Text(tr('byX', args: [listedApps[index].author]),
maxLines: 1,
style: TextStyle(
overflow: TextOverflow.ellipsis,
@@ -838,30 +844,6 @@ class AppsPageState extends State<AppsPage> {
Navigator.of(context).pop();
}
resetSelectedAppsInstallStatuses() async {
try {
var values = await showDialog(
context: context,
builder: (BuildContext ctx) {
return GeneratedFormModal(
title: tr('resetInstallStatusForSelectedAppsQuestion'),
items: const [],
initValid: true,
message: tr('installStatusOfXWillBeResetExplanation',
args: [plural('apps', selectedAppIds.length)]),
);
});
if (values != null) {
appsProvider.saveApps(selectedApps.map((e) {
e.installedVersion = null;
return e;
}).toList());
}
} finally {
Navigator.of(context).pop();
}
}
showMoreOptionsDialog() {
return showDialog(
context: context,
@@ -929,13 +911,15 @@ class AppsPageState extends State<AppsPage> {
.map((e) => e.id)
.toList(),
overrideExportSettings: false));
String fn =
'${tr('obtainiumExportHyphenatedLowercase')}-${DateTime.now().toIso8601String().replaceAll(':', '-')}-count-${selectedApps.length}';
XFile f = XFile.fromData(
Uint8List.fromList(
utf8.encode(exportJSON)),
mimeType: 'application/json',
name:
'${tr('obtainiumExportHyphenatedLowercase')}-${selectedApps.length}-${DateTime.now().millisecondsSinceEpoch}');
Share.shareXFiles([f]);
name: fn);
Share.shareXFiles([f],
fileNameOverrides: ['$fn.json']);
},
child: Text(
'${tr('share')} - ${tr('obtainiumExport')}')),

View File

@@ -130,13 +130,18 @@ class _HomePageState extends State<HomePage> {
// Check initial link if app was in cold state (terminated)
final appLink = await _appLinks.getInitialLink();
var initLinked = false;
if (appLink != null) {
await interpretLink(appLink);
initLinked = true;
}
// Handle link when app is in warm state (front or background)
_linkSubscription = _appLinks.uriLinkStream.listen((uri) async {
await interpretLink(uri);
if (!initLinked) {
await interpretLink(uri);
} else {
initLinked = false;
}
});
}

View File

@@ -262,14 +262,14 @@ class _SettingsPageState extends State<SettingsPage> {
child: Text(tr('followSystem')),
),
...supportedLocales.map((e) => DropdownMenuItem(
value: e.key.toLanguageTag(),
value: e.key,
child: Text(e.value),
))
],
onChanged: (value) {
settingsProvider.forcedLocale = value;
if (value != null) {
context.setLocale(Locale(value));
context.setLocale(value);
} else {
settingsProvider.resetLocaleSafe(context);
}

View File

@@ -9,6 +9,7 @@ import 'package:battery_plus/battery_plus.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:http/http.dart' as http;
import 'package:crypto/crypto.dart';
import 'dart:typed_data';
import 'package:android_intent_plus/flag.dart';
import 'package:android_package_installer/android_package_installer.dart';
@@ -19,6 +20,8 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:http/io_client.dart';
import 'package:obtainium/app_sources/directAPKLink.dart';
import 'package:obtainium/app_sources/html.dart';
import 'package:obtainium/components/generated_form.dart';
import 'package:obtainium/components/generated_form_modal.dart';
import 'package:obtainium/custom_errors.dart';
@@ -51,6 +54,7 @@ class AppInMemory {
AppInMemory(app.deepCopy(), downloadProgress, installedInfo, icon);
String get name => app.overrideName ?? app.finalName;
String get author => app.overrideAuthor ?? app.finalAuthor;
}
class DownloadedApk {
@@ -149,13 +153,15 @@ Future<File> downloadFileWithRetry(String url, String fileName,
{bool useExisting = true,
Map<String, String>? headers,
int retries = 3,
bool allowInsecure = false}) async {
bool allowInsecure = false,
LogsProvider? logs}) async {
try {
return await downloadFile(
url, fileName, fileNameHasExt, onProgress, destDir,
useExisting: useExisting,
headers: headers,
allowInsecure: allowInsecure);
allowInsecure: allowInsecure,
logs: logs);
} catch (e) {
if (retries > 0 && e is ClientException) {
await Future.delayed(const Duration(seconds: 5));
@@ -164,7 +170,8 @@ Future<File> downloadFileWithRetry(String url, String fileName,
useExisting: useExisting,
headers: headers,
retries: (retries - 1),
allowInsecure: allowInsecure);
allowInsecure: allowInsecure,
logs: logs);
} else {
rethrow;
}
@@ -217,7 +224,8 @@ Future<File> downloadFile(String url, String fileName, bool fileNameHasExt,
Function? onProgress, String destDir,
{bool useExisting = true,
Map<String, String>? headers,
bool allowInsecure = false}) async {
bool allowInsecure = false,
LogsProvider? logs}) async {
// Send the initial request but cancel it as soon as you have the headers
var reqHeaders = headers ?? {};
var req = Request('GET', Uri.parse(url));
@@ -278,6 +286,42 @@ Future<File> downloadFile(String url, String fileName, bool fileNameHasExt,
// Download to a '.temp' file (to distinguish btn. complete/incomplete files)
File tempDownloadedFile = File('${downloadedFile.path}.part');
// If there is already a temp file, a download may already be in progress - account for this (see #2073)
bool tempFileExists = tempDownloadedFile.existsSync();
if (tempFileExists && useExisting) {
logs?.add(
'Partial download exists - will wait: ${tempDownloadedFile.uri.pathSegments.last}');
bool isDownloading = true;
int currentTempFileSize = await tempDownloadedFile.length();
bool shouldReturn = false;
while (isDownloading) {
await Future.delayed(Duration(seconds: 7));
if (tempDownloadedFile.existsSync()) {
int newTempFileSize = await tempDownloadedFile.length();
if (newTempFileSize > currentTempFileSize) {
currentTempFileSize = newTempFileSize;
logs?.add(
'Existing partial download still in progress: ${tempDownloadedFile.uri.pathSegments.last}');
} else {
logs?.add(
'Ignoring existing partial download: ${tempDownloadedFile.uri.pathSegments.last}');
break;
}
} else {
shouldReturn = downloadedFile.existsSync();
}
}
if (shouldReturn) {
logs?.add(
'Existing partial download completed - not repeating: ${tempDownloadedFile.uri.pathSegments.last}');
client.close();
return downloadedFile;
} else {
logs?.add(
'Existing partial download not in progress: ${tempDownloadedFile.uri.pathSegments.last}');
}
}
// If the range feature is not available (or you need to start a ranged req from 0),
// complete the already-started request, else cancel it and start a ranged request,
// and open the file for writing in the appropriate mode
@@ -302,18 +346,44 @@ Future<File> downloadFile(String url, String fileName, bool fileNameHasExt,
// Perform the download
var received = 0;
double? progress;
DateTime? lastProgressUpdate; // Track last progress update time
if (rangeStart > 0 && fullContentLength != null) {
received = rangeStart;
}
await response.stream.map((s) {
received += s.length;
progress =
(fullContentLength != null ? (received / fullContentLength) * 100 : 30);
if (onProgress != null) {
onProgress(progress);
}
return s;
}).pipe(sink);
const downloadUIUpdateInterval = Duration(milliseconds: 500);
const downloadBufferSize = 32 * 1024; // 32KB
final downloadBuffer = BytesBuilder();
await response.stream
.map((chunk) {
received += chunk.length;
final now = DateTime.now();
if (onProgress != null &&
(lastProgressUpdate == null ||
now.difference(lastProgressUpdate!) >=
downloadUIUpdateInterval)) {
progress = fullContentLength != null
? (received / fullContentLength) * 100
: 30;
onProgress(progress);
lastProgressUpdate = now;
}
return chunk;
})
.transform(StreamTransformer<List<int>, List<int>>.fromHandlers(
handleData: (List<int> data, EventSink<List<int>> s) {
downloadBuffer.add(data);
if (downloadBuffer.length >= downloadBufferSize) {
s.add(downloadBuffer.takeBytes());
}
},
handleDone: (EventSink<List<int>> s) {
if (downloadBuffer.isNotEmpty) {
s.add(downloadBuffer.takeBytes());
}
s.close();
},
))
.pipe(sink);
await sink.close();
progress = null;
if (onProgress != null) {
@@ -417,9 +487,7 @@ class AppsProvider with ChangeNotifier {
// Delete any partial APKs (if safe to do so)
var cutoff = DateTime.now().subtract(const Duration(days: 7));
APKDir.listSync()
.where((element) =>
element.path.endsWith('.part') ||
element.statSync().modified.isBefore(cutoff))
.where((element) => element.statSync().modified.isBefore(cutoff))
.forEach((partialApk) {
if (!areDownloadsRunning()) {
partialApk.delete(recursive: true);
@@ -493,7 +561,8 @@ class AppsProvider with ChangeNotifier {
prevProg = prog;
}, APKDir.path,
useExisting: useExisting,
allowInsecure: app.additionalSettings['allowInsecure'] == true);
allowInsecure: app.additionalSettings['allowInsecure'] == true,
logs: logs);
// Set to 90 for remaining steps, will make null in 'finally'
if (apps[app.id] != null) {
apps[app.id]!.downloadProgress = -1;
@@ -888,6 +957,11 @@ class AppsProvider with ChangeNotifier {
}
MapEntry<String, String>? apkUrl;
var trackOnly = apps[id]!.app.additionalSettings['trackOnly'] == true;
var refreshBeforeDownload =
apps[id]!.app.additionalSettings['refreshBeforeDownload'] == true;
if (refreshBeforeDownload) {
await checkUpdate(apps[id]!.app.id);
}
if (!trackOnly) {
// ignore: use_build_context_synchronously
apkUrl = await confirmAppFileUrl(apps[id]!.app, context, false);
@@ -1074,6 +1148,11 @@ class AppsProvider with ChangeNotifier {
throw ObtainiumError(tr('appNotFound'));
}
MapEntry<String, String>? fileUrl;
var refreshBeforeDownload =
apps[id]!.app.additionalSettings['refreshBeforeDownload'] == true;
if (refreshBeforeDownload) {
await checkUpdate(apps[id]!.app.id);
}
if (apps[id]!.app.apkUrls.isNotEmpty ||
apps[id]!.app.otherAssetUrls.isNotEmpty) {
// ignore: use_build_context_synchronously
@@ -1112,7 +1191,8 @@ class AppsProvider with ChangeNotifier {
forAPKDownload:
fileUrl.key.endsWith('.apk') ? true : false),
useExisting: false,
allowInsecure: app.additionalSettings['allowInsecure'] == true);
allowInsecure: app.additionalSettings['allowInsecure'] == true,
logs: logs);
notificationsProvider
.notify(DownloadedNotification(fileUrl.key, fileUrl.value));
} catch (e) {
@@ -1149,17 +1229,25 @@ class AppsProvider with ChangeNotifier {
if (app?.app == null) {
return false;
}
var source = SourceProvider()
.getSource(app!.app.url, overrideSource: app.app.overrideSource);
var naiveStandardVersionDetection =
app!.app.additionalSettings['naiveStandardVersionDetection'] == true ||
SourceProvider()
.getSource(app.app.url, overrideSource: app.app.overrideSource)
.naiveStandardVersionDetection;
app.app.additionalSettings['naiveStandardVersionDetection'] == true ||
source.naiveStandardVersionDetection;
String? realInstalledVersion =
app.app.additionalSettings['useVersionCodeAsOSVersion'] == true
? app.installedInfo?.versionCode.toString()
: app.installedInfo?.versionName;
bool isHTMLWithNoVersionDetection =
(source.runtimeType == HTML().runtimeType &&
(app.app.additionalSettings['versionExtractionRegEx'] as String?)
?.isNotEmpty !=
true);
bool isDirectAPKLink = source.runtimeType == DirectAPKLink().runtimeType;
return app.app.additionalSettings['trackOnly'] != true &&
app.app.additionalSettings['releaseDateAsVersion'] != true &&
!isHTMLWithNoVersionDetection &&
!isDirectAPKLink &&
realInstalledVersion != null &&
app.app.installedVersion != null &&
(reconcileVersionDifferences(
@@ -1230,6 +1318,7 @@ class AppsProvider with ChangeNotifier {
!isVersionDetectionPossible(
AppInMemory(app, null, installedInfo, null))) {
app.additionalSettings['versionDetection'] = false;
app.installedVersion = app.latestVersion;
logs.add('Could not reconcile version formats for: ${app.id}');
modded = true;
}
@@ -1393,8 +1482,10 @@ class AppsProvider with ChangeNotifier {
app = getCorrectedInstallStatusAppIfPossible(app, info) ?? app;
}
if (!onlyIfExists || this.apps.containsKey(app.id)) {
File('${(await getAppsDir()).path}/${app.id}.json')
.writeAsStringSync(jsonEncode(app.toJson()));
String filePath = '${(await getAppsDir()).path}/${app.id}.json';
File('$filePath.tmp')
.writeAsStringSync(jsonEncode(app.toJson())); // #2089
File('$filePath.tmp').renameSync(filePath);
}
try {
this.apps.update(app.id,

View File

@@ -3,6 +3,7 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:obtainium/providers/settings_provider.dart';
import 'package:obtainium/providers/source_provider.dart';
class ObtainiumNotification {
@@ -44,23 +45,19 @@ class SilentUpdateNotification extends ObtainiumNotification {
SilentUpdateNotification(List<App> updates, bool succeeded, {int? id})
: super(
id ?? 3,
succeeded
? tr('appsUpdated')
: tr('appsNotUpdated'),
succeeded ? tr('appsUpdated') : tr('appsNotUpdated'),
'',
'APPS_UPDATED',
tr('appsUpdatedNotifChannel'),
tr('appsUpdatedNotifDescription'),
Importance.defaultImportance) {
message = updates.length == 1
? tr(succeeded
? 'xWasUpdatedToY'
: 'xWasNotUpdatedToY',
args: [updates[0].finalName, updates[0].latestVersion])
: plural(succeeded
? 'xAndNMoreUpdatesInstalled'
: "xAndNMoreUpdatesFailed",
updates.length - 1, args: [updates[0].finalName, (updates.length - 1).toString()]);
? tr(succeeded ? 'xWasUpdatedToY' : 'xWasNotUpdatedToY',
args: [updates[0].finalName, updates[0].latestVersion])
: plural(
succeeded ? 'xAndNMoreUpdatesInstalled' : "xAndNMoreUpdatesFailed",
updates.length - 1,
args: [updates[0].finalName, (updates.length - 1).toString()]);
}
}
@@ -214,7 +211,7 @@ class NotificationsProvider {
channelDescription: channelDescription,
importance: importance,
priority: importanceToPriority[importance]!,
groupKey: 'dev.imranr.obtainium.$channelCode',
groupKey: '$obtainiumId.$channelCode',
progress: progPercent ?? 0,
maxProgress: 100,
showProgress: progPercent != null,

View File

@@ -261,22 +261,24 @@ class SettingsProvider with ChangeNotifier {
notifyListeners();
}
String? get forcedLocale {
var fl = prefs?.getString('forcedLocale');
return supportedLocales
.where((element) => element.key.toLanguageTag() == fl)
.isNotEmpty
Locale? get forcedLocale {
var flSegs = prefs?.getString('forcedLocale')?.split('-');
var fl = flSegs != null && flSegs.isNotEmpty
? Locale(flSegs[0], flSegs.length > 1 ? flSegs[1] : null)
: null;
var set = supportedLocales.where((element) => element.key == fl).isNotEmpty
? fl
: null;
return set;
}
set forcedLocale(String? fl) {
set forcedLocale(Locale? fl) {
if (fl == null) {
prefs?.remove('forcedLocale');
} else if (supportedLocales
.where((element) => element.key.toLanguageTag() == fl)
.where((element) => element.key == fl)
.isNotEmpty) {
prefs?.setString('forcedLocale', fl);
prefs?.setString('forcedLocale', fl.toLanguageTag());
}
notifyListeners();
}
@@ -285,9 +287,7 @@ class SettingsProvider with ChangeNotifier {
a.length == b.length && a.union(b).length == a.length;
void resetLocaleSafe(BuildContext context) {
if (context.supportedLocales
.map((e) => e.languageCode)
.contains(context.deviceLocale.languageCode)) {
if (context.supportedLocales.contains(context.deviceLocale)) {
context.resetLocale();
} else {
context.setLocale(context.fallbackLocale!);

View File

@@ -23,16 +23,16 @@ import 'package:obtainium/app_sources/izzyondroid.dart';
import 'package:obtainium/app_sources/html.dart';
import 'package:obtainium/app_sources/jenkins.dart';
import 'package:obtainium/app_sources/neutroncode.dart';
import 'package:obtainium/app_sources/rustore.dart';
import 'package:obtainium/app_sources/sourceforge.dart';
import 'package:obtainium/app_sources/sourcehut.dart';
import 'package:obtainium/app_sources/telegramapp.dart';
import 'package:obtainium/app_sources/tencent.dart';
import 'package:obtainium/app_sources/uptodown.dart';
import 'package:obtainium/app_sources/vlc.dart';
import 'package:obtainium/app_sources/whatsapp.dart';
import 'package:obtainium/components/generated_form.dart';
import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/mass_app_sources/githubstars.dart';
import 'package:obtainium/providers/logs_provider.dart';
import 'package:obtainium/providers/settings_provider.dart';
class AppNames {
@@ -152,11 +152,11 @@ appJSONCompatibilityModifiers(Map<String, dynamic> json) {
if (additionalSettings['autoApkFilterByArch'] == null) {
additionalSettings['autoApkFilterByArch'] = false;
}
// GitHub "don't sort" option to new dropdown format
if (additionalSettings['dontSortReleasesList'] == true) {
additionalSettings['sortMethodChoice'] = 'none';
}
if (source.runtimeType == HTML().runtimeType) {
// HTML 'fixed URL' support should be disabled if it previously did not exist
if (originalAdditionalSettings['supportFixedAPKURL'] == null) {
additionalSettings['supportFixedAPKURL'] = false;
}
// HTML key rename
if (originalAdditionalSettings['sortByFileNamesNotLinks'] != null) {
additionalSettings['sortByLastLinkSegment'] =
@@ -214,6 +214,56 @@ appJSONCompatibilityModifiers(Map<String, dynamic> json) {
'\\d+.\\d+.\\d+';
additionalSettings = replacementAdditionalSettings;
}
// WhatsApp from before it was removed should be converted to HTML (#1943)
if (json['url'] == 'https://whatsapp.com' &&
json['id'] == 'com.whatsapp' &&
json['author'] == 'Meta' &&
json['name'] == 'WhatsApp' &&
json['overrideSource'] == null &&
additionalSettings['trackOnly'] == false &&
additionalSettings['versionExtractionRegEx'] == '' &&
json['lastUpdateCheck'] != null) {
json['url'] = 'https://whatsapp.com/android';
var replacementAdditionalSettings = getDefaultValuesFromFormItems(
HTML().combinedAppSpecificSettingFormItems);
replacementAdditionalSettings['refreshBeforeDownload'] = true;
additionalSettings = replacementAdditionalSettings;
}
// VLC from before it was removed should be converted to HTML (#1943)
if (json['url'] == 'https://videolan.org' &&
json['id'] == 'org.videolan.vlc' &&
json['author'] == 'VideoLAN' &&
json['name'] == 'VLC' &&
json['overrideSource'] == null &&
additionalSettings['trackOnly'] == false &&
additionalSettings['versionExtractionRegEx'] == '' &&
json['lastUpdateCheck'] != null) {
json['url'] = 'https://www.videolan.org/vlc/download-android.html';
var replacementAdditionalSettings = getDefaultValuesFromFormItems(
HTML().combinedAppSpecificSettingFormItems);
replacementAdditionalSettings['refreshBeforeDownload'] = true;
replacementAdditionalSettings['intermediateLink'] =
<Map<String, dynamic>>[
{
'customLinkFilterRegex': 'APK',
'filterByLinkText': true,
'skipSort': false,
'reverseSort': false,
'sortByLastLinkSegment': false
},
{
'customLinkFilterRegex': 'arm64-v8a\\.apk\$',
'filterByLinkText': false,
'skipSort': false,
'reverseSort': false,
'sortByLastLinkSegment': false
}
];
replacementAdditionalSettings['versionExtractionRegEx'] =
'/vlc-android/([^/]+)/';
replacementAdditionalSettings['matchGroupToUse'] = "1";
additionalSettings = replacementAdditionalSettings;
}
}
json['additionalSettings'] = jsonEncode(additionalSettings);
// F-Droid no longer needs cloudflare exception since override can be used - migrate apps appropriately
@@ -240,7 +290,7 @@ class App {
late String name;
String? installedVersion;
late String latestVersion;
List<MapEntry<String, String>> apkUrls = [];
List<MapEntry<String, String>> apkUrls = []; // Key is name, value is URL
List<MapEntry<String, String>> otherAssetUrls = [];
late int preferredApkIndex;
late Map<String, dynamic> additionalSettings;
@@ -284,6 +334,15 @@ class App {
return overrideName ?? name;
}
String? get overrideAuthor =>
additionalSettings['appAuthor']?.toString().trim().isNotEmpty == true
? additionalSettings['appAuthor']
: null;
String get finalAuthor {
return overrideAuthor ?? author;
}
App deepCopy() => App(
id,
url,
@@ -304,7 +363,14 @@ class App {
otherAssetUrls: otherAssetUrls);
factory App.fromJson(Map<String, dynamic> json) {
json = appJSONCompatibilityModifiers(json);
Map<String, dynamic> originalJSON = new Map.from(json);
try {
json = appJSONCompatibilityModifiers(json);
} catch (e) {
json = originalJSON;
LogsProvider().add(
'Error running JSON compat modifiers: ${e.toString()}: ${originalJSON.toString()}');
}
return App(
json['id'] as String,
json['url'] as String,
@@ -412,6 +478,23 @@ List<MapEntry<String, String>> getApkUrlsFromUrls(List<String> urls) =>
return MapEntry(apkSegs.isNotEmpty ? apkSegs.last : segments.last, e);
}).toList();
Future<List<MapEntry<String, String>>> filterApksByArch(
List<MapEntry<String, String>> apkUrls) async {
if (apkUrls.length > 1) {
var abis = (await DeviceInfoPlugin().androidInfo).supportedAbis;
for (var abi in abis) {
var urls2 = apkUrls
.where((element) => RegExp('.*$abi.*').hasMatch(element.key))
.toList();
if (urls2.isNotEmpty && urls2.length < apkUrls.length) {
apkUrls = urls2;
break;
}
}
}
return apkUrls;
}
getSourceRegex(List<String> hosts) {
return '(${hosts.join('|').replaceAll('.', '\\.')})';
}
@@ -569,6 +652,7 @@ abstract class AppSource {
label: tr('autoApkFilterByArch'), defaultValue: true)
],
[GeneratedFormTextField('appName', label: tr('appName'), required: false)],
[GeneratedFormTextField('appAuthor', label: tr('author'), required: false)],
[
GeneratedFormSwitch('shizukuPretendToBeGooglePlay',
label: tr('shizukuPretendToBeGooglePlay'), defaultValue: false)
@@ -586,6 +670,10 @@ abstract class AppSource {
label: tr('skipUpdateNotifications'))
],
[GeneratedFormTextField('about', label: tr('about'), required: false)],
[
GeneratedFormSwitch('refreshBeforeDownload',
label: tr('refreshBeforeDownload'))
]
];
// Previous 2 variables combined into one at runtime for convenient usage
@@ -808,8 +896,7 @@ class SourceProvider {
Tencent(),
Jenkins(),
APKMirror(),
VLC(),
WhatsApp(),
RuStore(),
TelegramApp(),
NeutronCode(),
DirectAPKLink(),
@@ -918,18 +1005,8 @@ class SourceProvider {
if (apk.apkUrls.isEmpty && !trackOnly) {
throw NoAPKError();
}
if (apk.apkUrls.length > 1 &&
additionalSettings['autoApkFilterByArch'] == true) {
var abis = (await DeviceInfoPlugin().androidInfo).supportedAbis;
for (var abi in abis) {
var urls2 = apk.apkUrls
.where((element) => RegExp('.*$abi.*').hasMatch(element.key))
.toList();
if (urls2.isNotEmpty && urls2.length < apk.apkUrls.length) {
apk.apkUrls = urls2;
break;
}
}
if (additionalSettings['autoApkFilterByArch'] == true) {
apk.apkUrls = await filterApksByArch(apk.apkUrls);
}
var name = currentApp != null ? currentApp.name.trim() : '';
name = name.isNotEmpty ? name : apk.names.name;

View File

@@ -5,26 +5,27 @@ packages:
dependency: "direct main"
description:
name: android_intent_plus
sha256: "38921ec22ebb3b9a7eb678792cf6fab0b6f458b61b9d327688573449c9b47db3"
sha256: dfc1fd3a577205ae8f11e990fb4ece8c90cceabbee56fcf48e463ecf0bd6aae3
url: "https://pub.dev"
source: hosted
version: "5.2.0"
version: "5.3.0"
android_package_installer:
dependency: "direct main"
description:
path: "."
ref: main
resolved-ref: bcad19e964d377da8816718032e5dbf6dd16ba3a
resolved-ref: "6109d0b1dc015c016e113ded3dd80ac823f790ab"
url: "https://github.com/ImranR98/android_package_installer"
source: git
version: "0.0.1"
android_package_manager:
dependency: "direct main"
description:
name: android_package_manager
sha256: "2de859fae7226a7de1c1ff9a2308f1967599408800330501a1ce97927c051153"
url: "https://pub.dev"
source: hosted
path: "."
ref: master
resolved-ref: "18231a8a2343747440b0bfe90f7d56ef7f586099"
url: "https://github.com/ImranR98/android_package_manager"
source: git
version: "0.7.1"
android_system_font:
dependency: "direct main"
@@ -47,10 +48,10 @@ packages:
dependency: "direct main"
description:
name: app_links
sha256: ad1a6d598e7e39b46a34f746f9a8b011ee147e4c275d407fa457e7a62f84dd99
sha256: "85ed8fc1d25a76475914fff28cc994653bd900bc2c26e4b57a49e097febb54ba"
url: "https://pub.dev"
source: hosted
version: "6.3.2"
version: "6.4.0"
app_links_linux:
dependency: transitive
description:
@@ -79,10 +80,10 @@ packages:
dependency: transitive
description:
name: archive
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
sha256: "0c64e928dcbefddecd234205422bcfc2b5e6d31be0b86fef0d0dd48d7b4c9742"
url: "https://pub.dev"
source: hosted
version: "3.6.1"
version: "4.0.4"
args:
dependency: transitive
description:
@@ -95,10 +96,10 @@ packages:
dependency: transitive
description:
name: async
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
url: "https://pub.dev"
source: hosted
version: "2.11.0"
version: "2.12.0"
background_fetch:
dependency: "direct main"
description:
@@ -111,10 +112,10 @@ packages:
dependency: "direct main"
description:
name: battery_plus
sha256: "220c8f1961efb01d6870493b5ac5a80afaeaffc8757f7a11ed3025a8570d29e7"
sha256: a0409fe7d21905987eb1348ad57c634f913166f14f0c8936b73d3f5940fac551
url: "https://pub.dev"
source: hosted
version: "6.2.0"
version: "6.2.1"
battery_plus_platform_interface:
dependency: transitive
description:
@@ -127,18 +128,18 @@ packages:
dependency: transitive
description:
name: boolean_selector
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
version: "2.1.2"
characters:
dependency: transitive
description:
name: characters
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.4.0"
checked_yaml:
dependency: transitive
description:
@@ -159,26 +160,26 @@ packages:
dependency: transitive
description:
name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
url: "https://pub.dev"
source: hosted
version: "1.1.1"
version: "1.1.2"
collection:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.18.0"
version: "1.19.1"
connectivity_plus:
dependency: "direct main"
description:
name: connectivity_plus
sha256: "876849631b0c7dc20f8b471a2a03142841b482438e3b707955464f5ffca3e4c3"
sha256: "04bf81bb0b77de31557b58d052b24b3eee33f09a6e7a8c68a3e247c7df19ec27"
url: "https://pub.dev"
source: hosted
version: "6.1.0"
version: "6.1.3"
connectivity_plus_platform_interface:
dependency: transitive
description:
@@ -223,26 +224,26 @@ packages:
dependency: transitive
description:
name: dbus
sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac"
sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c"
url: "https://pub.dev"
source: hosted
version: "0.7.10"
version: "0.7.11"
device_info_plus:
dependency: "direct main"
description:
name: device_info_plus
sha256: f545ffbadee826f26f2e1a0f0cbd667ae9a6011cc0f77c0f8f00a969655e6e95
sha256: "306b78788d1bb569edb7c55d622953c2414ca12445b41c9117963e03afc5c513"
url: "https://pub.dev"
source: hosted
version: "11.1.1"
version: "11.3.3"
device_info_plus_platform_interface:
dependency: transitive
description:
name: device_info_plus_platform_interface
sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba"
sha256: "0b04e02b30791224b31969eb1b50d723498f402971bff3630bca2ba839bd1ed2"
url: "https://pub.dev"
source: hosted
version: "7.0.1"
version: "7.0.2"
dynamic_color:
dependency: "direct main"
description:
@@ -255,10 +256,10 @@ packages:
dependency: "direct main"
description:
name: easy_localization
sha256: fa59bcdbbb911a764aa6acf96bbb6fa7a5cf8234354fc45ec1a43a0349ef0201
sha256: "0f5239c7b8ab06c66440cfb0e9aa4b4640429c6668d5a42fe389c5de42220b12"
url: "https://pub.dev"
source: hosted
version: "3.0.7"
version: "3.0.7+1"
easy_logger:
dependency: transitive
description:
@@ -279,18 +280,18 @@ packages:
dependency: transitive
description:
name: fake_async
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
version: "1.3.2"
ffi:
dependency: transitive
description:
name: ffi
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
url: "https://pub.dev"
source: hosted
version: "2.1.3"
version: "2.1.4"
file:
dependency: transitive
description:
@@ -303,10 +304,10 @@ packages:
dependency: "direct main"
description:
name: file_picker
sha256: "16dc141db5a2ccc6520ebb6a2eb5945b1b09e95085c021d9f914f8ded7f1465c"
sha256: "7423298f08f6fc8cce05792bae329f9a93653fc9c08712831b1a55540127995d"
url: "https://pub.dev"
source: hosted
version: "8.1.4"
version: "9.0.2"
fixnum:
dependency: transitive
description:
@@ -319,18 +320,18 @@ packages:
dependency: "direct main"
description:
name: flex_color_picker
sha256: "12dc855ae8ef5491f529b1fc52c655f06dcdf4114f1f7fdecafa41eec2ec8d79"
sha256: c083b79f1c57eaeed9f464368be376951230b3cb1876323b784626152a86e480
url: "https://pub.dev"
source: hosted
version: "3.6.0"
version: "3.7.0"
flex_seed_scheme:
dependency: transitive
description:
name: flex_seed_scheme
sha256: "7639d2c86268eff84a909026eb169f008064af0fb3696a651b24b0fa24a40334"
sha256: d3ba3c5c92d2d79d45e94b4c6c71d01fac3c15017da1545880c53864da5dfeb0
url: "https://pub.dev"
source: hosted
version: "3.4.1"
version: "3.5.0"
flutter:
dependency: "direct main"
description: flutter
@@ -344,14 +345,54 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.0.3"
flutter_charset_detector:
dependency: "direct main"
description:
name: flutter_charset_detector
sha256: "21f6fe8172fbfe3ba9d2fe0dba3702ba07f682315e829a68d49185a0c80d5ad0"
url: "https://pub.dev"
source: hosted
version: "5.0.0"
flutter_charset_detector_android:
dependency: transitive
description:
name: flutter_charset_detector_android
sha256: "443145e8fc8515b3b32aee375691e40dd59197a86a2ae153166bc88c8200d83b"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
flutter_charset_detector_darwin:
dependency: transitive
description:
name: flutter_charset_detector_darwin
sha256: daac20390275efb92fbb14350fe11286c5e29c7b80d6b0867f52d760f0d69763
url: "https://pub.dev"
source: hosted
version: "1.1.0"
flutter_charset_detector_platform_interface:
dependency: transitive
description:
name: flutter_charset_detector_platform_interface
sha256: "1c09ed7b314a5a9dde76057b98b7d35458ba881eed03d5e5b6f7f74b4869d18c"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
flutter_charset_detector_web:
dependency: transitive
description:
name: flutter_charset_detector_web
sha256: e3ac65f94b12f4887937b21a19365d7927db816840cb93274e3861241cb0e9f2
url: "https://pub.dev"
source: hosted
version: "2.0.0"
flutter_fgbg:
dependency: "direct main"
description:
name: flutter_fgbg
sha256: e02ad0738ba5fc7f331b62acb0d74aa540626a6441ae18fad685faa5ac4ad7a5
sha256: eb6da9b2047372566a6e17b505975fe5bace94af01f6fc825c4b6f81baa6c447
url: "https://pub.dev"
source: hosted
version: "0.6.0"
version: "0.7.1"
flutter_keyboard_visibility:
dependency: transitive
description:
@@ -404,10 +445,10 @@ packages:
dependency: "direct dev"
description:
name: flutter_launcher_icons
sha256: "619817c4b65b322b5104b6bb6dfe6cda62d9729bd7ad4303ecc8b4e690a67a77"
sha256: bfa04787c85d80ecb3f8777bde5fc10c3de809240c48fa061a2c2bf15ea5211c
url: "https://pub.dev"
source: hosted
version: "0.14.1"
version: "0.14.3"
flutter_lints:
dependency: "direct dev"
description:
@@ -449,18 +490,18 @@ packages:
dependency: "direct main"
description:
name: flutter_markdown
sha256: "999a4e3cb3e1532a971c86d6c73a480264f6a687959d4887cb4e2990821827e4"
sha256: e7bbc718adc9476aa14cfddc1ef048d2e21e4e8f18311aaac723266db9f9e7b5
url: "https://pub.dev"
source: hosted
version: "0.7.4+2"
version: "0.7.6+2"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: "9b78450b89f059e96c9ebb355fa6b3df1d6b330436e0b885fb49594c41721398"
sha256: "5a1e6fb2c0561958d7e4c33574674bda7b77caaca7a33b758876956f2902eea3"
url: "https://pub.dev"
source: hosted
version: "2.0.23"
version: "2.0.27"
flutter_test:
dependency: "direct dev"
description: flutter
@@ -483,18 +524,18 @@ packages:
dependency: "direct main"
description:
name: fluttertoast
sha256: "95f349437aeebe524ef7d6c9bde3e6b4772717cf46a0eb6a3ceaddc740b297cc"
sha256: "25e51620424d92d3db3832464774a6143b5053f15e382d8ffbfd40b6e795dcf1"
url: "https://pub.dev"
source: hosted
version: "8.2.8"
version: "8.2.12"
fraction:
dependency: transitive
description:
name: fraction
sha256: ac0d9904bb8211eb28606bdf623ff9f222c53240d8e9b927a07c149d356eddc2
sha256: "7804c9a73d26bd3d5ccf52b7225eecd0af4e33b310729726dc8f8bb14c217716"
url: "https://pub.dev"
source: hosted
version: "5.0.3"
version: "5.0.4"
gtk:
dependency: transitive
description:
@@ -523,26 +564,26 @@ packages:
dependency: "direct main"
description:
name: http
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
url: "https://pub.dev"
source: hosted
version: "1.2.2"
version: "1.3.0"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
version: "4.1.2"
image:
dependency: transitive
description:
name: image
sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d
sha256: "13d3349ace88f12f4a0d175eb5c12dcdd39d35c4c109a8a13dfeb6d0bd9e31c3"
url: "https://pub.dev"
source: hosted
version: "4.3.0"
version: "4.5.3"
intl:
dependency: transitive
description:
@@ -563,18 +604,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
url: "https://pub.dev"
source: hosted
version: "10.0.5"
version: "10.0.8"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
url: "https://pub.dev"
source: hosted
version: "3.0.5"
version: "3.0.9"
leak_tracker_testing:
dependency: transitive
description:
@@ -587,26 +628,26 @@ packages:
dependency: transitive
description:
name: lints
sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413"
sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7
url: "https://pub.dev"
source: hosted
version: "5.0.0"
version: "5.1.1"
markdown:
dependency: "direct main"
description:
name: markdown
sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051
sha256: "935e23e1ff3bc02d390bad4d4be001208ee92cc217cb5b5a6c19bc14aaa318c1"
url: "https://pub.dev"
source: hosted
version: "7.2.2"
version: "7.3.0"
matcher:
dependency: transitive
description:
name: matcher
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://pub.dev"
source: hosted
version: "0.12.16+1"
version: "0.12.17"
material_color_utilities:
dependency: transitive
description:
@@ -619,10 +660,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
url: "https://pub.dev"
source: hosted
version: "1.15.0"
version: "1.16.0"
mime:
dependency: transitive
description:
@@ -651,10 +692,10 @@ packages:
dependency: transitive
description:
name: path
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted
version: "1.9.0"
version: "1.9.1"
path_provider:
dependency: "direct main"
description:
@@ -667,18 +708,18 @@ packages:
dependency: transitive
description:
name: path_provider_android
sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a
sha256: "0ca7359dad67fd7063cb2892ab0c0737b2daafd807cf1acecd62374c8fae6c12"
url: "https://pub.dev"
source: hosted
version: "2.2.12"
version: "2.2.16"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.4.1"
path_provider_linux:
dependency: transitive
description:
@@ -707,26 +748,26 @@ packages:
dependency: "direct main"
description:
name: permission_handler
sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb"
sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849"
url: "https://pub.dev"
source: hosted
version: "11.3.1"
version: "11.4.0"
permission_handler_android:
dependency: transitive
description:
name: permission_handler_android
sha256: "71bbecfee799e65aff7c744761a57e817e73b738fedf62ab7afd5593da21f9f1"
sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc
url: "https://pub.dev"
source: hosted
version: "12.0.13"
version: "12.1.0"
permission_handler_apple:
dependency: transitive
description:
name: permission_handler_apple
sha256: e6f6d73b12438ef13e648c4ae56bd106ec60d17e90a59c4545db6781229082a0
sha256: f84a188e79a35c687c132a0a0556c254747a08561e99ab933f12f6ca71ef3c98
url: "https://pub.dev"
source: hosted
version: "9.4.5"
version: "9.4.6"
permission_handler_html:
dependency: transitive
description:
@@ -739,10 +780,10 @@ packages:
dependency: transitive
description:
name: permission_handler_platform_interface
sha256: e9c8eadee926c4532d0305dff94b85bf961f16759c3af791486613152af4b4f9
sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878
url: "https://pub.dev"
source: hosted
version: "4.2.3"
version: "4.3.0"
permission_handler_windows:
dependency: transitive
description:
@@ -807,6 +848,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.10.2+1"
posix:
dependency: transitive
description:
name: posix
sha256: a0117dc2167805aa9125b82eee515cc891819bac2f538c83646d355b16f58b9a
url: "https://pub.dev"
source: hosted
version: "6.0.1"
provider:
dependency: "direct main"
description:
@@ -819,42 +868,42 @@ packages:
dependency: "direct main"
description:
name: share_plus
sha256: "9c9bafd4060728d7cdb2464c341743adbd79d327cb067ec7afb64583540b47c8"
sha256: fce43200aa03ea87b91ce4c3ac79f0cecd52e2a7a56c7a4185023c271fbfa6da
url: "https://pub.dev"
source: hosted
version: "10.1.2"
version: "10.1.4"
share_plus_platform_interface:
dependency: transitive
description:
name: share_plus_platform_interface
sha256: c57c0bbfec7142e3a0f55633be504b796af72e60e3c791b44d5a017b985f7a48
sha256: cc012a23fc2d479854e6c80150696c4a5f5bb62cb89af4de1c505cf78d0a5d0b
url: "https://pub.dev"
source: hosted
version: "5.0.1"
version: "5.0.2"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
sha256: "95f9997ca1fb9799d494d0cb2a780fd7be075818d59f00c43832ed112b158a82"
sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a"
url: "https://pub.dev"
source: hosted
version: "2.3.3"
version: "2.5.2"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "3b9febd815c9ca29c9e3520d50ec32f49157711e143b7a4ca039eb87e8ade5ab"
sha256: "3ec7210872c4ba945e3244982918e502fa2bfb5230dff6832459ca0e1879b7ad"
url: "https://pub.dev"
source: hosted
version: "2.3.3"
version: "2.4.8"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d"
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
url: "https://pub.dev"
source: hosted
version: "2.5.3"
version: "2.5.4"
shared_preferences_linux:
dependency: transitive
description:
@@ -875,10 +924,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_web
sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
url: "https://pub.dev"
source: hosted
version: "2.4.2"
version: "2.4.3"
shared_preferences_windows:
dependency: transitive
description:
@@ -890,11 +939,12 @@ packages:
shared_storage:
dependency: "direct main"
description:
name: shared_storage
sha256: cf20428d06af065311b71e09cbfbbfe431e979a3bf9180001c1952129b7c708f
url: "https://pub.dev"
source: hosted
version: "0.8.1"
path: "."
ref: master
resolved-ref: "8784c39b909324df8913dd30fa416b8a50d55f49"
url: "https://github.com/AlexBacich/shared-storage"
source: git
version: "0.7.0"
shizuku_apk_installer:
dependency: "direct main"
description:
@@ -908,15 +958,15 @@ packages:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
version: "0.0.0"
source_span:
dependency: transitive
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
version: "1.10.1"
sprintf:
dependency: transitive
description:
@@ -929,34 +979,34 @@ packages:
dependency: "direct main"
description:
name: sqflite
sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb"
sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03
url: "https://pub.dev"
source: hosted
version: "2.4.1"
version: "2.4.2"
sqflite_android:
dependency: transitive
description:
name: sqflite_android
sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3"
sha256: "2b3070c5fa881839f8b402ee4a39c1b4d561704d4ebbbcfb808a119bc2a1701b"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.4.1"
sqflite_common:
dependency: transitive
description:
name: sqflite_common
sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709"
sha256: "84731e8bfd8303a3389903e01fb2141b6e59b5973cacbb0929021df08dddbe8b"
url: "https://pub.dev"
source: hosted
version: "2.5.4+6"
version: "2.5.5"
sqflite_darwin:
dependency: transitive
description:
name: sqflite_darwin
sha256: "96a698e2bc82bd770a4d6aab00b42396a7c63d9e33513a56945cbccb594c2474"
sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
version: "2.4.2"
sqflite_platform_interface:
dependency: transitive
description:
@@ -969,50 +1019,50 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
version: "1.12.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.4"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.4.1"
synchronized:
dependency: transitive
description:
name: synchronized
sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
sha256: "0669c70faae6270521ee4f05bffd2919892d42d1276e6c495be80174b6bc0ef6"
url: "https://pub.dev"
source: hosted
version: "3.3.0+3"
version: "3.3.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
version: "1.2.2"
test_api:
dependency: transitive
description:
name: test_api
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
url: "https://pub.dev"
source: hosted
version: "0.7.2"
version: "0.7.4"
timezone:
dependency: transitive
description:
@@ -1049,18 +1099,18 @@ packages:
dependency: transitive
description:
name: url_launcher_android
sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193"
sha256: "1d0eae19bd7606ef60fe69ef3b312a437a16549476c42321d5dc1506c9ca3bf4"
url: "https://pub.dev"
source: hosted
version: "6.3.14"
version: "6.3.15"
url_launcher_ios:
dependency: transitive
description:
name: url_launcher_ios
sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e
sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626"
url: "https://pub.dev"
source: hosted
version: "6.3.1"
version: "6.3.2"
url_launcher_linux:
dependency: transitive
description:
@@ -1073,10 +1123,10 @@ packages:
dependency: transitive
description:
name: url_launcher_macos
sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672"
sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2"
url: "https://pub.dev"
source: hosted
version: "3.2.1"
version: "3.2.2"
url_launcher_platform_interface:
dependency: transitive
description:
@@ -1089,18 +1139,18 @@ packages:
dependency: transitive
description:
name: url_launcher_web
sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e"
sha256: "3ba963161bd0fe395917ba881d320b9c4f6dd3c4a233da62ab18a5025c85f1e9"
url: "https://pub.dev"
source: hosted
version: "2.3.3"
version: "2.4.0"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
sha256: "44cf3aabcedde30f2dba119a9dea3b0f2672fbe6fa96e85536251d678216b3c4"
sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77"
url: "https://pub.dev"
source: hosted
version: "3.1.3"
version: "3.1.4"
uuid:
dependency: transitive
description:
@@ -1121,18 +1171,18 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
url: "https://pub.dev"
source: hosted
version: "14.2.5"
version: "14.3.1"
web:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
webview_flutter:
dependency: "direct main"
description:
@@ -1145,10 +1195,10 @@ packages:
dependency: transitive
description:
name: webview_flutter_android
sha256: "285cedfd9441267f6cca8843458620b5fda1af75b04f5818d0441acda5d7df19"
sha256: "631093a7fbd93e9690ac61d8c8f3e857efbc189fc33f712b9ad6c01a623517ef"
url: "https://pub.dev"
source: hosted
version: "4.1.0"
version: "4.3.3"
webview_flutter_platform_interface:
dependency: transitive
description:
@@ -1161,26 +1211,26 @@ packages:
dependency: transitive
description:
name: webview_flutter_wkwebview
sha256: b7e92f129482460951d96ef9a46b49db34bd2e1621685de26e9eaafd9674e7eb
sha256: c49a98510080378b1525132f407a92c3dcd3b7145bef04fb8137724aadcf1cf0
url: "https://pub.dev"
source: hosted
version: "3.16.3"
version: "3.18.4"
win32:
dependency: transitive
description:
name: win32
sha256: "84ba388638ed7a8cb3445a320c8273136ab2631cd5f2c57888335504ddab1bc2"
sha256: b89e6e24d1454e149ab20fbb225af58660f0c0bf4475544650700d8e2da54aef
url: "https://pub.dev"
source: hosted
version: "5.8.0"
version: "5.11.0"
win32_registry:
dependency: transitive
description:
name: win32_registry
sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852"
sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae"
url: "https://pub.dev"
source: hosted
version: "1.1.5"
version: "2.1.0"
xdg_directories:
dependency: transitive
description:
@@ -1201,10 +1251,10 @@ packages:
dependency: transitive
description:
name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev"
source: hosted
version: "3.1.2"
version: "3.1.3"
sdks:
dart: ">=3.5.0 <4.0.0"
flutter: ">=3.24.0"
dart: ">=3.7.0 <4.0.0"
flutter: ">=3.27.0"

View File

@@ -1,6 +1,5 @@
name: obtainium
description: Get Android app updates straight from the source.
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
@@ -17,10 +16,10 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.1.32+2289
version: 1.1.46+2303
environment:
sdk: '>=3.0.0 <4.0.0'
sdk: ^3.6.0
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
@@ -32,12 +31,11 @@ dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.5
path_provider: ^2.0.11
flutter_fgbg: ^0.6.0
flutter_fgbg: ^0.7.1
flutter_local_notifications: ^18.0.0
provider: ^6.0.3
http: ^1.0.0
@@ -49,13 +47,16 @@ dependencies:
permission_handler: ^11.0.0
fluttertoast: ^8.0.9
device_info_plus: ^11.0.0
file_picker: ^8.0.0+1
file_picker: ^9.0.0
animations: ^2.0.4
android_package_installer:
android_package_installer: # TODO: See if PR will be accepted (dev may not be active), else remove this comment
git:
url: https://github.com/ImranR98/android_package_installer
ref: main
android_package_manager: ^0.7.0
android_package_manager: # TODO: Make PR and switch to upstream
git:
url: https://github.com/ImranR98/android_package_manager
ref: master
share_plus: ^10.0.0
sqflite: ^2.2.0+3
easy_localization: ^3.0.1
@@ -64,7 +65,10 @@ dependencies:
flutter_archive: ^6.0.0
hsluv: ^1.1.3
connectivity_plus: ^6.0.1
shared_storage: ^0.8.0
shared_storage: # TODO: Is this maintained?
git:
url: https://github.com/AlexBacich/shared-storage
ref: master
crypto: ^3.0.3
app_links: ^6.0.1
background_fetch: ^1.2.1
@@ -82,6 +86,7 @@ dependencies:
markdown: any
flutter_typeahead: ^5.2.0
battery_plus: ^6.1.0
flutter_charset_detector: ^5.0.0
dev_dependencies:
flutter_test:
sdk: flutter
@@ -110,20 +115,20 @@ flutter:
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# - assets:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
assets:
- assets/translations/
- assets/graphics/
- assets/ca/
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware
# https://flutter.dev/to/resolution-aware-images
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages
# https://flutter.dev/to/asset-from-package
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
@@ -143,9 +148,9 @@ flutter:
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
# see https://flutter.dev/to/font-from-package
fonts:
- family: Wix-Madefor-Display
- family: Montserrat
fonts:
- asset: assets/fonts/WixMadeforDisplay-Regular.otf
- asset: assets/fonts/Montserrat-Regular.ttf