Skip to content

Commit

Permalink
feat: EXPERIMENTAL language switching.
Browse files Browse the repository at this point in the history
  • Loading branch information
Aunali321 committed Nov 10, 2022
1 parent 30376c9 commit be77a18
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 24 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,4 @@ app.*.map.json

Firebase related
.firebase
/lib/utils/environment.dart
2 changes: 2 additions & 0 deletions lib/app/app.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:revanced_manager/services/crowdin_api.dart';
import 'package:revanced_manager/services/github_api.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/services/patcher_api.dart';
Expand Down Expand Up @@ -37,6 +38,7 @@ import 'package:stacked_services/stacked_services.dart';
LazySingleton(classType: PatcherAPI),
LazySingleton(classType: RevancedAPI),
LazySingleton(classType: GithubAPI),
LazySingleton(classType: CrowdinAPI),
LazySingleton(classType: Toast),
],
)
Expand Down
17 changes: 16 additions & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,32 @@ import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/services/crowdin_api.dart';
import 'package:revanced_manager/services/github_api.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/services/patcher_api.dart';
import 'package:revanced_manager/services/revanced_api.dart';
import 'package:revanced_manager/ui/theme/dynamic_theme_builder.dart';
import 'package:revanced_manager/ui/views/navigation/navigation_view.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:stacked_themes/stacked_themes.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:timezone/data/latest.dart' as tz;

late SharedPreferences prefs;
Future main() async {
await ThemeManager.initialise();
await setupLocator();
WidgetsFlutterBinding.ensureInitialized();
await locator<ManagerAPI>().initialize();
String apiUrl = locator<ManagerAPI>().getApiUrl();
await locator<RevancedAPI>().initialize(apiUrl);
await locator<CrowdinAPI>().initialize();
// bool isSentryEnabled = locator<ManagerAPI>().isSentryEnabled();
locator<GithubAPI>().initialize();
await locator<PatcherAPI>().initialize();
tz.initializeTimeZones();
prefs = await SharedPreferences.getInstance();

// Remove this section if you are building from source and don't have sentry configured
// await SentryFlutter.init(
Expand Down Expand Up @@ -55,15 +60,25 @@ class MyApp extends StatelessWidget {

@override
Widget build(BuildContext context) {
String rawLocale = prefs.getString('language') ?? 'en_US';
String replaceLocale = rawLocale.replaceAll('_', '-');
List<String> localeList = replaceLocale.split('-');
Locale locale = Locale(localeList[0], localeList[1]);

return DynamicThemeBuilder(
title: 'ReVanced Manager',
home: const NavigationView(),
localizationsDelegates: [
FlutterI18nDelegate(
translationLoader: FileTranslationLoader(
fallbackFile: 'en_US',
forcedLocale: locale,
basePath: 'assets/i18n',
useCountryCode: true,
),
missingTranslationHandler: (key, locale) {
print(
'--> Missing translation: key: $key, languageCode: ${locale?.languageCode}');
},
),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate
Expand Down
61 changes: 61 additions & 0 deletions lib/services/crowdin_api.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import 'package:dio/dio.dart';
import 'package:dio_http_cache_lts/dio_http_cache_lts.dart';
import 'package:injectable/injectable.dart' hide Environment;
import 'package:revanced_manager/utils/environment.dart';
import 'package:sentry_dio/sentry_dio.dart';
import 'package:sentry_flutter/sentry_flutter.dart';

@lazySingleton
class CrowdinAPI {
late Dio _dio = Dio();
final DioCacheManager _dioCacheManager = DioCacheManager(CacheConfig());
final apiKey = Environment.crowdinKEY;

Future<void> initialize() async {
try {
_dio = Dio(BaseOptions(
baseUrl: 'https://api.crowdin.com/api/v2',
));

_dio.interceptors.add(_dioCacheManager.interceptor);
_dio.addSentry(
captureFailedRequests: true,
);
} on Exception catch (e, s) {
await Sentry.captureException(e, stackTrace: s);
}
}

Future<void> clearAllCache() async {
try {
await _dioCacheManager.clearAll();
} on Exception catch (e, s) {
await Sentry.captureException(e, stackTrace: s);
}
}

Future<List> getLanguages() async {
try {
var response = await _dio.get(
'/projects',
options: buildCacheOptions(
const Duration(hours: 6),
maxStale: const Duration(days: 1),
options: Options(
headers: {
'Authorization': 'Bearer $apiKey',
},
contentType: 'application/json',
),
),
);
List targetLanguages =
await response.data['data'][0]['data']['targetLanguages'];

return targetLanguages;
} on Exception catch (e, s) {
await Sentry.captureException(e, stackTrace: s);
return [];
}
}
}
2 changes: 1 addition & 1 deletion lib/ui/views/settings/settings_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class SettingsView extends StatelessWidget {
SettingsTileDialog(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
title: 'settingsView.languageLabel',
subtitle: 'English',
subtitle: model.selectedLanguage,
onTap: () => model.showLanguagesDialog(context),
),
_settingsDivider,
Expand Down
76 changes: 54 additions & 22 deletions lib/ui/views/settings/settings_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,49 @@ import 'package:logcat/logcat.dart';
import 'package:path_provider/path_provider.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/app/app.router.dart';
import 'package:revanced_manager/main.dart';
import 'package:revanced_manager/services/crowdin_api.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/services/toast.dart';
import 'package:revanced_manager/ui/views/navigation/navigation_viewmodel.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart';
import 'package:revanced_manager/ui/widgets/settingsView/custom_text_field.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:share_extend/share_extend.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
import 'package:timeago/timeago.dart';
import 'package:timeago/timeago.dart' as timeago;
import 'package:shared_preferences/shared_preferences.dart';

// ignore: constant_identifier_names
const int ANDROID_12_SDK_VERSION = 31;

class SettingsViewModel extends BaseViewModel {
final NavigationService _navigationService = locator<NavigationService>();
final ManagerAPI _managerAPI = locator<ManagerAPI>();
final CrowdinAPI _crowdinAPI = locator<CrowdinAPI>();
final Toast _toast = locator<Toast>();
final TextEditingController _orgPatSourceController = TextEditingController();
final TextEditingController _patSourceController = TextEditingController();
final TextEditingController _orgIntSourceController = TextEditingController();
final TextEditingController _intSourceController = TextEditingController();
final TextEditingController _apiUrlController = TextEditingController();
late SharedPreferences _prefs;
String selectedLanguage = 'English';
String selectedLanguageLocale = prefs.getString('language') ?? 'en_US';
List languages = [];

void setLanguage(String language) {
Future<void> initLang() async {
languages = await _crowdinAPI.getLanguages();
languages.sort((a, b) => a['name'].compareTo(b['name']));
notifyListeners();
}

Future<void> initialize() async {
_prefs = await SharedPreferences.getInstance();
selectedLanguageLocale =
_prefs.getString('language') ?? selectedLanguageLocale;
notifyListeners();
}

Expand All @@ -45,8 +63,13 @@ class SettingsViewModel extends BaseViewModel {

Future<void> updateLanguage(BuildContext context, String? value) async {
if (value != null) {
selectedLanguageLocale = value;
_prefs = await SharedPreferences.getInstance();
await _prefs.setString('language', value);
await FlutterI18n.refresh(context, Locale(value));
setLocaleMessages(value, EnMessages());
timeago.setLocaleMessages(value, timeago.EnMessages());
locator<NavigationViewModel>().notifyListeners();
notifyListeners();
}
}

Expand Down Expand Up @@ -86,21 +109,33 @@ class SettingsViewModel extends BaseViewModel {
notifyListeners();
}

Future<void> showLanguagesDialog(BuildContext context) {
Future<void> showLanguagesDialog(BuildContext parentContext) {
initLang();
return showDialog(
context: context,
context: parentContext,
builder: (context) => SimpleDialog(
title: I18nText('settingsView.languageLabel'),
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
children: <Widget>[
RadioListTile<String>(
title: I18nText('settingsView.englishOption'),
value: 'en',
groupValue: 'en',
onChanged: (value) {
updateLanguage(context, value);
Navigator.of(context).pop();
},
children: [
SizedBox(
height: 500,
child: ListView.builder(
itemCount: languages.length,
itemBuilder: (context, index) {
return RadioListTile<String>(
title: Text(languages[index]['name']),
subtitle: Text(languages[index]['locale']),
value: languages[index]['locale'],
groupValue: selectedLanguageLocale,
onChanged: (value) {
selectedLanguage = languages[index]['name'];
_toast.show('settingsView.restartAppForChanges');
updateLanguage(context, value);
Navigator.pop(context);
},
);
},
),
),
],
),
Expand Down Expand Up @@ -355,16 +390,13 @@ class SettingsViewModel extends BaseViewModel {
try {
File outFile = File(_managerAPI.storedPatchesFile);
if (outFile.existsSync()) {
String dateTime = DateTime.now()
.toString()
.replaceAll(' ', '_')
.split('.').first;
String tempFilePath = '${outFile.path.substring(0, outFile.path.lastIndexOf('/') + 1)}selected_patches_$dateTime.json';
String dateTime =
DateTime.now().toString().replaceAll(' ', '_').split('.').first;
String tempFilePath =
'${outFile.path.substring(0, outFile.path.lastIndexOf('/') + 1)}selected_patches_$dateTime.json';
outFile.copySync(tempFilePath);
await CRFileSaver.saveFileWithDialog(SaveFileDialogParams(
sourceFilePath: tempFilePath,
destinationFileName: ''
));
sourceFilePath: tempFilePath, destinationFileName: ''));
File(tempFilePath).delete();
locator<Toast>().showBottom('settingsView.exportedPatches');
} else {
Expand Down

1 comment on commit be77a18

@HiFIi
Copy link

@HiFIi HiFIi commented on be77a18 Nov 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice :)

Please sign in to comment.