mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-08-11 01:20:16 +02:00
More search options (#1107)
This commit is contained in:
@@ -223,7 +223,7 @@
|
|||||||
"moveNonInstalledAppsToBottom": "Premjesti neinstalirane aplikacije na dno prikaza aplikacija",
|
"moveNonInstalledAppsToBottom": "Premjesti neinstalirane aplikacije na dno prikaza aplikacija",
|
||||||
"gitlabPATLabel": "GitLab token za lični pristup\n(Omogućava pretraživanje i bolje otkrivanje APK-a)",
|
"gitlabPATLabel": "GitLab token za lični pristup\n(Omogućava pretraživanje i bolje otkrivanje APK-a)",
|
||||||
"about": "O nama",
|
"about": "O nama",
|
||||||
"requiresCredentialsInSettings": "Za ovo su potrebni dodatni akreditivi (u Postavkama)",
|
"requiresCredentialsInSettings": "{}: Za ovo su potrebni dodatni akreditivi (u Postavkama)",
|
||||||
"checkOnStart": "Provjerite ima li novosti pri pokretanju",
|
"checkOnStart": "Provjerite ima li novosti pri pokretanju",
|
||||||
"tryInferAppIdFromCode": "Pokušati otkriti ID aplikacije iz izvornog koda",
|
"tryInferAppIdFromCode": "Pokušati otkriti ID aplikacije iz izvornog koda",
|
||||||
"removeOnExternalUninstall": "Automatski ukloni eksterno deinstalirane aplikacije",
|
"removeOnExternalUninstall": "Automatski ukloni eksterno deinstalirane aplikacije",
|
||||||
|
@@ -223,7 +223,7 @@
|
|||||||
"moveNonInstalledAppsToBottom": "Přesunout nenainstalované aplikace na konec zobrazení Aplikace",
|
"moveNonInstalledAppsToBottom": "Přesunout nenainstalované aplikace na konec zobrazení Aplikace",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token\n(Umožňuje vyhledávání a lepší zjišťování APK)",
|
"gitlabPATLabel": "GitLab Personal Access Token\n(Umožňuje vyhledávání a lepší zjišťování APK)",
|
||||||
"about": "About",
|
"about": "About",
|
||||||
"requiresCredentialsInSettings": "Vyžaduje další pověření (v nastavení)",
|
"requiresCredentialsInSettings": "{}: Vyžaduje další pověření (v nastavení)",
|
||||||
"checkOnStart": "Zkontrolovat jednou při spuštění",
|
"checkOnStart": "Zkontrolovat jednou při spuštění",
|
||||||
"tryInferAppIdFromCode": "Pokusit se určit ID aplikace ze zdrojového kódu",
|
"tryInferAppIdFromCode": "Pokusit se určit ID aplikace ze zdrojového kódu",
|
||||||
"removeOnExternalUninstall": "Automaticky odstranit externě odinstalované aplikace",
|
"removeOnExternalUninstall": "Automaticky odstranit externě odinstalované aplikace",
|
||||||
|
@@ -223,7 +223,7 @@
|
|||||||
"moveNonInstalledAppsToBottom": "Nicht installierte Apps ans Ende der Apps Ansicht verschieben",
|
"moveNonInstalledAppsToBottom": "Nicht installierte Apps ans Ende der Apps Ansicht verschieben",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token\n(Aktiviert Suche und bessere APK Entdeckung)",
|
"gitlabPATLabel": "GitLab Personal Access Token\n(Aktiviert Suche und bessere APK Entdeckung)",
|
||||||
"about": "Über",
|
"about": "Über",
|
||||||
"requiresCredentialsInSettings": "Benötigt zusätzliche Anmeldedaten (in den Einstellungen)",
|
"requiresCredentialsInSettings": "{}: Benötigt zusätzliche Anmeldedaten (in den Einstellungen)",
|
||||||
"checkOnStart": "Überprüfe einmalig beim Start",
|
"checkOnStart": "Überprüfe einmalig beim Start",
|
||||||
"tryInferAppIdFromCode": "Versuche, die App-ID aus dem Quellcode zu ermitteln",
|
"tryInferAppIdFromCode": "Versuche, die App-ID aus dem Quellcode zu ermitteln",
|
||||||
"removeOnExternalUninstall": "Automatisches Entfernen von extern deinstallierten Apps",
|
"removeOnExternalUninstall": "Automatisches Entfernen von extern deinstallierten Apps",
|
||||||
|
@@ -223,7 +223,7 @@
|
|||||||
"moveNonInstalledAppsToBottom": "Move non-installed Apps to bottom of Apps view",
|
"moveNonInstalledAppsToBottom": "Move non-installed Apps to bottom of Apps view",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token\n(Enables Search and Better APK Discovery)",
|
"gitlabPATLabel": "GitLab Personal Access Token\n(Enables Search and Better APK Discovery)",
|
||||||
"about": "About",
|
"about": "About",
|
||||||
"requiresCredentialsInSettings": "This needs additional credentials (in Settings)",
|
"requiresCredentialsInSettings": "{} needs additional credentials (in Settings)",
|
||||||
"checkOnStart": "Check for updates on startup",
|
"checkOnStart": "Check for updates on startup",
|
||||||
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
||||||
"removeOnExternalUninstall": "Automatically remove externally uninstalled Apps",
|
"removeOnExternalUninstall": "Automatically remove externally uninstalled Apps",
|
||||||
|
@@ -223,7 +223,7 @@
|
|||||||
"moveNonInstalledAppsToBottom": "Move non-installed Apps to bottom of Apps view",
|
"moveNonInstalledAppsToBottom": "Move non-installed Apps to bottom of Apps view",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token\n(Enables Search and Better APK Discovery)",
|
"gitlabPATLabel": "GitLab Personal Access Token\n(Enables Search and Better APK Discovery)",
|
||||||
"about": "About",
|
"about": "About",
|
||||||
"requiresCredentialsInSettings": "This needs additional credentials (in Settings)",
|
"requiresCredentialsInSettings": "{}: This needs additional credentials (in Settings)",
|
||||||
"checkOnStart": "Check for updates on startup",
|
"checkOnStart": "Check for updates on startup",
|
||||||
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
||||||
"removeOnExternalUninstall": "Automatically remove externally uninstalled Apps",
|
"removeOnExternalUninstall": "Automatically remove externally uninstalled Apps",
|
||||||
|
@@ -223,7 +223,7 @@
|
|||||||
"moveNonInstalledAppsToBottom": "برنامه های نصب نشده را به نمای پایین برنامه ها منتقل کنید",
|
"moveNonInstalledAppsToBottom": "برنامه های نصب نشده را به نمای پایین برنامه ها منتقل کنید",
|
||||||
"gitlabPATLabel": "رمز دسترسی شخصی GitLab\n(جستجو و کشف بهتر APK را فعال میکند)",
|
"gitlabPATLabel": "رمز دسترسی شخصی GitLab\n(جستجو و کشف بهتر APK را فعال میکند)",
|
||||||
"about": "درباره",
|
"about": "درباره",
|
||||||
"requiresCredentialsInSettings": "این به اعتبارنامه های اضافی نیاز دارد (در تنظیمات)",
|
"requiresCredentialsInSettings": "{}: این به اعتبارنامه های اضافی نیاز دارد (در تنظیمات)",
|
||||||
"checkOnStart": "بررسی در شروع",
|
"checkOnStart": "بررسی در شروع",
|
||||||
"tryInferAppIdFromCode": "شناسه برنامه را از کد منبع استنباط کنید",
|
"tryInferAppIdFromCode": "شناسه برنامه را از کد منبع استنباط کنید",
|
||||||
"removeOnExternalUninstall": "حذف خودکار برنامه های حذف نصب شده خارجی",
|
"removeOnExternalUninstall": "حذف خودکار برنامه های حذف نصب شده خارجی",
|
||||||
|
@@ -223,7 +223,7 @@
|
|||||||
"moveNonInstalledAppsToBottom": "Move non-installed Apps to bottom of Apps view",
|
"moveNonInstalledAppsToBottom": "Move non-installed Apps to bottom of Apps view",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token\n(Enables Search and Better APK Discovery)",
|
"gitlabPATLabel": "GitLab Personal Access Token\n(Enables Search and Better APK Discovery)",
|
||||||
"about": "About",
|
"about": "About",
|
||||||
"requiresCredentialsInSettings": "This needs additional credentials (in Settings)",
|
"requiresCredentialsInSettings": "{}: This needs additional credentials (in Settings)",
|
||||||
"checkOnStart": "Check for updates on startup",
|
"checkOnStart": "Check for updates on startup",
|
||||||
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
||||||
"removeOnExternalUninstall": "Automatically remove externally uninstalled Apps",
|
"removeOnExternalUninstall": "Automatically remove externally uninstalled Apps",
|
||||||
|
@@ -223,7 +223,7 @@
|
|||||||
"moveNonInstalledAppsToBottom": "Helyezze át a nem telepített appokat az App nézet aljára",
|
"moveNonInstalledAppsToBottom": "Helyezze át a nem telepített appokat az App nézet aljára",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token\n(Engedélyezi a Keresést és jobb APK felfedezés)",
|
"gitlabPATLabel": "GitLab Personal Access Token\n(Engedélyezi a Keresést és jobb APK felfedezés)",
|
||||||
"about": "Rólunk",
|
"about": "Rólunk",
|
||||||
"requiresCredentialsInSettings": "Ehhez további hitelesítő adatokra van szükség (a Beállításokban)",
|
"requiresCredentialsInSettings": "{}: Ehhez további hitelesítő adatokra van szükség (a Beállításokban)",
|
||||||
"checkOnStart": "Egyszer az alkalmazás indításakor is",
|
"checkOnStart": "Egyszer az alkalmazás indításakor is",
|
||||||
"tryInferAppIdFromCode": "Próbálja kikövetkeztetni az app azonosítót a forráskódból",
|
"tryInferAppIdFromCode": "Próbálja kikövetkeztetni az app azonosítót a forráskódból",
|
||||||
"removeOnExternalUninstall": "A külsőleg eltávolított appok auto. eltávolítása",
|
"removeOnExternalUninstall": "A külsőleg eltávolított appok auto. eltávolítása",
|
||||||
|
@@ -223,7 +223,7 @@
|
|||||||
"moveNonInstalledAppsToBottom": "Sposta le app non installate in fondo alla lista",
|
"moveNonInstalledAppsToBottom": "Sposta le app non installate in fondo alla lista",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token\n(attiva la ricerca e migliora la rilevazione di apk)",
|
"gitlabPATLabel": "GitLab Personal Access Token\n(attiva la ricerca e migliora la rilevazione di apk)",
|
||||||
"about": "Informazioni",
|
"about": "Informazioni",
|
||||||
"requiresCredentialsInSettings": "Servono credenziali aggiuntive (in Impostazioni)",
|
"requiresCredentialsInSettings": "{}: Servono credenziali aggiuntive (in Impostazioni)",
|
||||||
"checkOnStart": "Controlla una volta all'avvio",
|
"checkOnStart": "Controlla una volta all'avvio",
|
||||||
"tryInferAppIdFromCode": "Prova a dedurre l'ID dell'app dal codice sorgente",
|
"tryInferAppIdFromCode": "Prova a dedurre l'ID dell'app dal codice sorgente",
|
||||||
"removeOnExternalUninstall": "Rimuovi automaticamente app disinstallate esternamente",
|
"removeOnExternalUninstall": "Rimuovi automaticamente app disinstallate esternamente",
|
||||||
|
@@ -223,7 +223,7 @@
|
|||||||
"moveNonInstalledAppsToBottom": "未インストールのアプリをアプリ一覧の下部に移動させる",
|
"moveNonInstalledAppsToBottom": "未インストールのアプリをアプリ一覧の下部に移動させる",
|
||||||
"gitlabPATLabel": "GitLab パーソナルアクセストークン\n(検索とより良いAPK検出の有効化)",
|
"gitlabPATLabel": "GitLab パーソナルアクセストークン\n(検索とより良いAPK検出の有効化)",
|
||||||
"about": "概要",
|
"about": "概要",
|
||||||
"requiresCredentialsInSettings": "これには追加の認証が必要です (設定にて)",
|
"requiresCredentialsInSettings": "{}: これには追加の認証が必要です (設定にて)",
|
||||||
"checkOnStart": "起動時にアップデートを確認する",
|
"checkOnStart": "起動時にアップデートを確認する",
|
||||||
"tryInferAppIdFromCode": "ソースコードからApp IDを推測する",
|
"tryInferAppIdFromCode": "ソースコードからApp IDを推測する",
|
||||||
"removeOnExternalUninstall": "外部でアンインストールされたアプリを自動的に削除する",
|
"removeOnExternalUninstall": "外部でアンインストールされたアプリを自動的に削除する",
|
||||||
|
@@ -223,7 +223,7 @@
|
|||||||
"moveNonInstalledAppsToBottom": "Verplaats niet-geïnstalleerde apps naar de onderkant van de apps-weergave",
|
"moveNonInstalledAppsToBottom": "Verplaats niet-geïnstalleerde apps naar de onderkant van de apps-weergave",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token\n(Maakt het mogelijk beter te zoeken naar APK's)",
|
"gitlabPATLabel": "GitLab Personal Access Token\n(Maakt het mogelijk beter te zoeken naar APK's)",
|
||||||
"about": "Over",
|
"about": "Over",
|
||||||
"requiresCredentialsInSettings": "Dit vereist aanvullende referenties (in Instellingen)",
|
"requiresCredentialsInSettings": "{}: Dit vereist aanvullende referenties (in Instellingen)",
|
||||||
"checkOnStart": "Controleren op updates bij opstarten",
|
"checkOnStart": "Controleren op updates bij opstarten",
|
||||||
"tryInferAppIdFromCode": "Probeer de app-ID af te leiden uit de broncode",
|
"tryInferAppIdFromCode": "Probeer de app-ID af te leiden uit de broncode",
|
||||||
"removeOnExternalUninstall": "Automatisch extern verwijderde apps verwijderen",
|
"removeOnExternalUninstall": "Automatisch extern verwijderde apps verwijderen",
|
||||||
|
@@ -223,7 +223,7 @@
|
|||||||
"moveNonInstalledAppsToBottom": "Przenieś niezainstalowane aplikacje na dół widoku aplikacji",
|
"moveNonInstalledAppsToBottom": "Przenieś niezainstalowane aplikacje na dół widoku aplikacji",
|
||||||
"gitlabPATLabel": "Osobisty token dostępu GitLab\n(Umożliwia wyszukiwanie i lepsze wykrywanie APK)",
|
"gitlabPATLabel": "Osobisty token dostępu GitLab\n(Umożliwia wyszukiwanie i lepsze wykrywanie APK)",
|
||||||
"about": "Więcej informacji",
|
"about": "Więcej informacji",
|
||||||
"requiresCredentialsInSettings": "Wymaga to dodatkowych poświadczeń (w Ustawieniach)",
|
"requiresCredentialsInSettings": "{}: Wymaga to dodatkowych poświadczeń (w Ustawieniach)",
|
||||||
"checkOnStart": "Sprawdź aktualizacje przy uruchomieniu",
|
"checkOnStart": "Sprawdź aktualizacje przy uruchomieniu",
|
||||||
"tryInferAppIdFromCode": "Spróbuj wywnioskować identyfikator aplikacji z kodu źródłowego",
|
"tryInferAppIdFromCode": "Spróbuj wywnioskować identyfikator aplikacji z kodu źródłowego",
|
||||||
"removeOnExternalUninstall": "Automatyczne usuń odinstalowane zewnętrznie aplikacje",
|
"removeOnExternalUninstall": "Automatyczne usuń odinstalowane zewnętrznie aplikacje",
|
||||||
|
@@ -223,7 +223,7 @@
|
|||||||
"moveNonInstalledAppsToBottom": "Mover Apps não instalados para o fundo da visão de Apps",
|
"moveNonInstalledAppsToBottom": "Mover Apps não instalados para o fundo da visão de Apps",
|
||||||
"gitlabPATLabel": "Token de Acceso Pessoal do Gitlab\n(Ativa Pesquisa e Melhor Descoberta de APKs)",
|
"gitlabPATLabel": "Token de Acceso Pessoal do Gitlab\n(Ativa Pesquisa e Melhor Descoberta de APKs)",
|
||||||
"about": "Sobre",
|
"about": "Sobre",
|
||||||
"requiresCredentialsInSettings": "Isso requer credenciais adicionais (em Configurações)",
|
"requiresCredentialsInSettings": "{}: Isso requer credenciais adicionais (em Configurações)",
|
||||||
"checkOnStart": "Checar por atualizações ao iniciar ",
|
"checkOnStart": "Checar por atualizações ao iniciar ",
|
||||||
"tryInferAppIdFromCode": "Tente inferir o ID do App pelo código fonte",
|
"tryInferAppIdFromCode": "Tente inferir o ID do App pelo código fonte",
|
||||||
"removeOnExternalUninstall": "Remover automaticamente Apps desinstalados externamente",
|
"removeOnExternalUninstall": "Remover automaticamente Apps desinstalados externamente",
|
||||||
|
@@ -223,7 +223,7 @@
|
|||||||
"moveNonInstalledAppsToBottom": "Отображать неустановленные приложения внизу списка",
|
"moveNonInstalledAppsToBottom": "Отображать неустановленные приложения внизу списка",
|
||||||
"gitlabPATLabel": "Персональный токен доступа GitLab\n(включает поиск и улучшает обнаружение APK)",
|
"gitlabPATLabel": "Персональный токен доступа GitLab\n(включает поиск и улучшает обнаружение APK)",
|
||||||
"about": "Описание",
|
"about": "Описание",
|
||||||
"requiresCredentialsInSettings": "Для этого требуются дополнительные учетные данные (в настройках)",
|
"requiresCredentialsInSettings": "{}: Для этого требуются дополнительные учетные данные (в настройках)",
|
||||||
"checkOnStart": "Проверять наличие обновлений при запуске",
|
"checkOnStart": "Проверять наличие обновлений при запуске",
|
||||||
"tryInferAppIdFromCode": "Попытаться определить ID приложения из исходного кода",
|
"tryInferAppIdFromCode": "Попытаться определить ID приложения из исходного кода",
|
||||||
"removeOnExternalUninstall": "Автоматически убирать из списка удаленные извне приложения",
|
"removeOnExternalUninstall": "Автоматически убирать из списка удаленные извне приложения",
|
||||||
|
@@ -223,7 +223,7 @@
|
|||||||
"moveNonInstalledAppsToBottom": "Move non-installed Apps to bottom of Apps view",
|
"moveNonInstalledAppsToBottom": "Move non-installed Apps to bottom of Apps view",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token\n(Enables Search and Better APK Discovery)",
|
"gitlabPATLabel": "GitLab Personal Access Token\n(Enables Search and Better APK Discovery)",
|
||||||
"about": "Om",
|
"about": "Om",
|
||||||
"requiresCredentialsInSettings": "This needs additional credentials (in Settings)",
|
"requiresCredentialsInSettings": "{}: This needs additional credentials (in Settings)",
|
||||||
"checkOnStart": "Kolla efter uppdateringar vid start",
|
"checkOnStart": "Kolla efter uppdateringar vid start",
|
||||||
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
||||||
"removeOnExternalUninstall": "Automatically remove externally uninstalled Apps",
|
"removeOnExternalUninstall": "Automatically remove externally uninstalled Apps",
|
||||||
|
@@ -223,7 +223,7 @@
|
|||||||
"moveNonInstalledAppsToBottom": "Yüklenmemiş Uygulamaları Uygulamalar Görünümünün Altına Taşı",
|
"moveNonInstalledAppsToBottom": "Yüklenmemiş Uygulamaları Uygulamalar Görünümünün Altına Taşı",
|
||||||
"gitlabPATLabel": "GitLab Kişisel Erişim Belirteci\n(Arama ve Daha İyi APK Keşfi İçin)",
|
"gitlabPATLabel": "GitLab Kişisel Erişim Belirteci\n(Arama ve Daha İyi APK Keşfi İçin)",
|
||||||
"about": "Hakkında",
|
"about": "Hakkında",
|
||||||
"requiresCredentialsInSettings": "Bu, ek kimlik bilgilerine ihtiyaç duyar (Ayarlar'da)",
|
"requiresCredentialsInSettings": "{}: Bu, ek kimlik bilgilerine ihtiyaç duyar (Ayarlar'da)",
|
||||||
"checkOnStart": "Başlangıçta güncellemeleri kontrol et",
|
"checkOnStart": "Başlangıçta güncellemeleri kontrol et",
|
||||||
"tryInferAppIdFromCode": "Uygulama kimliğini kaynak kodundan çıkarma girişimi",
|
"tryInferAppIdFromCode": "Uygulama kimliğini kaynak kodundan çıkarma girişimi",
|
||||||
"removeOnExternalUninstall": "Harici kaldırmada otomatik olarak kaldırılan uygulamalar",
|
"removeOnExternalUninstall": "Harici kaldırmada otomatik olarak kaldırılan uygulamalar",
|
||||||
|
@@ -223,7 +223,7 @@
|
|||||||
"moveNonInstalledAppsToBottom": "Di chuyển Ứng dụng chưa được cài đặt xuống cuối chế độ xem Ứng dụng",
|
"moveNonInstalledAppsToBottom": "Di chuyển Ứng dụng chưa được cài đặt xuống cuối chế độ xem Ứng dụng",
|
||||||
"gitlabPATLabel": "Mã thông báo truy cập cá nhân GitLab\n(Cho phép tìm kiếm và khám phá APK tốt hơn)",
|
"gitlabPATLabel": "Mã thông báo truy cập cá nhân GitLab\n(Cho phép tìm kiếm và khám phá APK tốt hơn)",
|
||||||
"about": "Giới thiệu",
|
"about": "Giới thiệu",
|
||||||
"requiresCredentialsInSettings": "Điều này cần thông tin xác thực bổ sung (trong Cài đặt)",
|
"requiresCredentialsInSettings": "{}: Điều này cần thông tin xác thực bổ sung (trong Cài đặt)",
|
||||||
"checkOnStart": "Kiểm tra các bản cập nhật khi khởi động",
|
"checkOnStart": "Kiểm tra các bản cập nhật khi khởi động",
|
||||||
"tryInferAppIdFromCode": "Thử suy ra ID ứng dụng từ mã nguồn",
|
"tryInferAppIdFromCode": "Thử suy ra ID ứng dụng từ mã nguồn",
|
||||||
"removeOnExternalUninstall": "Tự động xóa ứng dụng đã gỡ cài đặt bên ngoài",
|
"removeOnExternalUninstall": "Tự động xóa ứng dụng đã gỡ cài đặt bên ngoài",
|
||||||
|
@@ -223,7 +223,7 @@
|
|||||||
"moveNonInstalledAppsToBottom": "将未安装应用置底",
|
"moveNonInstalledAppsToBottom": "将未安装应用置底",
|
||||||
"gitlabPATLabel": "GitLab 个人访问令牌(启用搜索功能并增强 APK 发现)",
|
"gitlabPATLabel": "GitLab 个人访问令牌(启用搜索功能并增强 APK 发现)",
|
||||||
"about": "相关文档",
|
"about": "相关文档",
|
||||||
"requiresCredentialsInSettings": "此功能需要额外的凭据(在“设置”中添加)",
|
"requiresCredentialsInSettings": "{}: 此功能需要额外的凭据(在“设置”中添加)",
|
||||||
"checkOnStart": "启动时进行一次检查",
|
"checkOnStart": "启动时进行一次检查",
|
||||||
"tryInferAppIdFromCode": "尝试从源代码推断应用 ID",
|
"tryInferAppIdFromCode": "尝试从源代码推断应用 ID",
|
||||||
"removeOnExternalUninstall": "自动删除已卸载的外部应用",
|
"removeOnExternalUninstall": "自动删除已卸载的外部应用",
|
||||||
|
@@ -254,13 +254,30 @@ class _AddAppPageState extends State<AddAppPage> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
runSearch() async {
|
runSearch({bool filtered = true}) async {
|
||||||
setState(() {
|
setState(() {
|
||||||
searching = true;
|
searching = true;
|
||||||
});
|
});
|
||||||
|
var sourceStrings = <String, List<String>>{};
|
||||||
|
sourceProvider.sources
|
||||||
|
.where((e) => e.canSearch && !e.excludeFromMassSearch)
|
||||||
|
.forEach((s) {
|
||||||
|
sourceStrings[s.name] = [s.name];
|
||||||
|
});
|
||||||
try {
|
try {
|
||||||
|
var searchSources = await showDialog<List<String>?>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext ctx) {
|
||||||
|
return SelectionModal(
|
||||||
|
entries: sourceStrings,
|
||||||
|
selectedByDefault: true,
|
||||||
|
onlyOneSelectionAllowed: false,
|
||||||
|
titlesAreLinks: false,
|
||||||
|
);
|
||||||
|
}) ??
|
||||||
|
[];
|
||||||
var results = await Future.wait(sourceProvider.sources
|
var results = await Future.wait(sourceProvider.sources
|
||||||
.where((e) => e.canSearch && !e.excludeFromMassSearch)
|
.where((e) => searchSources.contains(e.name))
|
||||||
.map((e) async {
|
.map((e) async {
|
||||||
try {
|
try {
|
||||||
return await e.search(searchQuery);
|
return await e.search(searchQuery);
|
||||||
@@ -268,6 +285,8 @@ class _AddAppPageState extends State<AddAppPage> {
|
|||||||
if (err is! CredsNeededError) {
|
if (err is! CredsNeededError) {
|
||||||
rethrow;
|
rethrow;
|
||||||
} else {
|
} else {
|
||||||
|
err.unexpected = true;
|
||||||
|
showError(err, context);
|
||||||
return <String, List<String>>{};
|
return <String, List<String>>{};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,8 +316,8 @@ class _AddAppPageState extends State<AddAppPage> {
|
|||||||
: await showDialog<List<String>?>(
|
: await showDialog<List<String>?>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext ctx) {
|
builder: (BuildContext ctx) {
|
||||||
return UrlSelectionModal(
|
return SelectionModal(
|
||||||
urlsWithDescriptions: res,
|
entries: res,
|
||||||
selectedByDefault: false,
|
selectedByDefault: false,
|
||||||
onlyOneSelectionAllowed: true,
|
onlyOneSelectionAllowed: true,
|
||||||
);
|
);
|
||||||
@@ -470,23 +489,21 @@ class _AddAppPageState extends State<AddAppPage> {
|
|||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 16,
|
height: 16,
|
||||||
),
|
),
|
||||||
...sourceProvider.sources
|
...sourceProvider.sources.map((e) => GestureDetector(
|
||||||
.map((e) => GestureDetector(
|
onTap: e.host != null
|
||||||
onTap: e.host != null
|
? () {
|
||||||
? () {
|
launchUrlString('https://${e.host}',
|
||||||
launchUrlString('https://${e.host}',
|
mode: LaunchMode.externalApplication);
|
||||||
mode: LaunchMode.externalApplication);
|
}
|
||||||
}
|
: null,
|
||||||
: null,
|
child: Text(
|
||||||
child: Text(
|
'${e.name}${e.enforceTrackOnly ? ' ${tr('trackOnlyInBrackets')}' : ''}${e.canSearch ? ' ${tr('searchableInBrackets')}' : ''}',
|
||||||
'${e.name}${e.enforceTrackOnly ? ' ${tr('trackOnlyInBrackets')}' : ''}${e.canSearch ? ' ${tr('searchableInBrackets')}' : ''}',
|
style: TextStyle(
|
||||||
style: TextStyle(
|
decoration: e.host != null
|
||||||
decoration: e.host != null
|
? TextDecoration.underline
|
||||||
? TextDecoration.underline
|
: TextDecoration.none,
|
||||||
: TextDecoration.none,
|
fontStyle: FontStyle.italic),
|
||||||
fontStyle: FontStyle.italic),
|
)))
|
||||||
)))
|
|
||||||
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
@@ -208,8 +208,8 @@ class _ImportExportPageState extends State<ImportExportPage> {
|
|||||||
await showDialog<List<String>?>(
|
await showDialog<List<String>?>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext ctx) {
|
builder: (BuildContext ctx) {
|
||||||
return UrlSelectionModal(
|
return SelectionModal(
|
||||||
urlsWithDescriptions: urlsWithDescriptions,
|
entries: urlsWithDescriptions,
|
||||||
selectedByDefault: false,
|
selectedByDefault: false,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -269,8 +269,7 @@ class _ImportExportPageState extends State<ImportExportPage> {
|
|||||||
await showDialog<List<String>?>(
|
await showDialog<List<String>?>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext ctx) {
|
builder: (BuildContext ctx) {
|
||||||
return UrlSelectionModal(
|
return SelectionModal(entries: urlsWithDescriptions);
|
||||||
urlsWithDescriptions: urlsWithDescriptions);
|
|
||||||
});
|
});
|
||||||
if (selectedUrls != null) {
|
if (selectedUrls != null) {
|
||||||
var errors = await appsProvider.addAppsByURL(selectedUrls);
|
var errors = await appsProvider.addAppsByURL(selectedUrls);
|
||||||
@@ -300,6 +299,11 @@ class _ImportExportPageState extends State<ImportExportPage> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var sourceStrings = <String, List<String>>{};
|
||||||
|
sourceProvider.sources.where((e) => e.canSearch).forEach((s) {
|
||||||
|
sourceStrings[s.name] = [s.name];
|
||||||
|
});
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||||
body: CustomScrollView(slivers: <Widget>[
|
body: CustomScrollView(slivers: <Widget>[
|
||||||
@@ -409,6 +413,49 @@ class _ImportExportPageState extends State<ImportExportPage> {
|
|||||||
const Divider(
|
const Divider(
|
||||||
height: 32,
|
height: 32,
|
||||||
),
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: TextButton(
|
||||||
|
onPressed: importInProgress
|
||||||
|
? null
|
||||||
|
: () async {
|
||||||
|
var searchSourceName =
|
||||||
|
await showDialog<
|
||||||
|
List<String>?>(
|
||||||
|
context: context,
|
||||||
|
builder:
|
||||||
|
(BuildContext
|
||||||
|
ctx) {
|
||||||
|
return SelectionModal(
|
||||||
|
entries:
|
||||||
|
sourceStrings,
|
||||||
|
selectedByDefault:
|
||||||
|
false,
|
||||||
|
onlyOneSelectionAllowed:
|
||||||
|
true,
|
||||||
|
titlesAreLinks:
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}) ??
|
||||||
|
[];
|
||||||
|
var searchSource =
|
||||||
|
sourceProvider.sources
|
||||||
|
.where((e) =>
|
||||||
|
searchSourceName
|
||||||
|
.contains(
|
||||||
|
e.name))
|
||||||
|
.toList();
|
||||||
|
if (searchSource.isNotEmpty) {
|
||||||
|
runSourceSearch(
|
||||||
|
searchSource[0]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text(tr('searchX',
|
||||||
|
args: [tr('source')])))),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed:
|
onPressed:
|
||||||
importInProgress ? null : urlListImport,
|
importInProgress ? null : urlListImport,
|
||||||
@@ -424,39 +471,19 @@ class _ImportExportPageState extends State<ImportExportPage> {
|
|||||||
)),
|
)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
...sourceProvider.sources
|
...sourceProvider.massUrlSources.map((source) => Column(
|
||||||
.where((element) => element.canSearch)
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
.map((source) => Column(
|
children: [
|
||||||
crossAxisAlignment:
|
const SizedBox(height: 8),
|
||||||
CrossAxisAlignment.stretch,
|
TextButton(
|
||||||
children: [
|
onPressed: importInProgress
|
||||||
const SizedBox(height: 8),
|
? null
|
||||||
TextButton(
|
: () {
|
||||||
onPressed: importInProgress
|
runMassSourceImport(source);
|
||||||
? null
|
},
|
||||||
: () {
|
child: Text(
|
||||||
runSourceSearch(source);
|
tr('importX', args: [source.name])))
|
||||||
},
|
])),
|
||||||
child: Text(
|
|
||||||
tr('searchX', args: [source.name])))
|
|
||||||
]))
|
|
||||||
,
|
|
||||||
...sourceProvider.massUrlSources
|
|
||||||
.map((source) => Column(
|
|
||||||
crossAxisAlignment:
|
|
||||||
CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
TextButton(
|
|
||||||
onPressed: importInProgress
|
|
||||||
? null
|
|
||||||
: () {
|
|
||||||
runMassSourceImport(source);
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
tr('importX', args: [source.name])))
|
|
||||||
]))
|
|
||||||
,
|
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
const Divider(
|
const Divider(
|
||||||
height: 32,
|
height: 32,
|
||||||
@@ -532,38 +559,40 @@ class _ImportErrorDialogState extends State<ImportErrorDialog> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ignore: must_be_immutable
|
// ignore: must_be_immutable
|
||||||
class UrlSelectionModal extends StatefulWidget {
|
class SelectionModal extends StatefulWidget {
|
||||||
UrlSelectionModal(
|
SelectionModal(
|
||||||
{super.key,
|
{super.key,
|
||||||
required this.urlsWithDescriptions,
|
required this.entries,
|
||||||
this.selectedByDefault = true,
|
this.selectedByDefault = true,
|
||||||
this.onlyOneSelectionAllowed = false});
|
this.onlyOneSelectionAllowed = false,
|
||||||
|
this.titlesAreLinks = true});
|
||||||
|
|
||||||
Map<String, List<String>> urlsWithDescriptions;
|
Map<String, List<String>> entries;
|
||||||
bool selectedByDefault;
|
bool selectedByDefault;
|
||||||
bool onlyOneSelectionAllowed;
|
bool onlyOneSelectionAllowed;
|
||||||
|
bool titlesAreLinks;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<UrlSelectionModal> createState() => _UrlSelectionModalState();
|
State<SelectionModal> createState() => _SelectionModalState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _UrlSelectionModalState extends State<UrlSelectionModal> {
|
class _SelectionModalState extends State<SelectionModal> {
|
||||||
Map<MapEntry<String, List<String>>, bool> urlWithDescriptionSelections = {};
|
Map<MapEntry<String, List<String>>, bool> entrySelections = {};
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
for (var url in widget.urlsWithDescriptions.entries) {
|
for (var url in widget.entries.entries) {
|
||||||
urlWithDescriptionSelections.putIfAbsent(url,
|
entrySelections.putIfAbsent(url,
|
||||||
() => widget.selectedByDefault && !widget.onlyOneSelectionAllowed);
|
() => widget.selectedByDefault && !widget.onlyOneSelectionAllowed);
|
||||||
}
|
}
|
||||||
if (widget.selectedByDefault && widget.onlyOneSelectionAllowed) {
|
if (widget.selectedByDefault && widget.onlyOneSelectionAllowed) {
|
||||||
selectOnlyOne(widget.urlsWithDescriptions.entries.first.key);
|
selectOnlyOne(widget.entries.entries.first.key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectOnlyOne(String url) {
|
selectOnlyOne(String url) {
|
||||||
for (var uwd in urlWithDescriptionSelections.keys) {
|
for (var e in entrySelections.keys) {
|
||||||
urlWithDescriptionSelections[uwd] = uwd.key == url;
|
entrySelections[e] = e.key == url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -571,73 +600,88 @@ class _UrlSelectionModalState extends State<UrlSelectionModal> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
scrollable: true,
|
scrollable: true,
|
||||||
title: Text(
|
title: Text(tr('select')),
|
||||||
widget.onlyOneSelectionAllowed ? tr('selectURL') : tr('selectURLs')),
|
|
||||||
content: Column(children: [
|
content: Column(children: [
|
||||||
...urlWithDescriptionSelections.keys.map((urlWithD) {
|
...entrySelections.keys.map((entry) {
|
||||||
selectThis(bool? value) {
|
selectThis(bool? value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
value ??= false;
|
value ??= false;
|
||||||
if (value! && widget.onlyOneSelectionAllowed) {
|
if (value! && widget.onlyOneSelectionAllowed) {
|
||||||
selectOnlyOne(urlWithD.key);
|
selectOnlyOne(entry.key);
|
||||||
} else {
|
} else {
|
||||||
urlWithDescriptionSelections[urlWithD] = value!;
|
entrySelections[entry] = value!;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var urlLink = GestureDetector(
|
var urlLink = GestureDetector(
|
||||||
onTap: () {
|
onTap: !widget.titlesAreLinks
|
||||||
launchUrlString(urlWithD.key,
|
? null
|
||||||
mode: LaunchMode.externalApplication);
|
: () {
|
||||||
},
|
launchUrlString(entry.key,
|
||||||
|
mode: LaunchMode.externalApplication);
|
||||||
|
},
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
urlWithD.value[0],
|
entry.value.isEmpty ? entry.key : entry.value[0],
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
decoration: TextDecoration.underline,
|
decoration: widget.titlesAreLinks
|
||||||
|
? TextDecoration.underline
|
||||||
|
: null,
|
||||||
fontWeight: FontWeight.bold),
|
fontWeight: FontWeight.bold),
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
),
|
),
|
||||||
Text(
|
if (widget.titlesAreLinks)
|
||||||
Uri.parse(urlWithD.key).host,
|
Text(
|
||||||
style: const TextStyle(
|
Uri.parse(entry.key).host,
|
||||||
decoration: TextDecoration.underline, fontSize: 12),
|
style: const TextStyle(
|
||||||
)
|
decoration: TextDecoration.underline, fontSize: 12),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
|
|
||||||
var descriptionText = Text(
|
var descriptionText = entry.value.length <= 1
|
||||||
urlWithD.value[1].length > 128
|
? const SizedBox.shrink()
|
||||||
? '${urlWithD.value[1].substring(0, 128)}...'
|
: Text(
|
||||||
: urlWithD.value[1],
|
entry.value[1].length > 128
|
||||||
style: const TextStyle(fontStyle: FontStyle.italic, fontSize: 12),
|
? '${entry.value[1].substring(0, 128)}...'
|
||||||
);
|
: entry.value[1],
|
||||||
|
style: const TextStyle(
|
||||||
|
fontStyle: FontStyle.italic, fontSize: 12),
|
||||||
|
);
|
||||||
|
|
||||||
var selectedUrlsWithDs = urlWithDescriptionSelections.entries
|
var selectedEntries =
|
||||||
.where((e) => e.value)
|
entrySelections.entries.where((e) => e.value).toList();
|
||||||
.toList();
|
|
||||||
|
|
||||||
var singleSelectTile = ListTile(
|
var singleSelectTile = ListTile(
|
||||||
title: urlLink,
|
title: GestureDetector(
|
||||||
subtitle: GestureDetector(
|
onTap: widget.titlesAreLinks
|
||||||
onTap: () {
|
|
||||||
setState(() {
|
|
||||||
selectOnlyOne(urlWithD.key);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: descriptionText,
|
|
||||||
),
|
|
||||||
leading: Radio<String>(
|
|
||||||
value: urlWithD.key,
|
|
||||||
groupValue: selectedUrlsWithDs.isEmpty
|
|
||||||
? null
|
? null
|
||||||
: selectedUrlsWithDs.first.key.key,
|
: () {
|
||||||
|
selectThis(!(entrySelections[entry] ?? false));
|
||||||
|
},
|
||||||
|
child: urlLink,
|
||||||
|
),
|
||||||
|
subtitle: entry.value.length <= 1
|
||||||
|
? null
|
||||||
|
: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
selectOnlyOne(entry.key);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: descriptionText,
|
||||||
|
),
|
||||||
|
leading: Radio<String>(
|
||||||
|
value: entry.key,
|
||||||
|
groupValue: selectedEntries.isEmpty
|
||||||
|
? null
|
||||||
|
: selectedEntries.first.key.key,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
selectOnlyOne(urlWithD.key);
|
selectOnlyOne(entry.key);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -645,7 +689,7 @@ class _UrlSelectionModalState extends State<UrlSelectionModal> {
|
|||||||
|
|
||||||
var multiSelectTile = Row(children: [
|
var multiSelectTile = Row(children: [
|
||||||
Checkbox(
|
Checkbox(
|
||||||
value: urlWithDescriptionSelections[urlWithD],
|
value: entrySelections[entry],
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
selectThis(value);
|
selectThis(value);
|
||||||
}),
|
}),
|
||||||
@@ -657,20 +701,30 @@ class _UrlSelectionModalState extends State<UrlSelectionModal> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(
|
SizedBox(
|
||||||
height: 8,
|
height: entry.value.length <= 1 ? 16 : 8,
|
||||||
),
|
),
|
||||||
urlLink,
|
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: widget.titlesAreLinks
|
||||||
selectThis(
|
? null
|
||||||
!(urlWithDescriptionSelections[urlWithD] ?? false));
|
: () {
|
||||||
},
|
selectThis(!(entrySelections[entry] ?? false));
|
||||||
child: descriptionText,
|
},
|
||||||
|
child: urlLink,
|
||||||
),
|
),
|
||||||
const SizedBox(
|
entry.value.length <= 1
|
||||||
height: 8,
|
? const SizedBox.shrink()
|
||||||
)
|
: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
selectThis(!(entrySelections[entry] ?? false));
|
||||||
|
},
|
||||||
|
child: descriptionText,
|
||||||
|
),
|
||||||
|
entry.value.length <= 1
|
||||||
|
? const SizedBox.shrink()
|
||||||
|
: const SizedBox(
|
||||||
|
height: 8,
|
||||||
|
)
|
||||||
],
|
],
|
||||||
))
|
))
|
||||||
]);
|
]);
|
||||||
@@ -687,24 +741,18 @@ class _UrlSelectionModalState extends State<UrlSelectionModal> {
|
|||||||
},
|
},
|
||||||
child: Text(tr('cancel'))),
|
child: Text(tr('cancel'))),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed:
|
onPressed: entrySelections.values.where((b) => b).isEmpty
|
||||||
urlWithDescriptionSelections.values.where((b) => b).isEmpty
|
? null
|
||||||
? null
|
: () {
|
||||||
: () {
|
Navigator.of(context).pop(entrySelections.entries
|
||||||
Navigator.of(context).pop(urlWithDescriptionSelections
|
.where((entry) => entry.value)
|
||||||
.entries
|
.map((e) => e.key.key)
|
||||||
.where((entry) => entry.value)
|
.toList());
|
||||||
.map((e) => e.key.key)
|
},
|
||||||
.toList());
|
|
||||||
},
|
|
||||||
child: Text(widget.onlyOneSelectionAllowed
|
child: Text(widget.onlyOneSelectionAllowed
|
||||||
? tr('pick')
|
? tr('pick')
|
||||||
: tr('importX', args: [
|
: tr('importX', args: [
|
||||||
plural(
|
plural('url', entrySelections.values.where((b) => b).length)
|
||||||
'url',
|
|
||||||
urlWithDescriptionSelections.values
|
|
||||||
.where((b) => b)
|
|
||||||
.length)
|
|
||||||
])))
|
])))
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user