mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-07-22 17:19:42 +02:00
Added GitHub PAT support
This commit is contained in:
@@ -60,4 +60,7 @@ class FDroid implements AppSource {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> additionalDataDefaults = [];
|
List<String> additionalDataDefaults = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<GeneratedFormItem> moreSourceSettingsFormItems = [];
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@ import 'dart:convert';
|
|||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
import 'package:obtainium/components/generated_form.dart';
|
import 'package:obtainium/components/generated_form.dart';
|
||||||
import 'package:obtainium/custom_errors.dart';
|
import 'package:obtainium/custom_errors.dart';
|
||||||
|
import 'package:obtainium/providers/settings_provider.dart';
|
||||||
import 'package:obtainium/providers/source_provider.dart';
|
import 'package:obtainium/providers/source_provider.dart';
|
||||||
|
|
||||||
class GitHub implements AppSource {
|
class GitHub implements AppSource {
|
||||||
@@ -18,6 +19,14 @@ class GitHub implements AppSource {
|
|||||||
return url.substring(0, match.end);
|
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
|
@override
|
||||||
Future<APKDetails> getLatestAPKDetails(
|
Future<APKDetails> getLatestAPKDetails(
|
||||||
String standardUrl, List<String> additionalData) async {
|
String standardUrl, List<String> additionalData) async {
|
||||||
@@ -29,7 +38,7 @@ class GitHub implements AppSource {
|
|||||||
? additionalData[2]
|
? additionalData[2]
|
||||||
: null;
|
: null;
|
||||||
Response res = await get(Uri.parse(
|
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) {
|
if (res.statusCode == 200) {
|
||||||
var releases = jsonDecode(res.body) as List<dynamic>;
|
var releases = jsonDecode(res.body) as List<dynamic>;
|
||||||
|
|
||||||
@@ -124,4 +133,26 @@ class GitHub implements AppSource {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> additionalDataDefaults = ['true', 'true', ''];
|
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;
|
||||||
|
}
|
||||||
|
])
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@@ -68,4 +68,7 @@ class GitLab implements AppSource {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> additionalDataDefaults = [];
|
List<String> additionalDataDefaults = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<GeneratedFormItem> moreSourceSettingsFormItems = [];
|
||||||
}
|
}
|
||||||
|
@@ -62,4 +62,7 @@ class IzzyOnDroid implements AppSource {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> additionalDataDefaults = [];
|
List<String> additionalDataDefaults = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<GeneratedFormItem> moreSourceSettingsFormItems = [];
|
||||||
}
|
}
|
||||||
|
@@ -48,4 +48,7 @@ class Mullvad implements AppSource {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> additionalDataDefaults = [];
|
List<String> additionalDataDefaults = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<GeneratedFormItem> moreSourceSettingsFormItems = [];
|
||||||
}
|
}
|
||||||
|
@@ -41,4 +41,7 @@ class Signal implements AppSource {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> additionalDataDefaults = [];
|
List<String> additionalDataDefaults = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<GeneratedFormItem> moreSourceSettingsFormItems = [];
|
||||||
}
|
}
|
||||||
|
@@ -65,4 +65,7 @@ class SourceForge implements AppSource {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> additionalDataDefaults = [];
|
List<String> additionalDataDefaults = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<GeneratedFormItem> moreSourceSettingsFormItems = [];
|
||||||
}
|
}
|
||||||
|
@@ -10,13 +10,15 @@ class GeneratedFormItem {
|
|||||||
late bool required;
|
late bool required;
|
||||||
late int max;
|
late int max;
|
||||||
late List<String? Function(String? value)> additionalValidators;
|
late List<String? Function(String? value)> additionalValidators;
|
||||||
|
late String id;
|
||||||
|
|
||||||
GeneratedFormItem(
|
GeneratedFormItem(
|
||||||
{this.label = 'Input',
|
{this.label = 'Input',
|
||||||
this.type = FormItemType.string,
|
this.type = FormItemType.string,
|
||||||
this.required = true,
|
this.required = true,
|
||||||
this.max = 1,
|
this.max = 1,
|
||||||
this.additionalValidators = const []});
|
this.additionalValidators = const [],
|
||||||
|
this.id = 'input'});
|
||||||
}
|
}
|
||||||
|
|
||||||
class GeneratedForm extends StatefulWidget {
|
class GeneratedForm extends StatefulWidget {
|
||||||
|
@@ -14,7 +14,7 @@ import 'package:dynamic_color/dynamic_color.dart';
|
|||||||
import 'package:device_info_plus/device_info_plus.dart';
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
|
|
||||||
const String currentReleaseTag =
|
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';
|
const String bgUpdateCheckTaskName = 'bg-update-check';
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
|
import 'package:obtainium/app_sources/github.dart';
|
||||||
import 'package:obtainium/custom_errors.dart';
|
import 'package:obtainium/custom_errors.dart';
|
||||||
import 'package:obtainium/providers/source_provider.dart';
|
import 'package:obtainium/providers/source_provider.dart';
|
||||||
|
|
||||||
@@ -14,7 +15,7 @@ class GitHubStars implements MassAppSource {
|
|||||||
Future<List<String>> getOnePageOfUserStarredUrls(
|
Future<List<String>> getOnePageOfUserStarredUrls(
|
||||||
String username, int page) async {
|
String username, int page) async {
|
||||||
Response res = await get(Uri.parse(
|
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) {
|
if (res.statusCode == 200) {
|
||||||
return (jsonDecode(res.body) as List<dynamic>)
|
return (jsonDecode(res.body) as List<dynamic>)
|
||||||
.map((e) => e['html_url'] as String)
|
.map((e) => e['html_url'] as String)
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:obtainium/components/custom_app_bar.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/settings_provider.dart';
|
||||||
|
import 'package:obtainium/providers/source_provider.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:url_launcher/url_launcher_string.dart';
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
|
||||||
@@ -15,6 +17,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
SettingsProvider settingsProvider = context.watch<SettingsProvider>();
|
SettingsProvider settingsProvider = context.watch<SettingsProvider>();
|
||||||
|
SourceProvider sourceProvider = SourceProvider();
|
||||||
if (settingsProvider.prefs == null) {
|
if (settingsProvider.prefs == null) {
|
||||||
settingsProvider.initializeSettings();
|
settingsProvider.initializeSettings();
|
||||||
}
|
}
|
||||||
@@ -22,8 +25,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||||
body: CustomScrollView(slivers: <Widget>[
|
body: CustomScrollView(slivers: <Widget>[
|
||||||
const CustomAppBar(title: 'Settings'),
|
const CustomAppBar(title: 'Settings'),
|
||||||
SliverFillRemaining(
|
SliverToBoxAdapter(
|
||||||
hasScrollBody: true,
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: settingsProvider.prefs == null
|
child: settingsProvider.prefs == null
|
||||||
@@ -160,7 +162,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
height: 16,
|
height: 16,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'More',
|
'Updates',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).colorScheme.primary),
|
color: Theme.of(context).colorScheme.primary),
|
||||||
),
|
),
|
||||||
@@ -204,15 +206,54 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
.merge(const TextStyle(
|
.merge(const TextStyle(
|
||||||
fontStyle: FontStyle.italic)),
|
fontStyle: FontStyle.italic)),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Divider(
|
||||||
Row(
|
height: 48,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
),
|
||||||
|
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: [
|
children: [
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
foregroundColor:
|
foregroundColor: MaterialStateProperty.resolveWith<Color>(
|
||||||
MaterialStateProperty.resolveWith<
|
(Set<MaterialState> states) {
|
||||||
Color>((Set<MaterialState> states) {
|
|
||||||
return Colors.grey;
|
return Colors.grey;
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
@@ -223,14 +264,15 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
icon: const Icon(Icons.code),
|
icon: const Icon(Icons.code),
|
||||||
label: Text(
|
label: Text(
|
||||||
'Source',
|
'Source',
|
||||||
style:
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
Theme.of(context).textTheme.bodySmall,
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)))
|
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -122,4 +122,12 @@ class SettingsProvider with ChangeNotifier {
|
|||||||
prefs?.setBool('showAppWebpage', show);
|
prefs?.setBool('showAppWebpage', show);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String? getSettingString(String settingId) {
|
||||||
|
return prefs?.getString(settingId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSettingString(String settingId, String value) {
|
||||||
|
prefs?.setString(settingId, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -135,6 +135,7 @@ abstract class AppSource {
|
|||||||
AppNames getAppNames(String standardUrl);
|
AppNames getAppNames(String standardUrl);
|
||||||
late List<List<GeneratedFormItem>> additionalDataFormItems;
|
late List<List<GeneratedFormItem>> additionalDataFormItems;
|
||||||
late List<String> additionalDataDefaults;
|
late List<String> additionalDataDefaults;
|
||||||
|
late List<GeneratedFormItem> moreSourceSettingsFormItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class MassAppSource {
|
abstract class MassAppSource {
|
||||||
|
@@ -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
|
# 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
|
# 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.
|
# 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:
|
environment:
|
||||||
sdk: '>=2.19.0-79.0.dev <3.0.0'
|
sdk: '>=2.19.0-79.0.dev <3.0.0'
|
||||||
|
Reference in New Issue
Block a user