From fbe4f0b49ef87832d2f2d8ae870754a2cb8055b4 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Thu, 29 Sep 2022 21:27:54 -0400 Subject: [PATCH] Added GitHub PAT support --- lib/app_sources/fdroid.dart | 3 + lib/app_sources/github.dart | 33 ++++++++- lib/app_sources/gitlab.dart | 3 + lib/app_sources/izzyondroid.dart | 3 + lib/app_sources/mullvad.dart | 3 + lib/app_sources/signal.dart | 3 + lib/app_sources/sourceforge.dart | 3 + lib/components/generated_form.dart | 4 +- lib/main.dart | 2 +- lib/mass_app_sources/githubstars.dart | 3 +- lib/pages/settings.dart | 98 +++++++++++++++++++-------- lib/providers/settings_provider.dart | 8 +++ lib/providers/source_provider.dart | 1 + pubspec.yaml | 2 +- 14 files changed, 136 insertions(+), 33 deletions(-) diff --git a/lib/app_sources/fdroid.dart b/lib/app_sources/fdroid.dart index 4cf5a8f..7587839 100644 --- a/lib/app_sources/fdroid.dart +++ b/lib/app_sources/fdroid.dart @@ -60,4 +60,7 @@ class FDroid implements AppSource { @override List additionalDataDefaults = []; + + @override + List moreSourceSettingsFormItems = []; } diff --git a/lib/app_sources/github.dart b/lib/app_sources/github.dart index aef1bf5..327846d 100644 --- a/lib/app_sources/github.dart +++ b/lib/app_sources/github.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:http/http.dart'; import 'package:obtainium/components/generated_form.dart'; import 'package:obtainium/custom_errors.dart'; +import 'package:obtainium/providers/settings_provider.dart'; import 'package:obtainium/providers/source_provider.dart'; class GitHub implements AppSource { @@ -18,6 +19,14 @@ class GitHub implements AppSource { return url.substring(0, match.end); } + Future getCredentialPrefixIfAny() async { + SettingsProvider settingsProvider = SettingsProvider(); + await settingsProvider.initializeSettings(); + String? creds = + settingsProvider.getSettingString(moreSourceSettingsFormItems[0].id); + return creds != null && creds.isNotEmpty ? '$creds@' : ''; + } + @override Future getLatestAPKDetails( String standardUrl, List additionalData) async { @@ -29,7 +38,7 @@ class GitHub implements AppSource { ? additionalData[2] : null; Response res = await get(Uri.parse( - 'https://api.$host/repos${standardUrl.substring('https://$host'.length)}/releases')); + 'https://${await getCredentialPrefixIfAny()}api.$host/repos${standardUrl.substring('https://$host'.length)}/releases')); if (res.statusCode == 200) { var releases = jsonDecode(res.body) as List; @@ -124,4 +133,26 @@ class GitHub implements AppSource { @override List additionalDataDefaults = ['true', 'true', '']; + + @override + List moreSourceSettingsFormItems = [ + GeneratedFormItem( + label: 'GitHub Credentials (Increases Rate Limit)', + id: 'github-creds', + required: false, + additionalValidators: [ + (value) { + if (value != null && value.trim().isNotEmpty) { + if (value + .split(':') + .where((element) => element.trim().isNotEmpty) + .length != + 2) { + return 'PAT must be in this format: username:token'; + } + } + return null; + } + ]) + ]; } diff --git a/lib/app_sources/gitlab.dart b/lib/app_sources/gitlab.dart index 0e4e364..9917d58 100644 --- a/lib/app_sources/gitlab.dart +++ b/lib/app_sources/gitlab.dart @@ -68,4 +68,7 @@ class GitLab implements AppSource { @override List additionalDataDefaults = []; + + @override + List moreSourceSettingsFormItems = []; } diff --git a/lib/app_sources/izzyondroid.dart b/lib/app_sources/izzyondroid.dart index 061a037..2f36f98 100644 --- a/lib/app_sources/izzyondroid.dart +++ b/lib/app_sources/izzyondroid.dart @@ -62,4 +62,7 @@ class IzzyOnDroid implements AppSource { @override List additionalDataDefaults = []; + + @override + List moreSourceSettingsFormItems = []; } diff --git a/lib/app_sources/mullvad.dart b/lib/app_sources/mullvad.dart index 658f04f..bfb6397 100644 --- a/lib/app_sources/mullvad.dart +++ b/lib/app_sources/mullvad.dart @@ -48,4 +48,7 @@ class Mullvad implements AppSource { @override List additionalDataDefaults = []; + + @override + List moreSourceSettingsFormItems = []; } diff --git a/lib/app_sources/signal.dart b/lib/app_sources/signal.dart index 886c147..8a97b8f 100644 --- a/lib/app_sources/signal.dart +++ b/lib/app_sources/signal.dart @@ -41,4 +41,7 @@ class Signal implements AppSource { @override List additionalDataDefaults = []; + + @override + List moreSourceSettingsFormItems = []; } diff --git a/lib/app_sources/sourceforge.dart b/lib/app_sources/sourceforge.dart index 17f4f68..b46405a 100644 --- a/lib/app_sources/sourceforge.dart +++ b/lib/app_sources/sourceforge.dart @@ -65,4 +65,7 @@ class SourceForge implements AppSource { @override List additionalDataDefaults = []; + + @override + List moreSourceSettingsFormItems = []; } diff --git a/lib/components/generated_form.dart b/lib/components/generated_form.dart index d646b0f..1318b06 100644 --- a/lib/components/generated_form.dart +++ b/lib/components/generated_form.dart @@ -10,13 +10,15 @@ class GeneratedFormItem { late bool required; late int max; late List additionalValidators; + late String id; GeneratedFormItem( {this.label = 'Input', this.type = FormItemType.string, this.required = true, this.max = 1, - this.additionalValidators = const []}); + this.additionalValidators = const [], + this.id = 'input'}); } class GeneratedForm extends StatefulWidget { diff --git a/lib/main.dart b/lib/main.dart index cfebd9d..f1aadb7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -14,7 +14,7 @@ import 'package:dynamic_color/dynamic_color.dart'; import 'package:device_info_plus/device_info_plus.dart'; const String currentReleaseTag = - 'v0.4.1-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES + 'v0.5.0-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES const String bgUpdateCheckTaskName = 'bg-update-check'; diff --git a/lib/mass_app_sources/githubstars.dart b/lib/mass_app_sources/githubstars.dart index 389d446..c0bd948 100644 --- a/lib/mass_app_sources/githubstars.dart +++ b/lib/mass_app_sources/githubstars.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:http/http.dart'; +import 'package:obtainium/app_sources/github.dart'; import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/providers/source_provider.dart'; @@ -14,7 +15,7 @@ class GitHubStars implements MassAppSource { Future> getOnePageOfUserStarredUrls( String username, int page) async { Response res = await get(Uri.parse( - 'https://api.github.com/users/$username/starred?per_page=100&page=$page')); + 'https://${await GitHub().getCredentialPrefixIfAny()}api.github.com/users/$username/starred?per_page=100&page=$page')); if (res.statusCode == 200) { return (jsonDecode(res.body) as List) .map((e) => e['html_url'] as String) diff --git a/lib/pages/settings.dart b/lib/pages/settings.dart index b917f0f..5f0d55b 100644 --- a/lib/pages/settings.dart +++ b/lib/pages/settings.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:obtainium/components/custom_app_bar.dart'; +import 'package:obtainium/components/generated_form.dart'; import 'package:obtainium/providers/settings_provider.dart'; +import 'package:obtainium/providers/source_provider.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -15,6 +17,7 @@ class _SettingsPageState extends State { @override Widget build(BuildContext context) { SettingsProvider settingsProvider = context.watch(); + SourceProvider sourceProvider = SourceProvider(); if (settingsProvider.prefs == null) { settingsProvider.initializeSettings(); } @@ -22,8 +25,7 @@ class _SettingsPageState extends State { backgroundColor: Theme.of(context).colorScheme.surface, body: CustomScrollView(slivers: [ const CustomAppBar(title: 'Settings'), - SliverFillRemaining( - hasScrollBody: true, + SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.all(16), child: settingsProvider.prefs == null @@ -160,7 +162,7 @@ class _SettingsPageState extends State { height: 16, ), Text( - 'More', + 'Updates', style: TextStyle( color: Theme.of(context).colorScheme.primary), ), @@ -204,33 +206,73 @@ class _SettingsPageState extends State { .merge(const TextStyle( fontStyle: FontStyle.italic)), ), - const Spacer(), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - TextButton.icon( - style: ButtonStyle( - foregroundColor: - MaterialStateProperty.resolveWith< - Color>((Set states) { - return Colors.grey; - }), - ), - onPressed: () { - launchUrlString(settingsProvider.sourceUrl, - mode: LaunchMode.externalApplication); - }, - icon: const Icon(Icons.code), - label: Text( - 'Source', - style: - Theme.of(context).textTheme.bodySmall, - ), - ) - ], + const Divider( + height: 48, ), + Text( + 'Source-Specific', + style: TextStyle( + color: Theme.of(context).colorScheme.primary), + ), + ...sourceProvider.sources.map((e) { + if (e.moreSourceSettingsFormItems.isNotEmpty) { + return GeneratedForm( + items: e.moreSourceSettingsFormItems + .map((e) => [e]) + .toList(), + onValueChanges: (values, valid) { + if (valid) { + for (var i = 0; + i < values.length; + i++) { + settingsProvider.setSettingString( + e.moreSourceSettingsFormItems[i] + .id, + values[i]); + } + } + }, + defaultValues: + e.moreSourceSettingsFormItems.map((e) { + return settingsProvider + .getSettingString(e.id) ?? + ''; + }).toList()); + } else { + return Container(); + } + }), ], - ))) + ))), + SliverToBoxAdapter( + child: Column( + children: [ + const SizedBox( + height: 16, + ), + TextButton.icon( + style: ButtonStyle( + foregroundColor: MaterialStateProperty.resolveWith( + (Set states) { + return Colors.grey; + }), + ), + onPressed: () { + launchUrlString(settingsProvider.sourceUrl, + mode: LaunchMode.externalApplication); + }, + icon: const Icon(Icons.code), + label: Text( + 'Source', + style: Theme.of(context).textTheme.bodySmall, + ), + ), + const SizedBox( + height: 16, + ), + ], + ), + ) ])); } } diff --git a/lib/providers/settings_provider.dart b/lib/providers/settings_provider.dart index f5b353f..6b631ff 100644 --- a/lib/providers/settings_provider.dart +++ b/lib/providers/settings_provider.dart @@ -122,4 +122,12 @@ class SettingsProvider with ChangeNotifier { prefs?.setBool('showAppWebpage', show); notifyListeners(); } + + String? getSettingString(String settingId) { + return prefs?.getString(settingId); + } + + void setSettingString(String settingId, String value) { + prefs?.setString(settingId, value); + } } diff --git a/lib/providers/source_provider.dart b/lib/providers/source_provider.dart index 4251bdb..853c746 100644 --- a/lib/providers/source_provider.dart +++ b/lib/providers/source_provider.dart @@ -135,6 +135,7 @@ abstract class AppSource { AppNames getAppNames(String standardUrl); late List> additionalDataFormItems; late List additionalDataDefaults; + late List moreSourceSettingsFormItems; } abstract class MassAppSource { diff --git a/pubspec.yaml b/pubspec.yaml index a6282f0..045075d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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.4.1+20 # When changing this, update the tag in main() accordingly +version: 0.5.0+21 # When changing this, update the tag in main() accordingly environment: sdk: '>=2.19.0-79.0.dev <3.0.0'