feat: set app language to user's L1 (#3554)

pull/2245/head
ggurdin 3 months ago committed by GitHub
parent c017508a6a
commit 3bd840c621
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -6,12 +6,14 @@ import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:get_storage/get_storage.dart';
import 'package:matrix/matrix.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pangea/common/config/environment.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/common/utils/firebase_analytics.dart';
import 'package:fluffychat/pangea/learning_settings/utils/locale_provider.dart';
import 'package:fluffychat/pangea/learning_settings/utils/p_language_store.dart';
import 'package:fluffychat/utils/client_manager.dart';
import 'package:fluffychat/utils/platform_infos.dart';
@ -120,7 +122,16 @@ Future<void> startGui(List<Client> clients, SharedPreferences store) async {
DeviceOrientation.portraitUp, // Lock to portrait mode
]);
// Pangea#
runApp(FluffyChatApp(clients: clients, pincode: pin, store: store));
// #Pangea
// runApp(FluffyChatApp(clients: clients, pincode: pin, store: store));
runApp(
ChangeNotifierProvider(
create: (_) => LocaleProvider(),
child: FluffyChatApp(clients: clients, pincode: pin, store: store),
),
);
// Pangea#
}
/// Watches the lifecycle changes to start the application when it

@ -45,15 +45,12 @@ class ActivitySuggestionsAreaState extends State<ActivitySuggestionsArea> {
super.initState();
_setActivityItems();
_languageStream ??= MatrixState.pangeaController.userController.stateStream
_languageStream ??= MatrixState
.pangeaController.userController.languageStream.stream
.listen((update) {
if (update is Map<String, dynamic> &&
(update.containsKey('prev_base_lang') ||
update.containsKey('prev_target_lang'))) {
WidgetsBinding.instance.addPostFrameCallback(
(_) => _setActivityItems(),
);
}
WidgetsBinding.instance.addPostFrameCallback(
(_) => _setActivityItems(),
);
});
}

@ -59,12 +59,8 @@ class PutAnalyticsController extends BaseController<AnalyticsStream> {
// Listen for changes to the user's language settings
_languageStream ??=
_pangeaController.userController.stateStream.listen((update) {
if (update is Map<String, dynamic> &&
update['prev_target_lang'] is LanguageModel) {
final LanguageModel previousL2 = update['prev_target_lang'];
_onUpdateLanguages(previousL2);
}
_pangeaController.userController.languageStream.stream.listen((update) {
_onUpdateLanguages(update.prevTargetLang);
});
_refreshAnalyticsIfOutdated();

@ -57,8 +57,9 @@ class LearningProgressIndicatorsState
.listen(updateData);
// rebuild when target language changes
_languageSubscription =
MatrixState.pangeaController.userController.stateStream.listen((_) {
_languageSubscription = MatrixState
.pangeaController.userController.languageStream.stream
.listen((_) {
if (mounted) setState(() {});
});
}

@ -55,6 +55,7 @@ class Choreographer {
final StreamController stateStream = StreamController.broadcast();
StreamSubscription? _languageStream;
StreamSubscription? _settingsUpdateStream;
late AssistanceState _currentAssistanceState;
String? translatedText;
@ -70,14 +71,13 @@ class Choreographer {
errorService = ErrorService(this);
_textController.addListener(_onChangeListener);
_languageStream =
pangeaController.userController.stateStream.listen((update) {
if (update is Map<String, dynamic> &&
update['prev_target_lang'] is LanguageModel) {
clear();
}
pangeaController.userController.languageStream.stream.listen((update) {
clear();
setState();
});
// refresh on any profile update, to account
// for changes like enabling autocorrect
_settingsUpdateStream =
pangeaController.userController.settingsUpdateStream.stream.listen((_) {
setState();
});
_currentAssistanceState = assistanceState;
@ -589,6 +589,7 @@ class Choreographer {
dispose() {
_textController.dispose();
_languageStream?.cancel();
_settingsUpdateStream?.cancel();
stateStream.close();
TtsController.stop();
}

@ -1,10 +1,11 @@
import 'dart:async';
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:get_storage/get_storage.dart';
import 'package:matrix/matrix.dart';
import 'package:provider/provider.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:fluffychat/config/app_config.dart';
@ -17,6 +18,7 @@ import 'package:fluffychat/pangea/events/controllers/message_data_controller.dar
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:fluffychat/pangea/guard/p_vguard.dart';
import 'package:fluffychat/pangea/learning_settings/controllers/language_controller.dart';
import 'package:fluffychat/pangea/learning_settings/utils/locale_provider.dart';
import 'package:fluffychat/pangea/learning_settings/utils/p_language_store.dart';
import 'package:fluffychat/pangea/spaces/controllers/space_controller.dart';
import 'package:fluffychat/pangea/subscription/controllers/subscription_controller.dart';
@ -99,10 +101,11 @@ class PangeaController {
PAuthGaurd.pController = this;
}
_logOutfromPangea() {
_logOutfromPangea(BuildContext context) {
debugPrint("Pangea logout");
GoogleAnalytics.logout();
clearCache();
Provider.of<LocaleProvider>(context, listen: false).setLocale(null);
}
static final List<String> _storageKeys = [
@ -126,9 +129,10 @@ class PangeaController {
'onboarding_storage',
];
Future<void> clearCache() async {
Future<void> clearCache({List<String> exclude = const []}) async {
final List<Future<void>> futures = [];
for (final key in _storageKeys) {
if (exclude.contains(key)) continue;
futures.add(GetStorage(key).erase());
}
await Future.wait(futures);
@ -160,7 +164,11 @@ class PangeaController {
}
/// check user information if not found then redirect to Date of birth page
void handleLoginStateChange(LoginState state, String? userID) {
void handleLoginStateChange(
LoginState state,
String? userID,
BuildContext context,
) {
switch (state) {
case LoginState.loggedOut:
case LoginState.softLoggedOut:
@ -170,6 +178,7 @@ class PangeaController {
userController.clear();
_languageStream?.cancel();
_languageStream = null;
_logOutfromPangea(context);
break;
case LoginState.loggedIn:
// Initialize analytics data
@ -177,13 +186,14 @@ class PangeaController {
getAnalytics.initialize();
_setLanguageStream();
userController.reinitialize();
userController.reinitialize().then((_) {
final l1 = userController.profile.userSettings.sourceLanguage;
Provider.of<LocaleProvider>(context, listen: false).setLocale(l1);
});
subscriptionController.reinitialize();
break;
}
if (state != LoginState.loggedIn) {
_logOutfromPangea();
}
Sentry.configureScope(
(scope) => scope.setUser(
SentryUser(
@ -204,12 +214,9 @@ class PangeaController {
void _setLanguageStream() {
_languageStream?.cancel();
_languageStream = userController.stateStream.listen((update) {
if (update is Map<String, dynamic> &&
update['prev_target_lang'] != null) {
clearCache();
}
});
_languageStream = userController.languageStream.stream.listen(
(_) => clearCache(exclude: ["analytics_storage"]),
);
}
Future<void> setPangeaPushRules() async {

@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
class LocaleProvider extends ChangeNotifier {
Locale? _locale;
Locale? get locale => _locale;
void setLocale(String? value) {
if (value == null || value.isEmpty) {
_locale = null;
notifyListeners();
return;
}
final split = value.split('-');
_locale = Locale(split[0], split.length > 1 ? split[1] : null);
notifyListeners();
}
}

@ -34,8 +34,6 @@ class ConstructXpWidgetState extends State<ConstructXpWidget>
bool didChange = false;
late AnimationController _controller;
late Animation<Offset> _offsetAnimation;
late Animation<double> _fadeAnimation;
StreamSubscription<AnalyticsStreamUpdate>? _sub;
@ -48,26 +46,6 @@ class ConstructXpWidgetState extends State<ConstructXpWidget>
vsync: this,
);
_offsetAnimation = Tween<Offset>(
begin: Offset.zero,
end: const Offset(0.0, -1.0),
).animate(
CurvedAnimation(
parent: _controller,
curve: Curves.easeOut,
),
);
_fadeAnimation = Tween<double>(
begin: 1.0,
end: 0.0,
).animate(
CurvedAnimation(
parent: _controller,
curve: Curves.easeOut,
),
);
setState(() => constructLemmaCategory = constructUse?.lemmaCategory);
debugPrint('constructLemmaCategory: $constructLemmaCategory');

@ -1,6 +1,5 @@
import 'dart:async';
import 'dart:developer';
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@ -16,7 +15,6 @@ import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart';
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/common/utils/overlay.dart';
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart';
import 'package:fluffychat/pangea/events/event_wrappers/pangea_representation_event.dart';
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
@ -286,34 +284,6 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
// }
}
void _showReadingAssistanceContent() {
if (selectedToken == null) return;
if (MatrixState.pAnyState.isOverlayOpen(
selectedToken!.text.uniqueKey,
)) {
return;
}
final entry = ReadingAssistanceContent(
key: wordZoomKey,
pangeaMessageEvent: pangeaMessageEvent!,
overlayController: this,
);
if (mounted) {
OverlayUtil.showPositionedCard(
context: context,
cardToShow: entry,
transformTargetId: selectedToken!.text.uniqueKey,
closePrevOverlay: false,
backDropToDismiss: false,
addBorder: false,
overlayKey: "${selectedToken!.text.uniqueKey}_toolbar",
maxHeight: AppConfig.toolbarMaxHeight,
maxWidth: min(AppConfig.toolbarMinWidth, maxWidth),
);
}
}
void updateToolbarMode(MessageMode mode) => setState(() {
selectedChoice = null;

@ -6,7 +6,6 @@ import 'package:matrix/matrix.dart' as matrix;
import 'package:fluffychat/pangea/bot/utils/bot_name.dart';
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
import 'package:fluffychat/pangea/common/controllers/base_controller.dart';
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart';
@ -16,9 +15,29 @@ import 'package:fluffychat/pangea/learning_settings/utils/p_language_store.dart'
import 'package:fluffychat/pangea/user/models/profile_model.dart';
import '../models/user_model.dart';
class LanguageUpdate {
final LanguageModel? prevBaseLang;
final LanguageModel? prevTargetLang;
final LanguageModel baseLang;
final LanguageModel targetLang;
LanguageUpdate({
required this.baseLang,
required this.targetLang,
this.prevBaseLang,
this.prevTargetLang,
});
}
/// Controller that manages saving and reading of user/profile information
class UserController extends BaseController {
class UserController {
late PangeaController _pangeaController;
final StreamController<LanguageUpdate> languageStream =
StreamController.broadcast();
final StreamController settingsUpdateStream =
StreamController<Profile>.broadcast();
UserController(PangeaController pangeaController) : super() {
_pangeaController = pangeaController;
}
@ -94,19 +113,19 @@ class UserController extends BaseController {
await updatedProfile.saveProfileData(waitForDataInSync: waitForDataInSync);
Map<String, dynamic>? profileUpdate;
if (prevTargetLang != _pangeaController.languageController.userL2) {
profileUpdate ??= {};
profileUpdate['prev_target_lang'] = prevTargetLang;
}
if (prevBaseLang != _pangeaController.languageController.userL1) {
profileUpdate ??= {};
profileUpdate['prev_base_lang'] = prevBaseLang;
if ((prevTargetLang != _pangeaController.languageController.userL2) ||
(prevBaseLang != _pangeaController.languageController.userL1)) {
languageStream.add(
LanguageUpdate(
baseLang: _pangeaController.languageController.userL1!,
targetLang: _pangeaController.languageController.userL2!,
prevBaseLang: prevBaseLang,
prevTargetLang: prevTargetLang,
),
);
} else {
settingsUpdateStream.add(null);
}
setState(profileUpdate);
}
/// A completer for the profile model of a user.
@ -131,7 +150,6 @@ class UserController extends BaseController {
_pangeaController.languageController.userL2 == null) {
// update the language list and send an update to refresh analytics summary
await PLanguageStore.initialize(forceRefresh: true);
setState(null);
}
} catch (err, s) {
ErrorHandler.logError(

@ -4,12 +4,14 @@ import 'package:country_picker/country_picker.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:fluffychat/config/routes.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/common/utils/firebase_analytics.dart';
import 'package:fluffychat/pangea/learning_settings/utils/locale_provider.dart';
import 'package:fluffychat/widgets/app_lock.dart';
import 'package:fluffychat/widgets/theme_builder.dart';
import '../config/app_config.dart';
@ -58,6 +60,7 @@ class FluffyChatApp extends StatelessWidget {
FluffyThemes.buildTheme(context, Brightness.dark, primaryColor),
scrollBehavior: CustomScrollBehavior(),
// #Pangea
locale: Provider.of<LocaleProvider>(context).locale,
// localizationsDelegates: L10n.localizationsDelegates,
localizationsDelegates: const [
L10n.delegate,

@ -21,6 +21,8 @@ import 'package:url_launcher/url_launcher_string.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/common/utils/any_state_holder.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/learning_settings/utils/locale_provider.dart';
import 'package:fluffychat/utils/client_manager.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_file_extension.dart';
import 'package:fluffychat/utils/platform_infos.dart';
@ -181,6 +183,7 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
MatrixState.pangeaController.handleLoginStateChange(
LoginState.loggedIn,
_loginClientCandidate!.userID,
context,
);
// Pangea#
if (!widget.clients.contains(_loginClientCandidate)) {
@ -259,9 +262,38 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
),
);
pangeaController = PangeaController(matrix: widget, matrixState: this);
WidgetsBinding.instance.addPostFrameCallback((_) {
_setAppLanguage();
_setLanguageListener();
});
// Pangea#
}
// #Pangea
StreamSubscription? _languageListener;
Future<void> _setLanguageListener() async {
await pangeaController.userController.initialize();
_languageListener?.cancel();
_languageListener = pangeaController.userController.languageStream.stream
.listen((_) => _setAppLanguage());
}
void _setAppLanguage() {
try {
Provider.of<LocaleProvider>(context, listen: false).setLocale(
pangeaController.userController.profile.userSettings.sourceLanguage,
);
} catch (e, s) {
Logs().e('Error setting app language', e);
ErrorHandler.logError(
e: e,
s: s,
data: {},
);
}
}
// Pangea#
Future<void> initConfig() async {
try {
final configJsonString =
@ -320,6 +352,7 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
MatrixState.pangeaController.handleLoginStateChange(
state,
c.userID,
context,
);
// Pangea#
final loggedInWithMultipleClients = widget.clients.length > 1;
@ -500,6 +533,9 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
onBlurSub?.cancel();
linuxNotifications?.close();
// #Pangea
_languageListener?.cancel();
// Pangea#
super.dispose();
}

Loading…
Cancel
Save