From c5ad337daa8e35e20582dc28e6aac2b3d07f6890 Mon Sep 17 00:00:00 2001 From: Aunali321 <48486084+Aunali321@users.noreply.github.com> Date: Sun, 18 Sep 2022 23:12:30 +0530 Subject: [PATCH] feat: Custom api endpoints. (#216) Co-authored-by: Alberto Ponces --- assets/i18n/en.json | 5 ++ lib/services/manager_api.dart | 50 +++++++++-- lib/services/revanced_api.dart | 24 ++++-- lib/ui/views/settings/settings_view.dart | 11 +++ lib/ui/views/settings/settings_viewmodel.dart | 86 +++++++++++++++++++ 5 files changed, 162 insertions(+), 14 deletions(-) diff --git a/assets/i18n/en.json b/assets/i18n/en.json index 9fd376f9..01f0206a 100644 --- a/assets/i18n/en.json +++ b/assets/i18n/en.json @@ -97,6 +97,7 @@ "patcherSectionTitle": "Patcher", "teamSectionTitle": "Team", "infoSectionTitle": "Info", + "advancedSectionTitle": "Advanced", "darkThemeLabel": "Dark Mode", "darkThemeHint": "Welcome to the Dark Side", "dynamicThemeLabel": "Material You", @@ -112,10 +113,14 @@ "sourcesIntegrationsLabel": "Integrations Source", "sourcesResetDialogTitle": "Reset", "sourcesResetDialogText": "Are you sure you want to reset custom sources to their default values?", + "apiURLResetDialogText": "Are you sure you want to reset API URL to their default values?", "contributorsLabel": "Contributors", "contributorsHint": "A list of contributors of ReVanced", "logsLabel": "Logs", "logsHint": "Share device debug logs", + "apiURLLabel": "API URL", + "apiURLHint": "Configure your custom API URL", + "selectApiURL": "Select URL", "aboutLabel": "About", "snackbarMessage": "Copied to clipboard" }, diff --git a/lib/services/manager_api.dart b/lib/services/manager_api.dart index d5cfa1c1..eed5e4e3 100644 --- a/lib/services/manager_api.dart +++ b/lib/services/manager_api.dart @@ -19,6 +19,7 @@ class ManagerAPI { final String patcherRepo = 'revanced-patcher'; final String cliRepo = 'revanced-cli'; late SharedPreferences _prefs; + String defaultApiUrl = 'https://revanced-releases-api.afterst0rm.xyz'; String defaultPatcherRepo = 'revanced/revanced-patcher'; String defaultPatchesRepo = 'revanced/revanced-patches'; String defaultIntegrationsRepo = 'revanced/revanced-integrations'; @@ -29,6 +30,17 @@ class ManagerAPI { _prefs = await SharedPreferences.getInstance(); } + String getApiUrl() { + return _prefs.getString('apiUrl') ?? defaultApiUrl; + } + + Future setApiUrl(String url) async { + if (url.isEmpty || url == ' ') { + url = defaultApiUrl; + } + await _prefs.setString('apiUrl', url); + } + String getPatchesRepo() { return _prefs.getString('patchesRepo') ?? defaultPatchesRepo; } @@ -106,21 +118,26 @@ class ManagerAPI { } Future>> getContributors() async { - return await _revancedAPI.getContributors(); + String apiUrl = getApiUrl(); + return await _revancedAPI.getContributors(apiUrl); } Future> getPatches() async { - if (getPatchesRepo() == defaultPatchesRepo) { - return await _revancedAPI.getPatches(); + String repoName = getPatchesRepo(); + if (repoName == defaultPatchesRepo) { + String apiUrl = getApiUrl(); + return await _revancedAPI.getPatches(apiUrl); } else { - return await _githubAPI.getPatches(getPatchesRepo()); + return await _githubAPI.getPatches(repoName); } } Future downloadPatches() async { String repoName = getPatchesRepo(); if (repoName == defaultPatchesRepo) { + String apiUrl = getApiUrl(); return await _revancedAPI.getLatestReleaseFile( + apiUrl, '.jar', defaultPatchesRepo, ); @@ -132,7 +149,9 @@ class ManagerAPI { Future downloadIntegrations() async { String repoName = getIntegrationsRepo(); if (repoName == defaultIntegrationsRepo) { + String apiUrl = getApiUrl(); return await _revancedAPI.getLatestReleaseFile( + apiUrl, '.apk', defaultIntegrationsRepo, ); @@ -142,19 +161,36 @@ class ManagerAPI { } Future downloadManager() async { - return await _revancedAPI.getLatestReleaseFile('.apk', defaultManagerRepo); + String apiUrl = getApiUrl(); + return await _revancedAPI.getLatestReleaseFile( + apiUrl, + '.apk', + defaultManagerRepo, + ); } Future getLatestPatcherReleaseTime() async { - return await _revancedAPI.getLatestReleaseTime('.gz', defaultPatcherRepo); + String apiUrl = getApiUrl(); + return await _revancedAPI.getLatestReleaseTime( + apiUrl, + '.gz', + defaultPatcherRepo, + ); } Future getLatestManagerReleaseTime() async { - return await _revancedAPI.getLatestReleaseTime('.apk', defaultManagerRepo); + String apiUrl = getApiUrl(); + return await _revancedAPI.getLatestReleaseTime( + apiUrl, + '.apk', + defaultManagerRepo, + ); } Future getLatestManagerVersion() async { + String apiUrl = getApiUrl(); return await _revancedAPI.getLatestReleaseVersion( + apiUrl, '.apk', defaultManagerRepo, ); diff --git a/lib/services/revanced_api.dart b/lib/services/revanced_api.dart index 7059c83f..a75e32a1 100644 --- a/lib/services/revanced_api.dart +++ b/lib/services/revanced_api.dart @@ -9,7 +9,6 @@ import 'package:timeago/timeago.dart'; @lazySingleton class RevancedAPI { - final String apiUrl = 'https://revanced-releases-api.afterst0rm.xyz'; final Dio _dio = Dio(); final DioCacheManager _dioCacheManager = DioCacheManager(CacheConfig()); final Options _cacheOptions = buildCacheOptions( @@ -17,7 +16,7 @@ class RevancedAPI { maxStale: const Duration(days: 7), ); - void initialize() { + Future initialize() async { _dio.interceptors.add(_dioCacheManager.interceptor); } @@ -25,7 +24,7 @@ class RevancedAPI { await _dioCacheManager.clearAll(); } - Future>> getContributors() async { + Future>> getContributors(String apiUrl) async { Map> contributors = {}; try { var response = await _dio.get( @@ -43,7 +42,7 @@ class RevancedAPI { return contributors; } - Future> getPatches() async { + Future> getPatches(String apiUrl) async { try { var response = await _dio.get('$apiUrl/patches', options: _cacheOptions); List patches = response.data; @@ -54,6 +53,7 @@ class RevancedAPI { } Future?> _getLatestRelease( + String apiUrl, String extension, String repoName, ) async { @@ -71,10 +71,13 @@ class RevancedAPI { } Future getLatestReleaseVersion( - String extension, String repoName) async { + String apiUrl, + String extension, + String repoName, + ) async { try { Map? release = - await _getLatestRelease(extension, repoName); + await _getLatestRelease(apiUrl, extension, repoName); if (release != null) { return release['version']; } @@ -84,9 +87,14 @@ class RevancedAPI { return null; } - Future getLatestReleaseFile(String extension, String repoName) async { + Future getLatestReleaseFile( + String apiUrl, + String extension, + String repoName, + ) async { try { Map? release = await _getLatestRelease( + apiUrl, extension, repoName, ); @@ -101,11 +109,13 @@ class RevancedAPI { } Future getLatestReleaseTime( + String apiUrl, String extension, String repoName, ) async { try { Map? release = await _getLatestRelease( + apiUrl, extension, repoName, ); diff --git a/lib/ui/views/settings/settings_view.dart b/lib/ui/views/settings/settings_view.dart index d29fec03..4d7f1a1b 100644 --- a/lib/ui/views/settings/settings_view.dart +++ b/lib/ui/views/settings/settings_view.dart @@ -145,6 +145,17 @@ class SettingsView extends StatelessWidget { const AboutWidget(), ], ), + const Divider(thickness: 1.0), + SettingsSection( + title: 'settingsView.advancedSectionTitle', + children: [ + SettingsTileDialog( + title: 'settingsView.apiURLLabel', + subtitle: 'settingsView.apiURLHint', + onTap: () => model.showApiUrlDialog(context), + ), + ], + ), ], ), ), diff --git a/lib/ui/views/settings/settings_viewmodel.dart b/lib/ui/views/settings/settings_viewmodel.dart index 6d3e26b3..7bb9f73d 100644 --- a/lib/ui/views/settings/settings_viewmodel.dart +++ b/lib/ui/views/settings/settings_viewmodel.dart @@ -27,6 +27,7 @@ class SettingsViewModel extends BaseViewModel { final TextEditingController _patSourceController = TextEditingController(); final TextEditingController _orgIntSourceController = TextEditingController(); final TextEditingController _intSourceController = TextEditingController(); + final TextEditingController _apiUrlController = TextEditingController(); void setLanguage(String language) { notifyListeners(); @@ -208,6 +209,65 @@ class SettingsViewModel extends BaseViewModel { ); } + Future showApiUrlDialog(BuildContext context) async { + String apiUrl = _managerAPI.getApiUrl(); + _apiUrlController.text = apiUrl.replaceAll('https://', ''); + return showDialog( + context: context, + builder: (context) => AlertDialog( + title: Row( + children: [ + I18nText('settingsView.apiURLLabel'), + const Spacer(), + IconButton( + icon: const Icon(Icons.manage_history_outlined), + onPressed: () => showApiUrlResetDialog(context), + color: Theme.of(context).colorScheme.secondary, + ) + ], + ), + backgroundColor: Theme.of(context).colorScheme.secondaryContainer, + content: SingleChildScrollView( + child: Column( + children: [ + CustomTextField( + leadingIcon: Icon( + Icons.api_outlined, + color: Theme.of(context).colorScheme.secondary, + ), + inputController: _apiUrlController, + label: I18nText('settingsView.selectApiURL'), + hint: apiUrl.split('/')[0], + onChanged: (value) => notifyListeners(), + ), + ], + ), + ), + actions: [ + CustomMaterialButton( + isFilled: false, + label: I18nText('cancelButton'), + onPressed: () { + _apiUrlController.clear(); + Navigator.of(context).pop(); + }, + ), + CustomMaterialButton( + label: I18nText('okButton'), + onPressed: () { + String apiUrl = _apiUrlController.text; + if (!apiUrl.startsWith('https')) { + apiUrl = 'https://$apiUrl'; + } + _managerAPI.setApiUrl(apiUrl); + Navigator.of(context).pop(); + }, + ) + ], + ), + ); + } + Future showResetConfirmationDialog(BuildContext context) async { return showDialog( context: context, @@ -235,6 +295,32 @@ class SettingsViewModel extends BaseViewModel { ); } + Future showApiUrlResetDialog(BuildContext context) async { + return showDialog( + context: context, + builder: (context) => AlertDialog( + title: I18nText('settingsView.sourcesResetDialogTitle'), + backgroundColor: Theme.of(context).colorScheme.secondaryContainer, + content: I18nText('settingsView.apiURLResetDialogText'), + actions: [ + CustomMaterialButton( + isFilled: false, + label: I18nText('cancelButton'), + onPressed: () => Navigator.of(context).pop(), + ), + CustomMaterialButton( + label: I18nText('okButton'), + onPressed: () { + _managerAPI.setApiUrl(''); + Navigator.of(context).pop(); + Navigator.of(context).pop(); + }, + ) + ], + ), + ); + } + Future getSdkVersion() async { AndroidDeviceInfo info = await DeviceInfoPlugin().androidInfo; return info.version.sdkInt ?? -1;