Added GitHub PAT support

This commit is contained in:
Imran Remtulla
2022-09-29 21:27:54 -04:00
parent e2440a38c4
commit fbe4f0b49e
14 changed files with 136 additions and 33 deletions

View File

@ -60,4 +60,7 @@ class FDroid implements AppSource {
@override
List<String> additionalDataDefaults = [];
@override
List<GeneratedFormItem> moreSourceSettingsFormItems = [];
}

View File

@ -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<String> getCredentialPrefixIfAny() async {
SettingsProvider settingsProvider = SettingsProvider();
await settingsProvider.initializeSettings();
String? creds =
settingsProvider.getSettingString(moreSourceSettingsFormItems[0].id);
return creds != null && creds.isNotEmpty ? '$creds@' : '';
}
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> 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<dynamic>;
@ -124,4 +133,26 @@ class GitHub implements AppSource {
@override
List<String> additionalDataDefaults = ['true', 'true', ''];
@override
List<GeneratedFormItem> 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;
}
])
];
}

View File

@ -68,4 +68,7 @@ class GitLab implements AppSource {
@override
List<String> additionalDataDefaults = [];
@override
List<GeneratedFormItem> moreSourceSettingsFormItems = [];
}

View File

@ -62,4 +62,7 @@ class IzzyOnDroid implements AppSource {
@override
List<String> additionalDataDefaults = [];
@override
List<GeneratedFormItem> moreSourceSettingsFormItems = [];
}

View File

@ -48,4 +48,7 @@ class Mullvad implements AppSource {
@override
List<String> additionalDataDefaults = [];
@override
List<GeneratedFormItem> moreSourceSettingsFormItems = [];
}

View File

@ -41,4 +41,7 @@ class Signal implements AppSource {
@override
List<String> additionalDataDefaults = [];
@override
List<GeneratedFormItem> moreSourceSettingsFormItems = [];
}

View File

@ -65,4 +65,7 @@ class SourceForge implements AppSource {
@override
List<String> additionalDataDefaults = [];
@override
List<GeneratedFormItem> moreSourceSettingsFormItems = [];
}

View File

@ -10,13 +10,15 @@ class GeneratedFormItem {
late bool required;
late int max;
late List<String? Function(String? value)> 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 {

View File

@ -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';

View File

@ -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<List<String>> 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<dynamic>)
.map((e) => e['html_url'] as String)

View File

@ -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<SettingsPage> {
@override
Widget build(BuildContext context) {
SettingsProvider settingsProvider = context.watch<SettingsProvider>();
SourceProvider sourceProvider = SourceProvider();
if (settingsProvider.prefs == null) {
settingsProvider.initializeSettings();
}
@ -22,8 +25,7 @@ class _SettingsPageState extends State<SettingsPage> {
backgroundColor: Theme.of(context).colorScheme.surface,
body: CustomScrollView(slivers: <Widget>[
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<SettingsPage> {
height: 16,
),
Text(
'More',
'Updates',
style: TextStyle(
color: Theme.of(context).colorScheme.primary),
),
@ -204,15 +206,54 @@ class _SettingsPageState extends State<SettingsPage> {
.merge(const TextStyle(
fontStyle: FontStyle.italic)),
),
const Spacer(),
Row(
mainAxisAlignment: MainAxisAlignment.center,
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<
Color>((Set<MaterialState> states) {
foregroundColor: MaterialStateProperty.resolveWith<Color>(
(Set<MaterialState> states) {
return Colors.grey;
}),
),
@ -223,14 +264,15 @@ class _SettingsPageState extends State<SettingsPage> {
icon: const Icon(Icons.code),
label: Text(
'Source',
style:
Theme.of(context).textTheme.bodySmall,
style: Theme.of(context).textTheme.bodySmall,
),
),
const SizedBox(
height: 16,
),
],
),
)
],
),
],
)))
]));
}
}

View File

@ -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);
}
}

View File

@ -135,6 +135,7 @@ abstract class AppSource {
AppNames getAppNames(String standardUrl);
late List<List<GeneratedFormItem>> additionalDataFormItems;
late List<String> additionalDataDefaults;
late List<GeneratedFormItem> moreSourceSettingsFormItems;
}
abstract class MassAppSource {

View File

@ -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'