diff --git a/assets/translations/de.json b/assets/translations/de.json index 6510dd8..fb3135a 100644 --- a/assets/translations/de.json +++ b/assets/translations/de.json @@ -20,7 +20,6 @@ "githubPATLabel": "GitHub Personal Access Token (Erhöht das Ratenlimit)", "githubPATHint": "PAT muss in diesem Format sein: Benutzername:Token", "githubPATFormat": "Benutzername:Token", - "githubPATLinkText": "Über GitHub PATs", "includePrereleases": "Vorabversionen einbeziehen", "fallbackToOlderReleases": "Fallback auf ältere Versionen", "filterReleaseTitlesByRegEx": "Release-Titel nach regulärem Ausdruck\nfiltern", @@ -229,6 +228,9 @@ "dontShowTrackOnlyWarnings": "Warnung für 'Nur Nachverfolgen' nicht anzeigen", "dontShowAPKOriginWarnings": "Warnung für APK-Herkunft nicht anzeigen", "moveNonInstalledAppsToBottom": "Move Non-Installed Apps to Bottom of Apps View", + "gitlabPATLabel": "GitLab Personal Access Token (Enables Search)", + "about": "About", + "requiresCredentialsInSettings": "This needs additional credentials (in Settings)", "removeAppQuestion": { "one": "App entfernen?", "other": "Apps entfernen?" diff --git a/assets/translations/en.json b/assets/translations/en.json index 606f66f..dd027a9 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -20,7 +20,6 @@ "githubPATLabel": "GitHub Personal Access Token (Increases Rate Limit)", "githubPATHint": "PAT must be in this format: username:token", "githubPATFormat": "username:token", - "githubPATLinkText": "About GitHub PATs", "includePrereleases": "Include prereleases", "fallbackToOlderReleases": "Fallback to older releases", "filterReleaseTitlesByRegEx": "Filter Release Titles by Regular Expression", @@ -229,6 +228,9 @@ "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)", + "about": "About", + "requiresCredentialsInSettings": "This needs additional credentials (in Settings)", "removeAppQuestion": { "one": "Remove App?", "other": "Remove Apps?" diff --git a/assets/translations/es.json b/assets/translations/es.json index 3d8f1ad..d3fae41 100644 --- a/assets/translations/es.json +++ b/assets/translations/es.json @@ -20,7 +20,6 @@ "githubPATLabel": "Token de Acceso Personal de GitHub (Reduce tiempos de espera)", "githubPATHint": "El TAP debe tener este formato: nombre_de_usuario:token", "githubPATFormat": "nombre_de_usuario:token", - "githubPATLinkText": "Sobre los TAP de GitHub", "includePrereleases": "Incluir versiones preliminares", "fallbackToOlderReleases": "Retorceder a versiones previas", "filterReleaseTitlesByRegEx": "Filtra Títulos de Versiones mediantes Expresiones Regulares", @@ -229,6 +228,9 @@ "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)", + "about": "About", + "requiresCredentialsInSettings": "This needs additional credentials (in Settings)", "removeAppQuestion": { "one": "¿Eliminar Aplicación?", "other": "¿Eliminar Aplicaciones?" diff --git a/assets/translations/fa.json b/assets/translations/fa.json index 33da610..36e25d4 100644 --- a/assets/translations/fa.json +++ b/assets/translations/fa.json @@ -20,7 +20,6 @@ "githubPATLabel": "توکن دسترسی شخصی گیت هاب(محدودیت نرخ را افزایش میدهد)", "githubPATHint": "PAT باید در این قالب باشد: username:token", "githubPATFormat": "username:token", - "githubPATLinkText": "درباره گیتهاب PATs", "includePrereleases": "شامل نسخه های اولیه", "fallbackToOlderReleases": "بازگشت به نسخه های قدیمی تر", "filterReleaseTitlesByRegEx": "عناوین انتشار را با بیان منظم فیلتر کنید", @@ -229,6 +228,9 @@ "dontShowTrackOnlyWarnings": "هشدار 'فقط ردیابی' را نشان ندهید", "dontShowAPKOriginWarnings": "هشدارهای منبع APK را نشان ندهید", "moveNonInstalledAppsToBottom": "Move Non-Installed Apps to Bottom of Apps View", + "gitlabPATLabel": "GitLab Personal Access Token (Enables Search)", + "about": "About", + "requiresCredentialsInSettings": "This needs additional credentials (in Settings)", "removeAppQuestion": { "one": "برنامه حذف شود؟", "other": "برنامه ها حذف شوند؟" diff --git a/assets/translations/fr.json b/assets/translations/fr.json index 1840c8a..4e29966 100644 --- a/assets/translations/fr.json +++ b/assets/translations/fr.json @@ -20,7 +20,6 @@ "githubPATLabel": "Jeton d'Accès Personnel GitHub (Augmente la limite de débit)", "githubPATHint": "Le JAP doit être dans ce format : username:token", "githubPATFormat": "username:token", - "githubPATLinkText": "À propos des JAP GitHub", "includePrereleases": "Inclure les avant-premières", "fallbackToOlderReleases": "Retour aux anciennes versions", "filterReleaseTitlesByRegEx": "Filtrer les titres de version par expression régulière", @@ -229,6 +228,9 @@ "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)", + "about": "About", + "requiresCredentialsInSettings": "This needs additional credentials (in Settings)", "removeAppQuestion": { "one": "Supprimer l'application ?", "other": "Supprimer les applications ?" diff --git a/assets/translations/hu.json b/assets/translations/hu.json index 26de38e..85134f0 100644 --- a/assets/translations/hu.json +++ b/assets/translations/hu.json @@ -20,7 +20,6 @@ "githubPATLabel": "GitHub személyes hozzáférési token (megnöveli a díjkorlátot)", "githubPATHint": "A PAT-nak a következő formátumban kell lennie: felhasználónév:token", "githubPATFormat": "felhasználónév:token", - "githubPATLinkText": "A GitHub PAT-okról", "includePrereleases": "Tartalmazza az előzetes kiadásokat", "fallbackToOlderReleases": "Visszatérés a régebbi kiadásokhoz", "filterReleaseTitlesByRegEx": "A kiadás címeinek szűrése reguláris kifejezéssel", @@ -228,6 +227,9 @@ "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": "Move Non-Installed Apps to Bottom of Apps View", + "gitlabPATLabel": "GitLab Personal Access Token (Enables Search)", + "about": "About", + "requiresCredentialsInSettings": "This needs additional credentials (in Settings)", "removeAppQuestion": { "one": "Eltávolítja az alkalmazást?", "other": "Eltávolítja az alkalmazást?" diff --git a/assets/translations/it.json b/assets/translations/it.json index 0e49191..728bce8 100644 --- a/assets/translations/it.json +++ b/assets/translations/it.json @@ -20,7 +20,6 @@ "githubPATLabel": "GitHub Personal Access Token (diminuisce limite di traffico)", "githubPATHint": "PAT deve seguire questo formato: username:token", "githubPATFormat": "username:token", - "githubPATLinkText": "Informazioni su GitHub PAT", "includePrereleases": "Includi prerelease", "fallbackToOlderReleases": "Ripiega su release precedenti", "filterReleaseTitlesByRegEx": "Filtra release con espressioni regolari", @@ -229,6 +228,9 @@ "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)", + "about": "About", + "requiresCredentialsInSettings": "This needs additional credentials (in Settings)", "removeAppQuestion": { "one": "Rimuovere l'App?", "other": "Rimuovere le App?" diff --git a/assets/translations/ja.json b/assets/translations/ja.json index 7f5bf32..02ee143 100644 --- a/assets/translations/ja.json +++ b/assets/translations/ja.json @@ -20,7 +20,6 @@ "githubPATLabel": "GitHub パーソナルアクセストークン (レート制限の引き上げ)", "githubPATHint": "PATは次の形式でなければなりません: ユーザー名:トークン", "githubPATFormat": "ユーザー名:トークン", - "githubPATLinkText": "GitHub PATsについて", "includePrereleases": "プレリリースを含む", "fallbackToOlderReleases": "旧リリースへのフォールバック", "filterReleaseTitlesByRegEx": "正規表現でリリースタイトルを絞り込む", @@ -229,6 +228,9 @@ "dontShowTrackOnlyWarnings": "「追跡のみ」の警告を表示しない", "dontShowAPKOriginWarnings": "APK Originの警告を表示しない", "moveNonInstalledAppsToBottom": "Move Non-Installed Apps to Bottom of Apps View", + "gitlabPATLabel": "GitLab Personal Access Token (Enables Search)", + "about": "About", + "requiresCredentialsInSettings": "This needs additional credentials (in Settings)", "removeAppQuestion": { "one": "アプリを削除しますか?", "other": "アプリを削除しますか?" diff --git a/assets/translations/zh.json b/assets/translations/zh.json index 91ca57d..1cf5267 100644 --- a/assets/translations/zh.json +++ b/assets/translations/zh.json @@ -20,7 +20,6 @@ "githubPATLabel": "GitHub 个人访问令牌(提升 API 请求限额)", "githubPATHint": "个人访问令牌必须为“username:token”的格式", "githubPATFormat": "username:token", - "githubPATLinkText": "关于 GitHub 个人访问令牌", "includePrereleases": "包含预发行版", "fallbackToOlderReleases": "将旧发行版作为备选", "filterReleaseTitlesByRegEx": "使用正则表达式筛选发行标题", @@ -229,6 +228,9 @@ "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)", + "about": "About", + "requiresCredentialsInSettings": "This needs additional credentials (in Settings)", "removeAppQuestion": { "one": "是否删除应用?", "other": "是否删除应用?" diff --git a/lib/app_sources/fdroid.dart b/lib/app_sources/fdroid.dart index 88b4f5e..28d45cc 100644 --- a/lib/app_sources/fdroid.dart +++ b/lib/app_sources/fdroid.dart @@ -73,7 +73,8 @@ class FDroid extends AppSource { @override Future>> search(String query) async { - Response res = await sourceRequest('https://search.$host/?q=$query'); + Response res = await sourceRequest( + 'https://search.$host/?q=${Uri.encodeQueryComponent(query)}'); if (res.statusCode == 200) { Map> urlsWithDescriptions = {}; parse(res.body).querySelectorAll('.package-header').forEach((e) { diff --git a/lib/app_sources/github.dart b/lib/app_sources/github.dart index a9a76c3..f67c36e 100644 --- a/lib/app_sources/github.dart +++ b/lib/app_sources/github.dart @@ -35,7 +35,7 @@ class GitHub extends AppSource { hint: tr('githubPATFormat'), belowWidgets: [ const SizedBox( - height: 8, + height: 4, ), GestureDetector( onTap: () { @@ -44,10 +44,13 @@ class GitHub extends AppSource { mode: LaunchMode.externalApplication); }, child: Text( - tr('githubPATLinkText'), + tr('about'), style: const TextStyle( decoration: TextDecoration.underline, fontSize: 12), - )) + )), + const SizedBox( + height: 4, + ), ]) ]; diff --git a/lib/app_sources/gitlab.dart b/lib/app_sources/gitlab.dart index 07f8369..ae65875 100644 --- a/lib/app_sources/gitlab.dart +++ b/lib/app_sources/gitlab.dart @@ -1,15 +1,47 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; import 'package:html/parser.dart'; import 'package:http/http.dart'; import 'package:obtainium/app_sources/github.dart'; import 'package:obtainium/custom_errors.dart'; +import 'package:obtainium/providers/settings_provider.dart'; import 'package:obtainium/providers/source_provider.dart'; import 'package:obtainium/components/generated_form.dart'; import 'package:easy_localization/easy_localization.dart'; +import 'package:url_launcher/url_launcher_string.dart'; class GitLab extends AppSource { GitLab() { host = 'gitlab.com'; overrideEligible = true; + canSearch = true; + + additionalSourceSpecificSettingFormItems = [ + GeneratedFormTextField('gitlab-creds', + label: tr('gitlabPATLabel'), + password: true, + required: false, + belowWidgets: [ + const SizedBox( + height: 4, + ), + GestureDetector( + onTap: () { + launchUrlString( + 'https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#create-a-personal-access-token', + mode: LaunchMode.externalApplication); + }, + child: Text( + tr('about'), + style: const TextStyle( + decoration: TextDecoration.underline, fontSize: 12), + )), + const SizedBox( + height: 4, + ) + ]) + ]; additionalSourceAppSpecificSettingFormItems = [ [ @@ -29,6 +61,37 @@ class GitLab extends AppSource { return url.substring(0, match.end); } + Future getPATIfAny() async { + SettingsProvider settingsProvider = SettingsProvider(); + await settingsProvider.initializeSettings(); + String? creds = settingsProvider + .getSettingString(additionalSourceSpecificSettingFormItems[0].key); + return creds != null && creds.isNotEmpty ? creds : null; + } + + @override + Future>> search(String query) async { + String? PAT = await getPATIfAny(); + if (PAT == null) { + throw CredsNeededError(name); + } + var url = + 'https://$host/api/v4/search?private_token=$PAT&scope=projects&search=${Uri.encodeQueryComponent(query)}'; + var res = await sourceRequest(url); + if (res.statusCode != 200) { + throw getObtainiumHttpError(res); + } + var json = jsonDecode(res.body) as List; + Map> results = {}; + json.forEach((element) { + results['https://$host/${element['path_with_namespace']}'] = [ + element['name_with_namespace'], + element['description'] ?? tr('noDescription') + ]; + }); + return results; + } + @override String? changeLogPageFromStandardUrl(String standardUrl) => '$standardUrl/-/releases'; diff --git a/lib/custom_errors.dart b/lib/custom_errors.dart index 99970ea..8f535cf 100644 --- a/lib/custom_errors.dart +++ b/lib/custom_errors.dart @@ -25,6 +25,11 @@ class InvalidURLError extends ObtainiumError { : super(tr('invalidURLForSource', args: [sourceName])); } +class CredsNeededError extends ObtainiumError { + CredsNeededError(String sourceName) + : super(tr('requiresCredentialsInSettings', args: [sourceName])); +} + class NoReleasesError extends ObtainiumError { NoReleasesError() : super(tr('noReleaseFound')); } diff --git a/lib/pages/add_app.dart b/lib/pages/add_app.dart index 3cef280..3f1886e 100644 --- a/lib/pages/add_app.dart +++ b/lib/pages/add_app.dart @@ -248,9 +248,18 @@ class _AddAppPageState extends State { searching = true; }); try { - var results = await Future.wait(sourceProvider.sources - .where((e) => e.canSearch) - .map((e) => e.search(searchQuery))); + var results = await Future.wait( + sourceProvider.sources.where((e) => e.canSearch).map((e) async { + try { + return await e.search(searchQuery); + } catch (err) { + if (err is! CredsNeededError) { + rethrow; + } else { + return >{}; + } + } + })); // .then((results) async { // Interleave results instead of simple reduce diff --git a/lib/pages/settings.dart b/lib/pages/settings.dart index 224a076..65684cf 100644 --- a/lib/pages/settings.dart +++ b/lib/pages/settings.dart @@ -205,6 +205,10 @@ class _SettingsPageState extends State { height: 16, ); + const height32 = SizedBox( + height: 32, + ); + return Scaffold( backgroundColor: Theme.of(context).colorScheme.surface, body: CustomScrollView(slivers: [ @@ -217,9 +221,26 @@ class _SettingsPageState extends State { : Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text( + tr('updates'), + style: TextStyle( + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.primary), + ), + intervalDropdown, + height32, + Text( + tr('sourceSpecific'), + style: TextStyle( + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.primary), + ), + ...sourceSpecificFields, + height32, Text( tr('appearance'), style: TextStyle( + fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.primary), ), themeDropdown, @@ -332,31 +353,11 @@ class _SettingsPageState extends State { }) ], ), - const Divider( - height: 16, - ), - height16, - Text( - tr('updates'), - style: TextStyle( - color: Theme.of(context).colorScheme.primary), - ), - intervalDropdown, - const Divider( - height: 48, - ), - Text( - tr('sourceSpecific'), - style: TextStyle( - color: Theme.of(context).colorScheme.primary), - ), - ...sourceSpecificFields, - const Divider( - height: 48, - ), + height32, Text( tr('categories'), style: TextStyle( + fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.primary), ), height16,