feat: set app language to user's L1 (#3554)
This commit is contained in:
parent
c017508a6a
commit
3bd840c621
12 changed files with 142 additions and 105 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
19
lib/pangea/learning_settings/utils/locale_provider.dart
Normal file
19
lib/pangea/learning_settings/utils/locale_provider.dart
Normal file
|
|
@ -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 ((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);
|
||||
}
|
||||
|
||||
if (prevBaseLang != _pangeaController.languageController.userL1) {
|
||||
profileUpdate ??= {};
|
||||
profileUpdate['prev_base_lang'] = prevBaseLang;
|
||||
}
|
||||
|
||||
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…
Add table
Reference in a new issue