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

pull/2245/head
ggurdin 4 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:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:get_storage/get_storage.dart'; import 'package:get_storage/get_storage.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pangea/common/config/environment.dart'; import 'package:fluffychat/pangea/common/config/environment.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/common/utils/firebase_analytics.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/pangea/learning_settings/utils/p_language_store.dart';
import 'package:fluffychat/utils/client_manager.dart'; import 'package:fluffychat/utils/client_manager.dart';
import 'package:fluffychat/utils/platform_infos.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 DeviceOrientation.portraitUp, // Lock to portrait mode
]); ]);
// Pangea# // 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 /// Watches the lifecycle changes to start the application when it

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

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

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

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

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

@ -1,6 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:developer'; import 'dart:developer';
import 'dart:math';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.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/constructs_model.dart';
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.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/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_message_event.dart';
import 'package:fluffychat/pangea/events/event_wrappers/pangea_representation_event.dart'; import 'package:fluffychat/pangea/events/event_wrappers/pangea_representation_event.dart';
import 'package:fluffychat/pangea/events/models/pangea_token_model.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(() { void updateToolbarMode(MessageMode mode) => setState(() {
selectedChoice = null; 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/bot/utils/bot_name.dart';
import 'package:fluffychat/pangea/common/constants/model_keys.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/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/events/constants/pangea_event_types.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 'package:fluffychat/pangea/user/models/profile_model.dart';
import '../models/user_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 /// Controller that manages saving and reading of user/profile information
class UserController extends BaseController { class UserController {
late PangeaController _pangeaController; late PangeaController _pangeaController;
final StreamController<LanguageUpdate> languageStream =
StreamController.broadcast();
final StreamController settingsUpdateStream =
StreamController<Profile>.broadcast();
UserController(PangeaController pangeaController) : super() { UserController(PangeaController pangeaController) : super() {
_pangeaController = pangeaController; _pangeaController = pangeaController;
} }
@ -94,19 +113,19 @@ class UserController extends BaseController {
await updatedProfile.saveProfileData(waitForDataInSync: waitForDataInSync); await updatedProfile.saveProfileData(waitForDataInSync: waitForDataInSync);
Map<String, dynamic>? profileUpdate; if ((prevTargetLang != _pangeaController.languageController.userL2) ||
(prevBaseLang != _pangeaController.languageController.userL1)) {
if (prevTargetLang != _pangeaController.languageController.userL2) { languageStream.add(
profileUpdate ??= {}; LanguageUpdate(
profileUpdate['prev_target_lang'] = prevTargetLang; baseLang: _pangeaController.languageController.userL1!,
} targetLang: _pangeaController.languageController.userL2!,
prevBaseLang: prevBaseLang,
if (prevBaseLang != _pangeaController.languageController.userL1) { prevTargetLang: prevTargetLang,
profileUpdate ??= {}; ),
profileUpdate['prev_base_lang'] = prevBaseLang; );
} else {
settingsUpdateStream.add(null);
} }
setState(profileUpdate);
} }
/// A completer for the profile model of a user. /// A completer for the profile model of a user.
@ -131,7 +150,6 @@ class UserController extends BaseController {
_pangeaController.languageController.userL2 == null) { _pangeaController.languageController.userL2 == null) {
// update the language list and send an update to refresh analytics summary // update the language list and send an update to refresh analytics summary
await PLanguageStore.initialize(forceRefresh: true); await PLanguageStore.initialize(forceRefresh: true);
setState(null);
} }
} catch (err, s) { } catch (err, s) {
ErrorHandler.logError( ErrorHandler.logError(

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

@ -21,6 +21,8 @@ import 'package:url_launcher/url_launcher_string.dart';
import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/common/controllers/pangea_controller.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/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/client_manager.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_file_extension.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_file_extension.dart';
import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/utils/platform_infos.dart';
@ -181,6 +183,7 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
MatrixState.pangeaController.handleLoginStateChange( MatrixState.pangeaController.handleLoginStateChange(
LoginState.loggedIn, LoginState.loggedIn,
_loginClientCandidate!.userID, _loginClientCandidate!.userID,
context,
); );
// Pangea# // Pangea#
if (!widget.clients.contains(_loginClientCandidate)) { if (!widget.clients.contains(_loginClientCandidate)) {
@ -259,9 +262,38 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
), ),
); );
pangeaController = PangeaController(matrix: widget, matrixState: this); pangeaController = PangeaController(matrix: widget, matrixState: this);
WidgetsBinding.instance.addPostFrameCallback((_) {
_setAppLanguage();
_setLanguageListener();
});
// Pangea# // 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 { Future<void> initConfig() async {
try { try {
final configJsonString = final configJsonString =
@ -320,6 +352,7 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
MatrixState.pangeaController.handleLoginStateChange( MatrixState.pangeaController.handleLoginStateChange(
state, state,
c.userID, c.userID,
context,
); );
// Pangea# // Pangea#
final loggedInWithMultipleClients = widget.clients.length > 1; final loggedInWithMultipleClients = widget.clients.length > 1;
@ -500,6 +533,9 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
onBlurSub?.cancel(); onBlurSub?.cancel();
linuxNotifications?.close(); linuxNotifications?.close();
// #Pangea
_languageListener?.cancel();
// Pangea#
super.dispose(); super.dispose();
} }

Loading…
Cancel
Save