mirror of
				https://github.com/ImranR98/Obtainium.git
				synced 2025-10-31 05:23:28 +01:00 
			
		
		
		
	Compare commits
	
		
			29 Commits
		
	
	
		
			v0.13.15-b
			...
			v0.13.18-b
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | e093fc28b0 | ||
|  | 579bc94847 | ||
|  | 53dba06cc3 | ||
|  | 1c390a7f04 | ||
|  | 6b16857186 | ||
|  | 785bba1f45 | ||
|  | 3befcbc16d | ||
|  | be300608a9 | ||
|  | f05902925d | ||
|  | d32e7acc8f | ||
|  | fda9e6195a | ||
|  | b5d91adb21 | ||
|  | 1b52cb6233 | ||
|  | 5669634b44 | ||
|  | d6bb365cf1 | ||
|  | 53b7cfb9bf | ||
|  | 2558c851c0 | ||
|  | a8aa63daa3 | ||
|  | d587e9f708 | ||
|  | e2a8f40e3e | ||
|  | 1cc4241fac | ||
|  | bb98dfe0b3 | ||
|  | 6395dd820b | ||
|  | e909c03356 | ||
|  | 6a3278432d | ||
|  | 81c51970aa | ||
|  | 7f9d431b9b | ||
|  | 360591ebb9 | ||
|  | 814ff2c2e5 | 
| @@ -229,7 +229,7 @@ | ||||
|     "dontShowTrackOnlyWarnings": "Warnung für 'Nur Nachverfolgen' nicht anzeigen", | ||||
|     "dontShowAPKOriginWarnings": "Warnung für APK-Herkunft nicht anzeigen", | ||||
|     "moveNonInstalledAppsToBottom": "Nicht installierte Apps ans Ende der Apps Ansicht verschieben", | ||||
|     "gitlabPATLabel": "GitLab Personal Access Token (Aktiviert Suche)", | ||||
|     "gitlabPATLabel": "GitLab Personal Access Token\n(Aktiviert Suche and Better APK Discovery)", | ||||
|     "about": "Über", | ||||
|     "requiresCredentialsInSettings": "Benötigt zusätzliche Anmeldedaten (in den Einstellungen)", | ||||
|     "checkOnStart": "Überprüfe einmalig beim Start", | ||||
| @@ -237,6 +237,8 @@ | ||||
|     "removeOnExternalUninstall": "Automatically remove externally uninstalled Apps", | ||||
|     "pickHighestVersionCode": "Auto-select highest version code APK", | ||||
|     "checkUpdateOnDetailPage": "Check for updates on opening an App detail page", | ||||
|     "disablePageTransitions": "Disable page transition animations", | ||||
|     "reversePageTransitions": "Reverse page transition animations", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "App entfernen?", | ||||
|         "other": "Apps entfernen?" | ||||
|   | ||||
| @@ -229,7 +229,7 @@ | ||||
|     "dontShowTrackOnlyWarnings": "Don't show 'Track-Only' warnings", | ||||
|     "dontShowAPKOriginWarnings": "Don't show APK origin warnings", | ||||
|     "moveNonInstalledAppsToBottom": "Move non-installed Apps to bottom of Apps view", | ||||
|     "gitlabPATLabel": "GitLab Personal Access Token (Enables Search)", | ||||
|     "gitlabPATLabel": "GitLab Personal Access Token\n(Enables Search and Better APK Discovery)", | ||||
|     "about": "About", | ||||
|     "requiresCredentialsInSettings": "This needs additional credentials (in Settings)", | ||||
|     "checkOnStart": "Check for updates on startup", | ||||
| @@ -237,6 +237,8 @@ | ||||
|     "removeOnExternalUninstall": "Automatically remove externally uninstalled Apps", | ||||
|     "pickHighestVersionCode": "Auto-select highest version code APK", | ||||
|     "checkUpdateOnDetailPage": "Check for updates on opening an App detail page", | ||||
|     "disablePageTransitions": "Disable page transition animations", | ||||
|     "reversePageTransitions": "Reverse page transition animations", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Remove App?", | ||||
|         "other": "Remove Apps?" | ||||
|   | ||||
| @@ -229,7 +229,7 @@ | ||||
|     "dontShowTrackOnlyWarnings": "No mostrar avisos de 'Solo Seguimiento'", | ||||
|     "dontShowAPKOriginWarnings": "No mostrar avisos de las fuentes de las APks", | ||||
|     "moveNonInstalledAppsToBottom": "Move non-installed Apps to bottom of Apps view", | ||||
|     "gitlabPATLabel": "GitLab Personal Access Token (Enables Search)", | ||||
|     "gitlabPATLabel": "GitLab Personal Access Token\n(Enables Search and Better APK Discovery)", | ||||
|     "about": "About", | ||||
|     "requiresCredentialsInSettings": "This needs additional credentials (in Settings)", | ||||
|     "checkOnStart": "Check for updates on startup", | ||||
| @@ -237,6 +237,8 @@ | ||||
|     "removeOnExternalUninstall": "Automatically remove externally uninstalled Apps", | ||||
|     "pickHighestVersionCode": "Auto-select highest version code APK", | ||||
|     "checkUpdateOnDetailPage": "Check for updates on opening an App detail page", | ||||
|     "disablePageTransitions": "Disable page transition animations", | ||||
|     "reversePageTransitions": "Reverse page transition animations", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "¿Eliminar Aplicación?", | ||||
|         "other": "¿Eliminar Aplicaciones?" | ||||
|   | ||||
| @@ -229,7 +229,7 @@ | ||||
|     "dontShowTrackOnlyWarnings": "هشدار 'فقط ردیابی' را نشان ندهید", | ||||
|     "dontShowAPKOriginWarnings": "هشدارهای منبع APK را نشان ندهید", | ||||
|     "moveNonInstalledAppsToBottom": "برنامه های نصب نشده را به نمای پایین برنامه ها منتقل کنید", | ||||
|     "gitlabPATLabel": "رمز دسترسی شخصی GitLab (جستجو را فعال می کند)", | ||||
|     "gitlabPATLabel": "رمز دسترسی شخصی GitLab\n(جستجو را فعال می کند and Better APK Discovery)", | ||||
|     "about": "درباره", | ||||
|     "requiresCredentialsInSettings": "این به اعتبارنامه های اضافی نیاز دارد (در تنظیمات)", | ||||
|     "checkOnStart": "بررسی در شروع", | ||||
| @@ -237,6 +237,8 @@ | ||||
|     "removeOnExternalUninstall": "Automatically remove externally uninstalled Apps", | ||||
|     "pickHighestVersionCode": "Auto-select highest version code APK", | ||||
|     "checkUpdateOnDetailPage": "Check for updates on opening an App detail page", | ||||
|     "disablePageTransitions": "Disable page transition animations", | ||||
|     "reversePageTransitions": "Reverse page transition animations", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "برنامه حذف شود؟", | ||||
|         "other": "برنامه ها حذف شوند؟" | ||||
|   | ||||
| @@ -229,7 +229,7 @@ | ||||
|     "dontShowTrackOnlyWarnings": "Don't Show the 'Track-Only' Warning", | ||||
|     "dontShowAPKOriginWarnings": "Don't show APK origin warnings", | ||||
|     "moveNonInstalledAppsToBottom": "Move non-installed Apps to bottom of Apps view", | ||||
|     "gitlabPATLabel": "GitLab Personal Access Token (Enables Search)", | ||||
|     "gitlabPATLabel": "GitLab Personal Access Token\n(Enables Search and Better APK Discovery)", | ||||
|     "about": "About", | ||||
|     "requiresCredentialsInSettings": "This needs additional credentials (in Settings)", | ||||
|     "checkOnStart": "Check for updates on startup", | ||||
| @@ -237,6 +237,8 @@ | ||||
|     "removeOnExternalUninstall": "Automatically remove externally uninstalled Apps", | ||||
|     "pickHighestVersionCode": "Auto-select highest version code APK", | ||||
|     "checkUpdateOnDetailPage": "Check for updates on opening an App detail page", | ||||
|     "disablePageTransitions": "Disable page transition animations", | ||||
|     "reversePageTransitions": "Reverse page transition animations", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Supprimer l'application ?", | ||||
|         "other": "Supprimer les applications ?" | ||||
|   | ||||
| @@ -228,14 +228,16 @@ | ||||
|     "dontShowTrackOnlyWarnings": "Ne jelenítsen meg 'Csak nyomon követés' figyelmeztetést", | ||||
|     "dontShowAPKOriginWarnings": "Ne jelenítsen meg az APK eredetére vonatkozó figyelmeztetéseket", | ||||
|     "moveNonInstalledAppsToBottom": "Helyezze át a nem telepített appokat az App nézet aljára", | ||||
|     "gitlabPATLabel": "GitLab Personal Access Token (Engedélyezi a Keresést)", | ||||
|     "gitlabPATLabel": "GitLab Personal Access Token\n(Engedélyezi a Keresést and Better APK Discovery)", | ||||
|     "about": "Rólunk", | ||||
|     "requiresCredentialsInSettings": "Ehhez további hitelesítő adatokra van szükség (a Beállításokban)", | ||||
|     "checkOnStart": "Egyszer az indításkor", | ||||
|     "tryInferAppIdFromCode": "Próbálja kikövetkeztetni az app azonosítót a forráskódból", | ||||
|     "removeOnExternalUninstall": "Automatically remove externally uninstalled Apps", | ||||
|     "pickHighestVersionCode": "Auto-select highest version code APK", | ||||
|     "checkUpdateOnDetailPage": "Check for updates on opening an App detail page", | ||||
|     "removeOnExternalUninstall": "A külsőleg eltávolított appok auto. eltávolítása", | ||||
|     "pickHighestVersionCode": "A legmagasabb verziószámú APK auto. kiválasztása", | ||||
|     "checkUpdateOnDetailPage": "Frissítések keresése az app részleteit tartalmazó oldal megnyitásakor", | ||||
|     "disablePageTransitions": "Disable page transition animations", | ||||
|     "reversePageTransitions": "Reverse page transition animations", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Eltávolítja az alkalmazást?", | ||||
|         "other": "Eltávolítja az alkalmazást?" | ||||
|   | ||||
| @@ -229,7 +229,7 @@ | ||||
|     "dontShowTrackOnlyWarnings": "Non mostrare gli avvisi 'Solo-Monitoraggio'", | ||||
|     "dontShowAPKOriginWarnings": "Non mostrare gli avvisi di origine dell'APK", | ||||
|     "moveNonInstalledAppsToBottom": "Sposta le app non installate in fondo alla lista", | ||||
|     "gitlabPATLabel": "GitLab Personal Access Token (attiva la ricerca)", | ||||
|     "gitlabPATLabel": "GitLab Personal Access Token\n(attiva la ricerca and Better APK Discovery)", | ||||
|     "about": "Informazioni", | ||||
|     "requiresCredentialsInSettings": "Servono credenziali aggiuntive (in Impostazioni)", | ||||
|     "checkOnStart": "Controlla una volta all'avvio", | ||||
| @@ -237,6 +237,8 @@ | ||||
|     "removeOnExternalUninstall": "Automatically remove externally uninstalled Apps", | ||||
|     "pickHighestVersionCode": "Auto-select highest version code APK", | ||||
|     "checkUpdateOnDetailPage": "Check for updates on opening an App detail page", | ||||
|     "disablePageTransitions": "Disable page transition animations", | ||||
|     "reversePageTransitions": "Reverse page transition animations", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Rimuovere l'app?", | ||||
|         "other": "Rimuovere le app?" | ||||
|   | ||||
| @@ -135,7 +135,7 @@ | ||||
|     "showWebInAppView": "アプリページにソースのWebページを表示する", | ||||
|     "pinUpdates": "アップデートがあるアプリをトップに固定する", | ||||
|     "updates": "アップデート", | ||||
|     "sourceSpecific": "Github アクセストークン", | ||||
|     "sourceSpecific": "ソース別の設定", | ||||
|     "appSource": "アプリのソース", | ||||
|     "noLogs": "ログはありません", | ||||
|     "appLogs": "アプリのログ", | ||||
| @@ -227,16 +227,18 @@ | ||||
|     "overrideSource": "ソースの上書き", | ||||
|     "dontShowAgain": "二度と表示しない", | ||||
|     "dontShowTrackOnlyWarnings": "「追跡のみ」の警告を表示しない", | ||||
|     "dontShowAPKOriginWarnings": "APK Originの警告を表示しない", | ||||
|     "dontShowAPKOriginWarnings": "APKのダウンロード元の警告を表示しない", | ||||
|     "moveNonInstalledAppsToBottom": "未インストールのアプリをアプリ一覧の下部に移動させる", | ||||
|     "gitlabPATLabel": "GitLab パーソナルアクセストークン (検索を有効化する)", | ||||
|     "gitlabPATLabel": "GitLab パーソナルアクセストークン\n(検索とより良いAPK検出の有効化)", | ||||
|     "about": "概要", | ||||
|     "requiresCredentialsInSettings": "これには追加の認証が必要です (設定にて)", | ||||
|     "checkOnStart": "Check for updates on startup", | ||||
|     "tryInferAppIdFromCode": "Try inferring App ID from source code", | ||||
|     "removeOnExternalUninstall": "Automatically remove externally uninstalled Apps", | ||||
|     "pickHighestVersionCode": "Auto-select highest version code APK", | ||||
|     "checkUpdateOnDetailPage": "Check for updates on opening an App detail page", | ||||
|     "checkOnStart": "起動時にアップデートを確認する", | ||||
|     "tryInferAppIdFromCode": "ソースコードからApp IDを推測する", | ||||
|     "removeOnExternalUninstall": "外部でアンインストールされたアプリを自動的に削除する", | ||||
|     "pickHighestVersionCode": "最も高いバージョンコードのAPKを自動的に選択する", | ||||
|     "checkUpdateOnDetailPage": "アプリの詳細ページを開く際にアップデートを確認する", | ||||
|     "disablePageTransitions": "Disable page transition animations", | ||||
|     "reversePageTransitions": "Reverse page transition animations", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "アプリを削除しますか?", | ||||
|         "other": "アプリを削除しますか?" | ||||
|   | ||||
| @@ -25,8 +25,8 @@ | ||||
|     "bgUpdateTaskFinished": "Zakończono zadanie sprawdzania aktualizacji w tle", | ||||
|     "firstRun": "Jest to pierwsze uruchomienie Obtainium", | ||||
|     "settingUpdateCheckIntervalTo": "Ustawianie interwału aktualizacji na {}", | ||||
|     "githubPATLabel": "Osobisty Token Dostępu GitHub (zwiększa limit zapytań)", | ||||
|     "githubPATHint": "Wymagany format OTD: użytkownik:token", | ||||
|     "githubPATLabel": "Osobisty token dostępu GitHub (zwiększa limit zapytań)", | ||||
|     "githubPATHint": "Wymagany format: użytkownik:token", | ||||
|     "githubPATFormat": "użytkownik:token", | ||||
|     "includePrereleases": "Uwzględnij wersje wstępne", | ||||
|     "fallbackToOlderReleases": "Powracaj do starszych wersji", | ||||
| @@ -233,14 +233,16 @@ | ||||
|     "dontShowTrackOnlyWarnings": "Nie wyświetlaj ostrzeżeń „Tylko obserwowana”", | ||||
|     "dontShowAPKOriginWarnings": "Nie pokazuj ostrzeżeń o pochodzeniu APK", | ||||
|     "moveNonInstalledAppsToBottom": "Przenieś niezainstalowane aplikacje na dół widoku aplikacji", | ||||
|     "gitlabPATLabel": "Osobisty Token Dostępu GitLab (umożliwia wyszukiwanie)", | ||||
|     "gitlabPATLabel": "Osobisty token dostępu GitLab\n(Umożliwia wyszukiwanie i lepsze wykrywanie APK)", | ||||
|     "about": "Więcej informacji", | ||||
|     "requiresCredentialsInSettings": "Wymaga to dodatkowych poświadczeń (w Ustawieniach)", | ||||
|     "checkOnStart": "Sprawdź raz przy starcie", | ||||
|     "checkOnStart": "Sprawdź aktualizacje przy uruchomieniu", | ||||
|     "tryInferAppIdFromCode": "Spróbuj wywnioskować identyfikator aplikacji z kodu źródłowego", | ||||
|     "removeOnExternalUninstall": "Automatically remove externally uninstalled Apps", | ||||
|     "pickHighestVersionCode": "Auto-select highest version code APK", | ||||
|     "checkUpdateOnDetailPage": "Check for updates on opening an App detail page", | ||||
|     "removeOnExternalUninstall": "Automatyczne usuń odinstalowane zewnętrznie aplikacje", | ||||
|     "pickHighestVersionCode": "Automatycznie wybierz najwyższy kod wersji APK", | ||||
|     "checkUpdateOnDetailPage": "Sprawdzaj aktualizacje podczas otwierania strony szczegółów aplikacji", | ||||
|     "disablePageTransitions": "Disable page transition animations", | ||||
|     "reversePageTransitions": "Reverse page transition animations", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Usunąć aplikację?", | ||||
|         "other": "Usunąć aplikacje?" | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     "appIdMismatch": "ID загруженного пакета не совпадает с существующим ID приложения", | ||||
|     "functionNotImplemented": "Этот класс не реализовал эту функцию", | ||||
|     "placeholder": "Заполнитель", | ||||
|     "someErrors": "Произошли некоторые ошибки", | ||||
|     "someErrors": "Возникли некоторые ошибки", | ||||
|     "unexpectedError": "Неожиданная ошибка", | ||||
|     "ok": "Окей", | ||||
|     "and": "и", | ||||
| @@ -22,7 +22,7 @@ | ||||
|     "githubPATFormat": "имя_пользователя:токен", | ||||
|     "includePrereleases": "Включить предварительные релизы", | ||||
|     "fallbackToOlderReleases": "Откатиться к более старым версиям", | ||||
|     "filterReleaseTitlesByRegEx": "Фильтровать заголовки релизов с помощью регулярного выражения", | ||||
|     "filterReleaseTitlesByRegEx": "Фильтровать заголовки релизов\nс помощью регулярного выражения", | ||||
|     "invalidRegEx": "Неверное регулярное выражение", | ||||
|     "noDescription": "Нет описания", | ||||
|     "cancel": "Отмена", | ||||
| @@ -33,7 +33,7 @@ | ||||
|     "githubStarredRepos": "Помеченные звездочкой репозитории на GitHub", | ||||
|     "uname": "Имя пользователя", | ||||
|     "wrongArgNum": "Неправильное количество предоставленных аргументов", | ||||
|     "xIsTrackOnly": "{} является приложением только для отслеживания", | ||||
|     "xIsTrackOnly": "{} только для отслеживания", | ||||
|     "source": "Источник", | ||||
|     "app": "Приложение", | ||||
|     "appsFromSourceAreTrackOnly": "Приложения из этого источника являются 'только для отслеживания'.", | ||||
| @@ -100,7 +100,7 @@ | ||||
|     "invalidInput": "Неверный ввод", | ||||
|     "importedX": "Импортировано {}", | ||||
|     "obtainiumImport": "Импорт в Obtainium", | ||||
|     "importFromURLList": "Импорт из списка URL-адреса", | ||||
|     "importFromURLList": "Импорт из списка URL-адресов", | ||||
|     "searchQuery": "Поисковый запрос", | ||||
|     "appURLList": "Список URL приложений", | ||||
|     "line": "Строка", | ||||
| @@ -121,7 +121,7 @@ | ||||
|     "followSystem": "Следовать системе", | ||||
|     "obtainium": "Obtainium", | ||||
|     "materialYou": "Material You", | ||||
|     "useBlackTheme": "Использовать темную тему", | ||||
|     "useBlackTheme": "Использовать чёрную тему", | ||||
|     "appSortBy": "Сортировка приложений по", | ||||
|     "authorName": "Автор/Название", | ||||
|     "nameAuthor": "Название/Автор", | ||||
| @@ -132,7 +132,7 @@ | ||||
|     "bgUpdateCheckInterval": "Интервал проверки обновлений в фоновом режиме", | ||||
|     "neverManualOnly": "Никогда - Только вручную", | ||||
|     "appearance": "Внешний вид", | ||||
|     "showWebInAppView": "Показывать веб-страницу источника в представлении приложения", | ||||
|     "showWebInAppView": "Показывать исходную веб-страницу в представлении приложения", | ||||
|     "pinUpdates": "Закрепить обновления сверху списка приложений", | ||||
|     "updates": "Обновления", | ||||
|     "sourceSpecific": "Специфика источника", | ||||
| @@ -183,7 +183,7 @@ | ||||
|     "appId": "ID приложения", | ||||
|     "appWithIdOrNameNotFound": "Приложение с таким ID или названием не было найдено", | ||||
|     "reposHaveMultipleApps": "В хранилище может быть несколько приложений", | ||||
|     "fdroidThirdPartyRepo": "Хранилище F-Droid сторонних разработчиков", | ||||
|     "fdroidThirdPartyRepo": "Репозитории F-Droid сторонних разработчиков", | ||||
|     "steam": "Steam", | ||||
|     "steamMobile": "Steam Mobile", | ||||
|     "steamChat": "Steam Chat", | ||||
| @@ -211,7 +211,7 @@ | ||||
|     "copiedToClipboard": "Скопировано в буфер обмена", | ||||
|     "storagePermissionDenied": "Отказано в доступе к хранилищу", | ||||
|     "selectedCategorizeWarning": "Это заменит все текущие настройки категорий для выбранных приложений.", | ||||
|     "filterAPKsByRegEx": "Фильтровать APK-файлы с помощью регулярного выражения", | ||||
|     "filterAPKsByRegEx": "Фильтровать APK-файлы с помощью\nрегулярного выражения", | ||||
|     "removeFromObtainium": "Удалить из Obtainium", | ||||
|     "uninstallFromDevice": "Удалить с устройства", | ||||
|     "onlyWorksWithNonVersionDetectApps": "Работает только для приложений с отключенным определением версии.", | ||||
| @@ -219,7 +219,7 @@ | ||||
|     "releaseDateAsVersionExplanation": "Этот параметр следует использовать только для приложений, в которых определение версии не работает правильно, но имеется дата выпуска.", | ||||
|     "changes": "Изменения", | ||||
|     "releaseDate": "Дата выпуска", | ||||
|     "importFromURLsInFile": "Импортировать из URL-адресов в файл (например, OPML)", | ||||
|     "importFromURLsInFile": "Импорт из URL-адресов в файле (например, OPML)", | ||||
|     "versionDetection": "Определение версии", | ||||
|     "standardVersionDetection": "Стандартное определение версии", | ||||
|     "groupByCategory": "Группировать по категориям", | ||||
| @@ -229,14 +229,16 @@ | ||||
|     "dontShowTrackOnlyWarnings": "Не показывать предупреждения о только отслеживаемых приложениях", | ||||
|     "dontShowAPKOriginWarnings": "Не показывать предупреждения об источнике APK-файлов", | ||||
|     "moveNonInstalledAppsToBottom": "Переместить неустановленные приложения вниз списка", | ||||
|     "gitlabPATLabel": "Персональный токен доступа GitLab (Включает поиск)", | ||||
|     "gitlabPATLabel": "Персональный токен доступа GitLab\n(Включает поиск и улучшает обнаружение APK)", | ||||
|     "about": "О приложении", | ||||
|     "requiresCredentialsInSettings": "Для этого требуются дополнительные учетные данные (в настройках)", | ||||
|     "checkOnStart": "Проверить один раз при запуске", | ||||
|     "checkOnStart": "Проверять наличие обновлений при запуске", | ||||
|     "tryInferAppIdFromCode": "Попытаться определить ID приложения из исходного кода", | ||||
|     "removeOnExternalUninstall": "Automatically remove externally uninstalled Apps", | ||||
|     "pickHighestVersionCode": "Auto-select highest version code APK", | ||||
|     "checkUpdateOnDetailPage": "Check for updates on opening an App detail page", | ||||
|     "removeOnExternalUninstall": "Автоматически убирать из списка удаленные извне приложения", | ||||
|     "pickHighestVersionCode": "Автовыбор кода наивысшей версии APK", | ||||
|     "checkUpdateOnDetailPage": "Проверять наличие обновлений при открытии страницы представления приложения", | ||||
|     "disablePageTransitions": "Disable page transition animations", | ||||
|     "reversePageTransitions": "Reverse page transition animations", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Удалить приложение?", | ||||
|         "other": "Удалить приложения?" | ||||
| @@ -258,8 +260,8 @@ | ||||
|         "other": "{} Приложений" | ||||
|     }, | ||||
|     "url": { | ||||
|         "one": "{} Ссылка", | ||||
|         "other": "{} Ссылки" | ||||
|         "one": "{} URL-адрес", | ||||
|         "other": "{} URL-адреса" | ||||
|     }, | ||||
|     "minute": { | ||||
|         "one": "{} Минута", | ||||
| @@ -278,11 +280,11 @@ | ||||
|         "other": "Очищено {n} журналов (до = {before}, после = {after})" | ||||
|     }, | ||||
|     "xAndNMoreUpdatesAvailable": { | ||||
|         "one": "У {} и еще 1 приложения есть обновления.", | ||||
|         "other": "{} and {} more apps have updates." | ||||
|         "one": "У {} и еще 1 приложения есть обновление.", | ||||
|         "other": "У {} и ещё {} приложений есть обновления." | ||||
|     }, | ||||
|     "xAndNMoreUpdatesInstalled": { | ||||
|         "one": "{} and 1 more app were updated.", | ||||
|         "other": "У {} и еще {} приложений есть обновления." | ||||
|         "one": "{} и еще 1 приложение были обновлены.", | ||||
|         "other": "{} и еще {} приложений были обновлены." | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -229,7 +229,7 @@ | ||||
|     "dontShowTrackOnlyWarnings": "不显示“仅追踪”模式警告", | ||||
|     "dontShowAPKOriginWarnings": "不显示 APK 文件来源警告", | ||||
|     "moveNonInstalledAppsToBottom": "将未安装应用置底", | ||||
|     "gitlabPATLabel": "GitLab 个人访问令牌(用于搜索应用)", | ||||
|     "gitlabPATLabel": "GitLab 个人访问令牌\n(用于搜索应用 and Better APK Discovery)", | ||||
|     "about": "相关文档", | ||||
|     "requiresCredentialsInSettings": "此功能需要额外的凭据(在“设置”中添加)", | ||||
|     "checkOnStart": "启动时进行一次检查", | ||||
| @@ -237,6 +237,8 @@ | ||||
|     "removeOnExternalUninstall": "Automatically remove externally uninstalled Apps", | ||||
|     "pickHighestVersionCode": "Auto-select highest version code APK", | ||||
|     "checkUpdateOnDetailPage": "Check for updates on opening an App detail page", | ||||
|     "disablePageTransitions": "Disable page transition animations", | ||||
|     "reversePageTransitions": "Reverse page transition animations", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "是否删除应用?", | ||||
|         "other": "是否删除应用?" | ||||
|   | ||||
| @@ -102,11 +102,53 @@ class GitLab extends AppSource { | ||||
|   ) async { | ||||
|     bool fallbackToOlderReleases = | ||||
|         additionalSettings['fallbackToOlderReleases'] == true; | ||||
|     String? PAT = await getPATIfAny(); | ||||
|     Iterable<APKDetails> apkDetailsList = []; | ||||
|     if (PAT != null) { | ||||
|       var names = GitHub().getAppNames(standardUrl); | ||||
|       Response res = await sourceRequest( | ||||
|           'https://$host/api/v4/projects/${names.author}%2F${names.name}/releases?private_token=$PAT'); | ||||
|       if (res.statusCode != 200) { | ||||
|         throw getObtainiumHttpError(res); | ||||
|       } | ||||
|       var json = jsonDecode(res.body) as List<dynamic>; | ||||
|       apkDetailsList = json.map((e) { | ||||
|         var apkUrlsFromAssets = (e['assets']?['links'] as List<dynamic>? ?? []) | ||||
|             .map((e) { | ||||
|               return (e['direct_asset_url'] ?? e['url'] ?? '') as String; | ||||
|             }) | ||||
|             .where((s) => s.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) => '$standardUrl$s') | ||||
|                 .toList(); | ||||
|         var apkUrlsSet = apkUrlsFromAssets.toSet(); | ||||
|         apkUrlsSet.addAll(uploadedAPKsFromDescription); | ||||
|         var releaseDateString = e['released_at'] ?? e['created_at']; | ||||
|         DateTime? releaseDate = releaseDateString != null | ||||
|             ? DateTime.parse(releaseDateString) | ||||
|             : null; | ||||
|         return APKDetails( | ||||
|             e['tag_name'] ?? e['name'], | ||||
|             getApkUrlsFromUrls(apkUrlsSet.toList()), | ||||
|             GitHub().getAppNames(standardUrl), | ||||
|             releaseDate: releaseDate); | ||||
|       }); | ||||
|     } else { | ||||
|       Response res = await sourceRequest('$standardUrl/-/tags?format=atom'); | ||||
|     if (res.statusCode == 200) { | ||||
|       if (res.statusCode != 200) { | ||||
|         throw getObtainiumHttpError(res); | ||||
|       } | ||||
|       var standardUri = Uri.parse(standardUrl); | ||||
|       var parsedHtml = parse(res.body); | ||||
|       var apkDetailsList = parsedHtml.querySelectorAll('entry').map((entry) { | ||||
|       apkDetailsList = parsedHtml.querySelectorAll('entry').map((entry) { | ||||
|         var entryContent = parse( | ||||
|             parseFragment(entry.querySelector('content')!.innerHtml).text); | ||||
|         var apkUrls = [ | ||||
| @@ -124,7 +166,6 @@ class GitLab extends AppSource { | ||||
|               .where((element) => Uri.parse(element).host != '') | ||||
|               .toList() | ||||
|         ]; | ||||
|  | ||||
|         var entryId = entry.querySelector('id')?.innerHtml; | ||||
|         var version = | ||||
|             entryId == null ? null : Uri.parse(entryId).pathSegments.last; | ||||
| @@ -139,6 +180,7 @@ class GitLab extends AppSource { | ||||
|             GitHub().getAppNames(standardUrl), | ||||
|             releaseDate: releaseDate); | ||||
|       }); | ||||
|     } | ||||
|     if (apkDetailsList.isEmpty) { | ||||
|       throw NoReleasesError(); | ||||
|     } | ||||
| @@ -152,8 +194,5 @@ class GitLab extends AppSource { | ||||
|       } | ||||
|     } | ||||
|     return apkDetailsList.first; | ||||
|     } else { | ||||
|       throw getObtainiumHttpError(res); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -21,7 +21,7 @@ import 'package:easy_localization/src/easy_localization_controller.dart'; | ||||
| // ignore: implementation_imports | ||||
| import 'package:easy_localization/src/localization.dart'; | ||||
|  | ||||
| const String currentVersion = '0.13.15'; | ||||
| const String currentVersion = '0.13.18'; | ||||
| const String currentReleaseTag = | ||||
|     'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES | ||||
|  | ||||
|   | ||||
| @@ -57,6 +57,11 @@ class _AppPageState extends State<AppPage> { | ||||
|         app?.app.additionalSettings['versionDetection'] == | ||||
|             'standardVersionDetection'; | ||||
|  | ||||
|     bool installedVersionIsEstimate = trackOnly || | ||||
|         (app?.app.installedVersion != null && | ||||
|             app?.app.additionalSettings['versionDetection'] == | ||||
|                 'noVersionDetection'); | ||||
|  | ||||
|     getInfoColumn() => Column( | ||||
|           mainAxisAlignment: MainAxisAlignment.center, | ||||
|           crossAxisAlignment: CrossAxisAlignment.stretch, | ||||
| @@ -92,9 +97,7 @@ class _AppPageState extends State<AppPage> { | ||||
|                         app?.app.latestVersion ?? tr('unknown') | ||||
|                       ])}\n${tr('installedVersionX', args: [ | ||||
|                         app?.app.installedVersion ?? tr('none') | ||||
|                       ])}${trackOnly ? ' ${tr('estimateInBrackets')}\n\n${tr('xIsTrackOnly', args: [ | ||||
|                           tr('app') | ||||
|                         ])}' : ''}', | ||||
|                       ])}${installedVersionIsEstimate ? '\n${tr('estimateInBrackets')}' : ''}', | ||||
|                   textAlign: TextAlign.end, | ||||
|                   style: Theme.of(context).textTheme.bodyLarge!, | ||||
|                 ), | ||||
| @@ -105,11 +108,14 @@ class _AppPageState extends State<AppPage> { | ||||
|               Column( | ||||
|                 children: [ | ||||
|                   const SizedBox( | ||||
|                     height: 4, | ||||
|                     height: 16, | ||||
|                   ), | ||||
|                   Text( | ||||
|                     tr('noVersionDetection'), | ||||
|                     '${trackOnly ? '${tr('xIsTrackOnly', args: [ | ||||
|                             tr('app') | ||||
|                           ])}\n' : ''}${tr('noVersionDetection')}', | ||||
|                     style: Theme.of(context).textTheme.labelSmall, | ||||
|                     textAlign: TextAlign.center, | ||||
|                   ) | ||||
|                 ], | ||||
|               ), | ||||
|   | ||||
| @@ -7,6 +7,7 @@ import 'package:obtainium/pages/apps.dart'; | ||||
| import 'package:obtainium/pages/import_export.dart'; | ||||
| import 'package:obtainium/pages/settings.dart'; | ||||
| import 'package:obtainium/providers/apps_provider.dart'; | ||||
| import 'package:obtainium/providers/settings_provider.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
|  | ||||
| class HomePage extends StatefulWidget { | ||||
| @@ -26,6 +27,7 @@ class NavigationPageItem { | ||||
|  | ||||
| class _HomePageState extends State<HomePage> { | ||||
|   List<int> selectedIndexHistory = []; | ||||
|   bool isReversing = false; | ||||
|   int prevAppCount = -1; | ||||
|   bool prevIsLoading = true; | ||||
|  | ||||
| @@ -41,8 +43,18 @@ class _HomePageState extends State<HomePage> { | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     AppsProvider appsProvider = context.watch<AppsProvider>(); | ||||
|     SettingsProvider settingsProvider = context.watch<SettingsProvider>(); | ||||
|  | ||||
|     setIsReversing(int targetIndex) { | ||||
|       bool reversing = selectedIndexHistory.isNotEmpty && | ||||
|           selectedIndexHistory.last > targetIndex; | ||||
|       setState(() { | ||||
|         isReversing = reversing; | ||||
|       }); | ||||
|     } | ||||
|  | ||||
|     switchToPage(int index) async { | ||||
|       setIsReversing(index); | ||||
|       if (index == 0) { | ||||
|         while ((pages[0].widget.key as GlobalKey<AppsPageState>).currentState != | ||||
|             null) { | ||||
| @@ -79,6 +91,12 @@ class _HomePageState extends State<HomePage> { | ||||
|         child: Scaffold( | ||||
|           backgroundColor: Theme.of(context).colorScheme.surface, | ||||
|           body: PageTransitionSwitcher( | ||||
|             duration: Duration( | ||||
|                 milliseconds: | ||||
|                     settingsProvider.disablePageTransitions ? 0 : 300), | ||||
|             reverse: settingsProvider.reversePageTransitions | ||||
|                 ? !isReversing | ||||
|                 : isReversing, | ||||
|             transitionBuilder: ( | ||||
|               Widget child, | ||||
|               Animation<double> animation, | ||||
| @@ -104,13 +122,16 @@ class _HomePageState extends State<HomePage> { | ||||
|                 .toList(), | ||||
|             onDestinationSelected: (int index) async { | ||||
|               HapticFeedback.selectionClick(); | ||||
|               await switchToPage(index); | ||||
|               switchToPage(index); | ||||
|             }, | ||||
|             selectedIndex: | ||||
|                 selectedIndexHistory.isEmpty ? 0 : selectedIndexHistory.last, | ||||
|           ), | ||||
|         ), | ||||
|         onWillPop: () async { | ||||
|           setIsReversing(selectedIndexHistory.length >= 2 | ||||
|               ? selectedIndexHistory.reversed.toList()[1] | ||||
|               : 0); | ||||
|           if (selectedIndexHistory.isNotEmpty) { | ||||
|             setState(() { | ||||
|               selectedIndexHistory.removeLast(); | ||||
|   | ||||
| @@ -396,6 +396,36 @@ class _SettingsPageState extends State<SettingsPage> { | ||||
|                                     }) | ||||
|                               ], | ||||
|                             ), | ||||
|                             height16, | ||||
|                             Row( | ||||
|                               mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|                               children: [ | ||||
|                                 Flexible( | ||||
|                                     child: Text(tr('disablePageTransitions'))), | ||||
|                                 Switch( | ||||
|                                     value: | ||||
|                                         settingsProvider.disablePageTransitions, | ||||
|                                     onChanged: (value) { | ||||
|                                       settingsProvider.disablePageTransitions = | ||||
|                                           value; | ||||
|                                     }) | ||||
|                               ], | ||||
|                             ), | ||||
|                             height16, | ||||
|                             Row( | ||||
|                               mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|                               children: [ | ||||
|                                 Flexible( | ||||
|                                     child: Text(tr('reversePageTransitions'))), | ||||
|                                 Switch( | ||||
|                                     value: | ||||
|                                         settingsProvider.reversePageTransitions, | ||||
|                                     onChanged: (value) { | ||||
|                                       settingsProvider.reversePageTransitions = | ||||
|                                           value; | ||||
|                                     }) | ||||
|                               ], | ||||
|                             ), | ||||
|                             height32, | ||||
|                             Text( | ||||
|                               tr('categories'), | ||||
|   | ||||
| @@ -117,7 +117,7 @@ class AppsProvider with ChangeNotifier { | ||||
|     foregroundStream = FGBGEvents.stream.asBroadcastStream(); | ||||
|     foregroundSubscription = foregroundStream?.listen((event) async { | ||||
|       isForeground = event == FGBGType.foreground; | ||||
|       if (isForeground) await refreshInstallStatuses(); | ||||
|       if (isForeground) await loadApps(); | ||||
|     }); | ||||
|     () async { | ||||
|       var cacheDirs = await getExternalCacheDirectories(); | ||||
| @@ -341,20 +341,33 @@ class AppsProvider with ChangeNotifier { | ||||
|  | ||||
|   Future<void> installXApkDir(DownloadedXApkDir dir, | ||||
|       {bool silent = false}) async { | ||||
|     // We don't know which APKs in an XAPK are supported by the user's device | ||||
|     // So we try installing all of them and assume success if at least one installed | ||||
|     // If 0 APKs installed, throw the first install error encountered | ||||
|     try { | ||||
|       var somethingInstalled = false; | ||||
|       var firstError = null; | ||||
|       for (var file in dir.extracted | ||||
|           .listSync(recursive: true, followLinks: false) | ||||
|           .whereType<File>()) { | ||||
|         if (file.path.toLowerCase().endsWith('.apk')) { | ||||
|           try { | ||||
|             somethingInstalled = somethingInstalled || | ||||
|               await installApk(DownloadedApk(dir.appId, file), silent: silent); | ||||
|                 await installApk(DownloadedApk(dir.appId, file), | ||||
|                     silent: silent); | ||||
|           } catch (e) { | ||||
|             logs.add( | ||||
|                 'Could not install APK from XAPK \'${file.path}\': ${e.toString()}'); | ||||
|             firstError ??= e; | ||||
|           } | ||||
|         } else if (file.path.toLowerCase().endsWith('.obb')) { | ||||
|           await moveObbFile(file, dir.appId); | ||||
|         } | ||||
|       } | ||||
|       if (somethingInstalled) { | ||||
|         dir.file.delete(recursive: true); | ||||
|       } else if (firstError) { | ||||
|         throw firstError; | ||||
|       } | ||||
|     } finally { | ||||
|       dir.extracted.delete(recursive: true); | ||||
| @@ -725,21 +738,12 @@ class AppsProvider with ChangeNotifier { | ||||
|     notifyListeners(); | ||||
|     var sp = SourceProvider(); | ||||
|     List<List<String>> errors = []; | ||||
|     List<FileSystemEntity> newApps = (await getAppsDir()) | ||||
|     List<App?> newApps = (await getAppsDir()) // Parse Apps from JSON | ||||
|         .listSync() | ||||
|         .where((item) => item.path.toLowerCase().endsWith('.json')) | ||||
|         .toList(); | ||||
|     for (var e in newApps) { | ||||
|         .map((e) { | ||||
|       try { | ||||
|         var app = App.fromJson(jsonDecode(File(e.path).readAsStringSync())); | ||||
|         try { | ||||
|           var info = await getInstalledInfo(app.id); | ||||
|           sp.getSource(app.url, overrideSource: app.overrideSource); | ||||
|           apps[app.id] = AppInMemory(app, null, info); | ||||
|           notifyListeners(); | ||||
|         } catch (e) { | ||||
|           errors.add([app.id, app.finalName, e.toString()]); | ||||
|         } | ||||
|         return App.fromJson(jsonDecode(File(e.path).readAsStringSync())); | ||||
|       } catch (err) { | ||||
|         if (err is FormatException) { | ||||
|           logs.add('Corrupt JSON when loading App (will be ignored): $e'); | ||||
| @@ -748,28 +752,40 @@ class AppsProvider with ChangeNotifier { | ||||
|           rethrow; | ||||
|         } | ||||
|       } | ||||
|     }).toList(); | ||||
|     for (var app in newApps) { | ||||
|       // Put Apps into memory to list them (fast) | ||||
|       if (app != null) { | ||||
|         try { | ||||
|           sp.getSource(app.url, overrideSource: app.overrideSource); | ||||
|           apps.update( | ||||
|               app.id, | ||||
|               (value) => | ||||
|                   AppInMemory(app, value.downloadProgress, value.installedInfo), | ||||
|               ifAbsent: () => AppInMemory(app, null, null)); | ||||
|         } catch (e) { | ||||
|           errors.add([app.id, app.finalName, e.toString()]); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     notifyListeners(); | ||||
|     if (errors.isNotEmpty) { | ||||
|       removeApps(errors.map((e) => e[0]).toList()); | ||||
|       NotificationsProvider().notify( | ||||
|           AppsRemovedNotification(errors.map((e) => [e[1], e[2]]).toList())); | ||||
|     } | ||||
|     loadingApps = false; | ||||
|     notifyListeners(); | ||||
|  | ||||
|     refreshInstallStatuses(useExistingInstalledInfo: true); | ||||
|   } | ||||
|  | ||||
|   Future<void> refreshInstallStatuses( | ||||
|       {bool useExistingInstalledInfo = false}) async { | ||||
|     if (await doesInstalledAppsPluginWork()) { | ||||
|       for (var app in apps.values) { | ||||
|         // Check install status for each App (slow) | ||||
|         apps[app.app.id]?.installedInfo = await getInstalledInfo(app.app.id); | ||||
|         notifyListeners(); | ||||
|       } | ||||
|       // Reconcile version differences | ||||
|       List<App> modifiedApps = []; | ||||
|       for (var app in apps.values) { | ||||
|         var moddedApp = getCorrectedInstallStatusAppIfPossible( | ||||
|             app.app, | ||||
|             useExistingInstalledInfo | ||||
|                 ? app.installedInfo | ||||
|                 : await getInstalledInfo(app.app.id)); | ||||
|         var moddedApp = | ||||
|             getCorrectedInstallStatusAppIfPossible(app.app, app.installedInfo); | ||||
|         if (moddedApp != null) { | ||||
|           modifiedApps.add(moddedApp); | ||||
|         } | ||||
| @@ -780,6 +796,7 @@ class AppsProvider with ChangeNotifier { | ||||
|             .where((a) => a.installedVersion == null) | ||||
|             .map((e) => e.id) | ||||
|             .toList(); | ||||
|         // After reconciliation, delete externally uninstalled Apps if needed | ||||
|         if (removedAppIds.isNotEmpty) { | ||||
|           var settingsProvider = SettingsProvider(); | ||||
|           await settingsProvider.initializeSettings(); | ||||
| @@ -789,6 +806,9 @@ class AppsProvider with ChangeNotifier { | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     loadingApps = false; | ||||
|     notifyListeners(); | ||||
|   } | ||||
|  | ||||
|   Future<void> saveApps(List<App> apps, | ||||
|   | ||||
| @@ -291,4 +291,22 @@ class SettingsProvider with ChangeNotifier { | ||||
|     prefs?.setBool('checkUpdateOnDetailPage', show); | ||||
|     notifyListeners(); | ||||
|   } | ||||
|  | ||||
|   bool get disablePageTransitions { | ||||
|     return prefs?.getBool('disablePageTransitions') ?? false; | ||||
|   } | ||||
|  | ||||
|   set disablePageTransitions(bool show) { | ||||
|     prefs?.setBool('disablePageTransitions', show); | ||||
|     notifyListeners(); | ||||
|   } | ||||
|  | ||||
|   bool get reversePageTransitions { | ||||
|     return prefs?.getBool('reversePageTransitions') ?? false; | ||||
|   } | ||||
|  | ||||
|   set reversePageTransitions(bool show) { | ||||
|     prefs?.setBool('reversePageTransitions', show); | ||||
|     notifyListeners(); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -594,9 +594,7 @@ class SourceProvider { | ||||
|     } | ||||
|     String apkVersion = apk.version.replaceAll('/', '-'); | ||||
|     var name = currentApp != null ? currentApp.name.trim() : ''; | ||||
|     name = name.isNotEmpty | ||||
|         ? name | ||||
|         : apk.names.name[0].toUpperCase() + apk.names.name.substring(1); | ||||
|     name = name.isNotEmpty ? name : apk.names.name; | ||||
|     return App( | ||||
|         currentApp?.id ?? | ||||
|             ((!source.appIdInferIsOptional || | ||||
| @@ -606,7 +604,7 @@ class SourceProvider { | ||||
|                 : null) ?? | ||||
|             generateTempID(standardUrl, additionalSettings), | ||||
|         standardUrl, | ||||
|         apk.names.author[0].toUpperCase() + apk.names.author.substring(1), | ||||
|         apk.names.author, | ||||
|         name, | ||||
|         currentApp?.installedVersion, | ||||
|         apkVersion, | ||||
|   | ||||
| @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev | ||||
| # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html | ||||
| # In Windows, build-name is used as the major, minor, and patch parts | ||||
| # of the product and file versions while build-number is used as the build suffix. | ||||
| version: 0.13.15+179 # When changing this, update the tag in main() accordingly | ||||
| version: 0.13.18+182 # When changing this, update the tag in main() accordingly | ||||
|  | ||||
| environment: | ||||
|   sdk: '>=2.18.2 <3.0.0' | ||||
|   | ||||
		Reference in New Issue
	
	Block a user