diff --git a/lib/pages/chat/chat_input_row.dart b/lib/pages/chat/chat_input_row.dart index 1f5a16db3..bca5450da 100644 --- a/lib/pages/chat/chat_input_row.dart +++ b/lib/pages/chat/chat_input_row.dart @@ -70,12 +70,8 @@ class ChatInputRow extends StatelessWidget { activel1.langCode != LanguageKeys.unknownLanguage && activel2.langCode != LanguageKeys.unknownLanguage ? L10n.of(context).writeAMessageFlag( - activel1.languageEmoji ?? - activel1.getDisplayName(context) ?? - activel1.langCode, - activel2.languageEmoji ?? - activel2.getDisplayName(context) ?? - activel2.langCode, + activel1.getDisplayName(context) ?? activel1.langCode, + activel2.getDisplayName(context) ?? activel2.langCode, ) : L10n.of(context).writeAMessage; } diff --git a/lib/pangea/analytics_misc/client_analytics_extension.dart b/lib/pangea/analytics_misc/client_analytics_extension.dart index 66aa04650..2fa509be7 100644 --- a/lib/pangea/analytics_misc/client_analytics_extension.dart +++ b/lib/pangea/analytics_misc/client_analytics_extension.dart @@ -11,25 +11,25 @@ import 'package:fluffychat/pangea/chat_settings/constants/pangea_room_types.dart import 'package:fluffychat/pangea/common/constants/model_keys.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; +import 'package:fluffychat/pangea/learning_settings/models/language_model.dart'; import 'package:fluffychat/widgets/matrix.dart'; extension AnalyticsClientExtension on Client { /// Get the logged in user's analytics room matching /// a given langCode. If not present, create it. - Future getMyAnalyticsRoom(String langCode) async { - final Room? analyticsRoom = analyticsRoomLocal(langCode); + Future getMyAnalyticsRoom(LanguageModel lang) async { + final Room? analyticsRoom = analyticsRoomLocal(lang); if (analyticsRoom != null) return analyticsRoom; - return _makeAnalyticsRoom(langCode); + return _makeAnalyticsRoom(lang); } /// Get local analytics room for a given langCode and /// optional userId (if not specified, uses current user). /// If user is invited to the room, joins the room. - Room? analyticsRoomLocal([String? langCode, String? userIdParam]) { - langCode ??= - MatrixState.pangeaController.languageController.userL2?.langCode; + Room? analyticsRoomLocal([LanguageModel? lang, String? userIdParam]) { + lang ??= MatrixState.pangeaController.languageController.userL2; - if (langCode == null) { + if (lang == null) { debugger(when: kDebugMode); return null; } @@ -37,7 +37,7 @@ extension AnalyticsClientExtension on Client { final Room? analyticsRoom = rooms.firstWhereOrNull((e) { return e.isAnalyticsRoom && e.isAnalyticsRoomOfUser(userIdParam ?? userID!) && - e.isMadeForLang(langCode!); + e.isMadeForLang(lang!.langCodeShort); }); if (analyticsRoom != null && analyticsRoom.membership == Membership.invite) { @@ -47,7 +47,7 @@ extension AnalyticsClientExtension on Client { e: error, s: stackTrace, data: { - "langCode": langCode, + "langCode": lang!.langCodeShort, "userIdParam": userIdParam, }, ), @@ -62,7 +62,7 @@ extension AnalyticsClientExtension on Client { /// /// If the room does not appear immediately after creation, this method waits for it to appear in sync. /// Returns the created [Room] object. - Future _makeAnalyticsRoom(String langCode) async { + Future _makeAnalyticsRoom(LanguageModel lang) async { if (userID == null || userID == BotName.byEnvironment) { return null; } @@ -70,9 +70,9 @@ extension AnalyticsClientExtension on Client { final String roomID = await createRoom( creationContent: { 'type': PangeaRoomTypes.analytics, - ModelKey.langCode: langCode, + ModelKey.langCode: lang.langCodeShort, }, - name: "$userID $langCode Analytics", + name: "$userID ${lang.langCodeShort} Analytics", topic: "This room stores learning analytics for $userID.", preset: CreateRoomPreset.publicChat, visibility: Visibility.private, diff --git a/lib/pangea/analytics_misc/get_analytics_controller.dart b/lib/pangea/analytics_misc/get_analytics_controller.dart index bd3a9cf53..147f893ac 100644 --- a/lib/pangea/analytics_misc/get_analytics_controller.dart +++ b/lib/pangea/analytics_misc/get_analytics_controller.dart @@ -18,6 +18,7 @@ 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/extensions/pangea_room_extension.dart'; +import 'package:fluffychat/pangea/learning_settings/models/language_model.dart'; /// A minimized version of AnalyticsController that get the logged in user's analytics class GetAnalyticsController extends BaseController { @@ -42,7 +43,7 @@ class GetAnalyticsController extends BaseController { ); } - String? get _l2Code => _pangeaController.languageController.userL2?.langCode; + LanguageModel? get _l2 => _pangeaController.languageController.userL2; Client get _client => _pangeaController.matrixState.client; // the minimum XP required for a given level @@ -282,13 +283,13 @@ class GetAnalyticsController extends BaseController { Future myAnalyticsLastUpdated() async { // this function gets called soon after login, so first // make sure that the user's l2 is loaded, if the user has set their l2 - if (_client.userID != null && _l2Code == null) { + if (_client.userID != null && _l2 == null) { if (_pangeaController.matrixState.client.prevBatch == null) { await _pangeaController.matrixState.client.onSync.stream.first; } - if (_l2Code == null) return null; + if (_l2 == null) return null; } - final Room? analyticsRoom = _client.analyticsRoomLocal(_l2Code!); + final Room? analyticsRoom = _client.analyticsRoomLocal(_l2!); if (analyticsRoom == null) return null; final DateTime? lastUpdated = await analyticsRoom.analyticsLastUpdated( _client.userID!, @@ -298,8 +299,8 @@ class GetAnalyticsController extends BaseController { /// Get all the construct analytics events for the logged in user Future> _allMyConstructs() async { - if (_l2Code == null) return []; - final Room? analyticsRoom = _client.analyticsRoomLocal(_l2Code!); + if (_l2 == null) return []; + final Room? analyticsRoom = _client.analyticsRoomLocal(_l2!); if (analyticsRoom == null) return []; return await analyticsRoom.getAnalyticsEvents(userId: _client.userID!) ?? []; @@ -310,7 +311,7 @@ class GetAnalyticsController extends BaseController { ConstructTypeEnum? constructType, }) { final index = _cache.indexWhere( - (e) => e.type == constructType && e.langCode == _l2Code, + (e) => e.type == constructType && e.langCode == _l2?.langCodeShort, ); if (index > -1) { @@ -330,11 +331,11 @@ class GetAnalyticsController extends BaseController { required List uses, ConstructTypeEnum? constructType, }) { - if (_l2Code == null) return; + if (_l2 == null) return; final entry = AnalyticsCacheEntry( type: constructType, uses: List.from(uses), - langCode: _l2Code!, + langCode: _l2!.langCodeShort, ); _cache.add(entry); } diff --git a/lib/pangea/analytics_misc/put_analytics_controller.dart b/lib/pangea/analytics_misc/put_analytics_controller.dart index 1454e2fa9..0d099c0ee 100644 --- a/lib/pangea/analytics_misc/put_analytics_controller.dart +++ b/lib/pangea/analytics_misc/put_analytics_controller.dart @@ -14,6 +14,7 @@ import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/events/models/pangea_token_model.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; +import 'package:fluffychat/pangea/learning_settings/models/language_model.dart'; enum AnalyticsUpdateType { server, local } @@ -30,8 +31,6 @@ class PutAnalyticsController extends BaseController { Client get _client => _pangeaController.matrixState.client; - String? get _userL2 => _pangeaController.languageController.activeL2Code(); - /// the last time that matrix analytics events were updated for the user's current l2 DateTime? lastUpdated; @@ -62,8 +61,9 @@ class PutAnalyticsController extends BaseController { // Listen for changes to the user's language settings _languageStream ??= _pangeaController.userController.stateStream.listen((update) { - if (update is Map) { - final previousL2 = update['prev_target_lang']; + if (update is Map && + update['prev_target_lang'] is LanguageModel) { + final LanguageModel previousL2 = update['prev_target_lang']; _onUpdateLanguages(previousL2); } }); @@ -147,7 +147,7 @@ class PutAnalyticsController extends BaseController { ); } - Future _onUpdateLanguages(String? previousL2) async { + Future _onUpdateLanguages(LanguageModel? previousL2) async { await sendLocalAnalyticsToAnalyticsRoom( l2Override: previousL2, ); @@ -361,7 +361,7 @@ class PutAnalyticsController extends BaseController { /// since the last update and notifies the [analyticsUpdateStream]. Future sendLocalAnalyticsToAnalyticsRoom({ onLogout = false, - String? l2Override, + LanguageModel? l2Override, }) async { if (_pangeaController.matrixState.client.userID == null) return; if (_pangeaController.getAnalytics.messagesSinceUpdate.isEmpty) return; @@ -400,7 +400,7 @@ class PutAnalyticsController extends BaseController { /// Updates the analytics by sending cached analytics data to the analytics room. /// The analytics room is determined based on the user's current target language. - Future _updateAnalytics({String? l2Override}) async { + Future _updateAnalytics({LanguageModel? l2Override}) async { // if there's no cached construct data, there's nothing to send final cachedConstructs = _pangeaController.getAnalytics.messagesSinceUpdate; final bool onlyDraft = cachedConstructs.length == 1 && @@ -408,11 +408,11 @@ class PutAnalyticsController extends BaseController { if (cachedConstructs.isEmpty || onlyDraft) return; // if missing important info, don't send analytics. Could happen if user just signed up. - final l2Code = l2Override ?? _userL2; - if (l2Code == null || _client.userID == null) return; + final l2 = l2Override ?? _pangeaController.languageController.userL2; + if (l2 == null || _client.userID == null) return; // analytics room for the user and current target language - final Room? analyticsRoom = await _client.getMyAnalyticsRoom(l2Code); + final Room? analyticsRoom = await _client.getMyAnalyticsRoom(l2); // and send cached analytics data to the room await analyticsRoom?.sendConstructsEvent( diff --git a/lib/pangea/choreographer/widgets/it_bar.dart b/lib/pangea/choreographer/widgets/it_bar.dart index cb7141781..0cb5caa31 100644 --- a/lib/pangea/choreographer/widgets/it_bar.dart +++ b/lib/pangea/choreographer/widgets/it_bar.dart @@ -362,6 +362,7 @@ class ITChoices extends StatelessWidget { maxWidth: 300, borderColor: borderColor, transformTargetId: controller.choreographer.itBarTransformTargetKey, + isScrollable: choiceFeedback == null, ); } diff --git a/lib/pangea/choreographer/widgets/it_feedback_card.dart b/lib/pangea/choreographer/widgets/it_feedback_card.dart index b4e63692e..5ddd9708b 100644 --- a/lib/pangea/choreographer/widgets/it_feedback_card.dart +++ b/lib/pangea/choreographer/widgets/it_feedback_card.dart @@ -1,9 +1,11 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:http/http.dart'; +import 'package:fluffychat/pangea/analytics_misc/text_loading_shimmer.dart'; import 'package:fluffychat/pangea/choreographer/repo/full_text_translation_repo.dart'; -import '../../../config/app_config.dart'; import '../../../widgets/matrix.dart'; import '../../bot/utils/bot_style.dart'; import '../../common/controllers/pangea_controller.dart'; @@ -90,40 +92,37 @@ class ITFeedbackCardView extends StatelessWidget { @override Widget build(BuildContext context) { - final ScrollController scrollController = ScrollController(); + const characterWidth = 10.0; - return Scrollbar( - thumbVisibility: true, - controller: scrollController, - child: SingleChildScrollView( - controller: scrollController, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - controller.widget.req.chosenContinuance, - ), - const SizedBox(height: 10), - Text( - "≈", - style: TextStyle( - fontSize: - AppConfig.fontSizeFactor * AppConfig.messageFontSize * 1.5, - fontWeight: FontWeight.bold, - ), - ), - Container( - constraints: const BoxConstraints( - minHeight: 30, - ), - child: Text( - controller.res?.text ?? "loading", - style: BotStyle.text(context), - ), - ), - ], - ), + return Container( + constraints: const BoxConstraints(maxWidth: 300), + alignment: Alignment.center, + child: Wrap( + alignment: WrapAlignment.center, + children: [ + Text( + controller.widget.req.chosenContinuance, + style: BotStyle.text(context), + ), + const SizedBox(width: 10), + Text( + "≈", + style: BotStyle.text(context), + ), + const SizedBox(width: 10), + controller.res?.text != null + ? Text( + controller.res!.text, + style: BotStyle.text(context), + ) + : TextLoadingShimmer( + width: min( + 140, + characterWidth * + controller.widget.req.chosenContinuance.length, + ), + ), + ], ), ); } diff --git a/lib/pangea/common/network/urls.dart b/lib/pangea/common/network/urls.dart index 264943434..8608353ac 100644 --- a/lib/pangea/common/network/urls.dart +++ b/lib/pangea/common/network/urls.dart @@ -24,7 +24,7 @@ class PApiUrls { static String appVersion = "${PApiUrls.choreoEndpoint}/version"; /// ---------------------- Languages -------------------------------------- - static String getLanguages = "${PApiUrls.choreoEndpoint}/languages"; + static String getLanguages = "${PApiUrls.choreoEndpoint}/languages_v2"; /// ---------------------- Users -------------------------------------- static String paymentLink = "${PApiUrls.subscriptionEndpoint}/payment_link"; diff --git a/lib/pangea/common/utils/overlay.dart b/lib/pangea/common/utils/overlay.dart index 32e7a76d5..ab3304f8f 100644 --- a/lib/pangea/common/utils/overlay.dart +++ b/lib/pangea/common/utils/overlay.dart @@ -97,6 +97,7 @@ class OverlayUtil { Color? borderColor, bool closePrevOverlay = true, String? overlayKey, + bool isScrollable = true, }) { try { final LayerLinkAndKey layerLinkAndKey = @@ -142,6 +143,7 @@ class OverlayUtil { borderColor: borderColor, maxHeight: maxHeight, maxWidth: maxWidth, + isScrollable: isScrollable, ), ); diff --git a/lib/pangea/common/widgets/overlay_container.dart b/lib/pangea/common/widgets/overlay_container.dart index eae6c935f..88a2697fc 100644 --- a/lib/pangea/common/widgets/overlay_container.dart +++ b/lib/pangea/common/widgets/overlay_container.dart @@ -5,6 +5,7 @@ class OverlayContainer extends StatelessWidget { final Color? borderColor; final double maxHeight; final double maxWidth; + final bool isScrollable; const OverlayContainer({ super.key, @@ -12,10 +13,17 @@ class OverlayContainer extends StatelessWidget { this.borderColor, required this.maxHeight, required this.maxWidth, + this.isScrollable = true, }); @override Widget build(BuildContext context) { + final content = Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [cardToShow], + ); + return Container( padding: const EdgeInsets.fromLTRB(10, 10, 10, 10), decoration: BoxDecoration( @@ -35,14 +43,7 @@ class OverlayContainer extends StatelessWidget { minHeight: 100, minWidth: 100, ), - //PTODO - position card above input/message - // margin: const EdgeInsets.all(10), - child: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [cardToShow], - ), - ), + child: isScrollable ? SingleChildScrollView(child: content) : content, ); } } diff --git a/lib/pangea/events/models/representation_content_model.dart b/lib/pangea/events/models/representation_content_model.dart index 12c15e51a..3f1843624 100644 --- a/lib/pangea/events/models/representation_content_model.dart +++ b/lib/pangea/events/models/representation_content_model.dart @@ -103,8 +103,8 @@ class PangeaRepresentation { ChoreoRecord? choreo, }) { final List uses = []; - final l2 = MatrixState.pangeaController.languageController.activeL2Code(); - if (langCode != l2) return uses; + final l2 = MatrixState.pangeaController.languageController.userL2; + if (langCode.split("-")[0] != l2?.langCodeShort) return uses; // missing vital info so return if (event?.roomId == null && metadata?.roomId == null) { diff --git a/lib/pangea/learning_settings/constants/language_constants.dart b/lib/pangea/learning_settings/constants/language_constants.dart index 552ce46d5..dff1f383b 100644 --- a/lib/pangea/learning_settings/constants/language_constants.dart +++ b/lib/pangea/learning_settings/constants/language_constants.dart @@ -9,7 +9,7 @@ class LanguageKeys { class PrefKey { static const lastFetched = 'p_lang_lastfetched'; - static const flags = 'p_lang_flag'; + static const languagesKey = 'p_lang_flag'; } final LanguageDetection unknownLanguageDetection = LanguageDetection( diff --git a/lib/pangea/learning_settings/models/language_model.dart b/lib/pangea/learning_settings/models/language_model.dart index 0185548bf..6faee7565 100644 --- a/lib/pangea/learning_settings/models/language_model.dart +++ b/lib/pangea/learning_settings/models/language_model.dart @@ -1,29 +1,19 @@ -import 'dart:developer'; - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart'; import 'package:fluffychat/pangea/learning_settings/enums/l2_support_enum.dart'; -import '../../common/utils/error_handler.dart'; class LanguageModel { final String langCode; - final String languageFlag; final String displayName; - final String? languageEmoji; - final bool l1; final L2SupportEnum l2Support; LanguageModel({ required this.langCode, - required this.languageFlag, required this.displayName, - required this.l1, this.l2Support = L2SupportEnum.na, - this.languageEmoji, }); factory LanguageModel.fromJson(json) { @@ -35,12 +25,7 @@ class LanguageModel { return LanguageModel( langCode: code, - languageFlag: json['language_flag'] ?? "", - displayName: _LanguageLocal.getDisplayName( - code != LanguageKeys.unknownLanguage ? code : json['language_name'], - ), - l1: json["l1"] ?? !code.contains("es") && !code.contains("en"), - languageEmoji: json['language_emoji'], + displayName: json['language_name'], l2Support: json['l2_support'] != null ? L2SupportEnum.na.fromStorageString(json['l2_support']) : L2SupportEnum.na, @@ -50,9 +35,6 @@ class LanguageModel { toJson() => { 'language_code': langCode, 'language_name': displayName, - 'language_flag': languageFlag, - 'l1': l1, - 'language_emoji': languageEmoji, 'l2_support': l2Support.storageString, }; @@ -63,11 +45,6 @@ class LanguageModel { if (codeOrName.isEmpty) return LanguageKeys.unknownLanguage; if (codeOrName == LanguageKeys.unknownLanguage) return codeOrName; - if (_LanguageLocal.isoLangs.containsKey(codeOrName)) return codeOrName; - - final String code = _LanguageLocal.langCodeFromName(codeOrName); - if (code != LanguageKeys.unknownLanguage) return code; - if (url == null) return LanguageKeys.unknownLanguage; final List split = url.split('/'); @@ -77,672 +54,30 @@ class LanguageModel { //PTODO - add flag for unknown static LanguageModel get unknown => LanguageModel( langCode: LanguageKeys.unknownLanguage, - languageFlag: "", displayName: "Unknown", - l1: false, ); static LanguageModel multiLingual([BuildContext? context]) => LanguageModel( displayName: context != null ? L10n.of(context).multiLingualSpace : "Multilingual Space", - l1: false, langCode: LanguageKeys.multiLanguage, - languageFlag: 'assets/colors.png', - languageEmoji: "🌎", ); String? getDisplayName(BuildContext context) { - switch (langCode) { - case 'ab': - return L10n.of(context).abDisplayName; - case 'aa': - return L10n.of(context).aaDisplayName; - case 'af': - return L10n.of(context).afDisplayName; - case 'ak': - return L10n.of(context).akDisplayName; - case 'sq': - return L10n.of(context).sqDisplayName; - case 'am': - return L10n.of(context).amDisplayName; - case 'ar': - return L10n.of(context).arDisplayName; - case 'an': - return L10n.of(context).anDisplayName; - case 'hy': - return L10n.of(context).hyDisplayName; - case 'as': - return L10n.of(context).asDisplayName; - case 'av': - return L10n.of(context).avDisplayName; - case 'ae': - return L10n.of(context).aeDisplayName; - case 'ay': - return L10n.of(context).ayDisplayName; - case 'az': - return L10n.of(context).azDisplayName; - case 'bm': - return L10n.of(context).bmDisplayName; - case 'ba': - return L10n.of(context).baDisplayName; - case 'eu': - return L10n.of(context).euDisplayName; - case 'be': - return L10n.of(context).beDisplayName; - case 'bn': - return L10n.of(context).bnDisplayName; - case 'bh': - return L10n.of(context).bhDisplayName; - case 'bi': - return L10n.of(context).biDisplayName; - case 'bs': - return L10n.of(context).bsDisplayName; - case 'br': - return L10n.of(context).brDisplayName; - case 'bg': - return L10n.of(context).bgDisplayName; - case 'my': - return L10n.of(context).myDisplayName; - case 'ca': - return L10n.of(context).caDisplayName; - case 'ch': - return L10n.of(context).chDisplayName; - case 'ce': - return L10n.of(context).ceDisplayName; - case 'ny': - return L10n.of(context).nyDisplayName; - case 'zh': - return L10n.of(context).zhDisplayName; - case 'cv': - return L10n.of(context).cvDisplayName; - case 'kw': - return L10n.of(context).kwDisplayName; - case 'co': - return L10n.of(context).coDisplayName; - case 'cr': - return L10n.of(context).crDisplayName; - case 'hr': - return L10n.of(context).hrDisplayName; - case 'cs': - return L10n.of(context).csDisplayName; - case 'da': - return L10n.of(context).daDisplayName; - case 'dv': - return L10n.of(context).dvDisplayName; - case 'nl': - return L10n.of(context).nlDisplayName; - case 'en': - return L10n.of(context).enDisplayName; - case 'eo': - return L10n.of(context).eoDisplayName; - case 'et': - return L10n.of(context).etDisplayName; - case 'ee': - return L10n.of(context).eeDisplayName; - case 'fo': - return L10n.of(context).foDisplayName; - case 'fj': - return L10n.of(context).fjDisplayName; - case 'fi': - return L10n.of(context).fiDisplayName; - case 'fr': - return L10n.of(context).frDisplayName; - case 'ff': - return L10n.of(context).ffDisplayName; - case 'gl': - return L10n.of(context).glDisplayName; - case 'ka': - return L10n.of(context).kaDisplayName; - case 'de': - return L10n.of(context).deDisplayName; - case 'el': - return L10n.of(context).elDisplayName; - case 'gn': - return L10n.of(context).gnDisplayName; - case 'gu': - return L10n.of(context).guDisplayName; - case 'ht': - return L10n.of(context).htDisplayName; - case 'ha': - return L10n.of(context).haDisplayName; - case 'he': - return L10n.of(context).heDisplayName; - case 'hz': - return L10n.of(context).hzDisplayName; - case 'hi': - return L10n.of(context).hiDisplayName; - case 'ho': - return L10n.of(context).hoDisplayName; - case 'hu': - return L10n.of(context).huDisplayName; - case 'ia': - return L10n.of(context).iaDisplayName; - case 'id': - return L10n.of(context).idDisplayName; - case 'ie': - return L10n.of(context).ieDisplayName; - case 'ga': - return L10n.of(context).gaDisplayName; - case 'ig': - return L10n.of(context).igDisplayName; - case 'ik': - return L10n.of(context).ikDisplayName; - case 'io': - return L10n.of(context).ioDisplayName; - case 'is': - return L10n.of(context).isDisplayName; - case 'it': - return L10n.of(context).itDisplayName; - case 'iu': - return L10n.of(context).iuDisplayName; - case 'ja': - return L10n.of(context).jaDisplayName; - case 'jv': - return L10n.of(context).jvDisplayName; - case 'kl': - return L10n.of(context).klDisplayName; - case 'kn': - return L10n.of(context).knDisplayName; - case 'kr': - return L10n.of(context).krDisplayName; - case 'ks': - return L10n.of(context).ksDisplayName; - case 'kk': - return L10n.of(context).kkDisplayName; - case 'km': - return L10n.of(context).kmDisplayName; - case 'ki': - return L10n.of(context).kiDisplayName; - case 'rw': - return L10n.of(context).rwDisplayName; - case 'ky': - return L10n.of(context).kyDisplayName; - case 'kv': - return L10n.of(context).kvDisplayName; - case 'kg': - return L10n.of(context).kgDisplayName; - case 'ko': - return L10n.of(context).koDisplayName; - case 'ku': - return L10n.of(context).kuDisplayName; - case 'kj': - return L10n.of(context).kjDisplayName; - case 'la': - return L10n.of(context).laDisplayName; - case 'lb': - return L10n.of(context).lbDisplayName; - case 'lg': - return L10n.of(context).lgDisplayName; - case 'li': - return L10n.of(context).liDisplayName; - case 'ln': - return L10n.of(context).lnDisplayName; - case 'lo': - return L10n.of(context).loDisplayName; - case 'lt': - return L10n.of(context).ltDisplayName; - case 'lu': - return L10n.of(context).luDisplayName; - case 'lv': - return L10n.of(context).lvDisplayName; - case 'gv': - return L10n.of(context).gvDisplayName; - case 'mk': - return L10n.of(context).mkDisplayName; - case 'mg': - return L10n.of(context).mgDisplayName; - case 'ms': - return L10n.of(context).msDisplayName; - case 'ml': - return L10n.of(context).mlDisplayName; - case 'mt': - return L10n.of(context).mtDisplayName; - case 'mi': - return L10n.of(context).miDisplayName; - case 'mr': - return L10n.of(context).mrDisplayName; - case 'mh': - return L10n.of(context).mhDisplayName; - case 'mn': - return L10n.of(context).mnDisplayName; - case 'na': - return L10n.of(context).naDisplayName; - case 'nv': - return L10n.of(context).nvDisplayName; - case 'nb': - return L10n.of(context).nbDisplayName; - case 'nd': - return L10n.of(context).ndDisplayName; - case 'ne': - return L10n.of(context).neDisplayName; - case 'ng': - return L10n.of(context).ngDisplayName; - case 'nn': - return L10n.of(context).nnDisplayName; - case 'no': - return L10n.of(context).noDisplayName; - case 'ii': - return L10n.of(context).iiDisplayName; - case 'nr': - return L10n.of(context).nrDisplayName; - case 'oc': - return L10n.of(context).ocDisplayName; - case 'oj': - return L10n.of(context).ojDisplayName; - case 'cu': - return L10n.of(context).cuDisplayName; - case 'om': - return L10n.of(context).omDisplayName; - case 'or': - return L10n.of(context).orDisplayName; - case 'os': - return L10n.of(context).osDisplayName; - case 'pa': - return L10n.of(context).paDisplayName; - case 'pi': - return L10n.of(context).piDisplayName; - case 'fa': - return L10n.of(context).faDisplayName; - case 'pl': - return L10n.of(context).plDisplayName; - case 'ps': - return L10n.of(context).psDisplayName; - case 'pt': - return L10n.of(context).ptDisplayName; - case 'qu': - return L10n.of(context).quDisplayName; - case 'rm': - return L10n.of(context).rmDisplayName; - case 'rn': - return L10n.of(context).rnDisplayName; - case 'ro': - return L10n.of(context).roDisplayName; - case 'ru': - return L10n.of(context).ruDisplayName; - case 'sa': - return L10n.of(context).saDisplayName; - case 'sc': - return L10n.of(context).scDisplayName; - case 'sd': - return L10n.of(context).sdDisplayName; - case 'se': - return L10n.of(context).seDisplayName; - case 'sm': - return L10n.of(context).smDisplayName; - case 'sg': - return L10n.of(context).sgDisplayName; - case 'sr': - return L10n.of(context).srDisplayName; - case 'gd': - return L10n.of(context).gdDisplayName; - case 'sn': - return L10n.of(context).snDisplayName; - case 'si': - return L10n.of(context).siDisplayName; - case 'sk': - return L10n.of(context).skDisplayName; - case 'sl': - return L10n.of(context).slDisplayName; - case 'so': - return L10n.of(context).soDisplayName; - case 'st': - return L10n.of(context).stDisplayName; - case 'es': - return L10n.of(context).esDisplayName; - case 'su': - return L10n.of(context).suDisplayName; - case 'sw': - return L10n.of(context).swDisplayName; - case 'ss': - return L10n.of(context).ssDisplayName; - case 'sv': - return L10n.of(context).svDisplayName; - case 'ta': - return L10n.of(context).taDisplayName; - case 'te': - return L10n.of(context).teDisplayName; - case 'tg': - return L10n.of(context).tgDisplayName; - case 'th': - return L10n.of(context).thDisplayName; - case 'ti': - return L10n.of(context).tiDisplayName; - case 'bo': - return L10n.of(context).boDisplayName; - case 'tk': - return L10n.of(context).tkDisplayName; - case 'tl': - return L10n.of(context).tlDisplayName; - case 'tn': - return L10n.of(context).tnDisplayName; - case 'to': - return L10n.of(context).toDisplayName; - case 'tr': - return L10n.of(context).trDisplayName; - case 'ts': - return L10n.of(context).tsDisplayName; - case 'tt': - return L10n.of(context).ttDisplayName; - case 'tw': - return L10n.of(context).twDisplayName; - case 'ty': - return L10n.of(context).tyDisplayName; - case 'ug': - return L10n.of(context).ugDisplayName; - case 'uk': - return L10n.of(context).ukDisplayName; - case 'ur': - return L10n.of(context).urDisplayName; - case 'uz': - return L10n.of(context).uzDisplayName; - case 've': - return L10n.of(context).veDisplayName; - case 'vi': - return L10n.of(context).viDisplayName; - case 'vo': - return L10n.of(context).voDisplayName; - case 'wa': - return L10n.of(context).waDisplayName; - case 'cy': - return L10n.of(context).cyDisplayName; - case 'wo': - return L10n.of(context).woDisplayName; - case 'fy': - return L10n.of(context).fyDisplayName; - case 'xh': - return L10n.of(context).xhDisplayName; - case 'yi': - return L10n.of(context).yiDisplayName; - case 'yo': - return L10n.of(context).yoDisplayName; - case 'za': - return L10n.of(context).zaDisplayName; - case 'unk': - return L10n.of(context).unkDisplayName; - case 'zu': - return L10n.of(context).zuDisplayName; - case 'haw': - return L10n.of(context).hawDisplayName; - case 'hmn': - return L10n.of(context).hmnDisplayName; - case 'multi': - return L10n.of(context).multiDisplayName; - case 'ceb': - return L10n.of(context).cebDisplayName; - case 'dz': - return L10n.of(context).dzDisplayName; - case 'iw': - return L10n.of(context).iwDisplayName; - case 'jw': - return L10n.of(context).jwDisplayName; - case 'mo': - return L10n.of(context).moDisplayName; - case 'sh': - return L10n.of(context).shDisplayName; - } - debugger(when: kDebugMode); - ErrorHandler.logError( - m: "No Display name found", - s: StackTrace.current, - data: { - "langCode": langCode, - }, - ); - return null; - } -} - -class _LanguageLocal { - static const isoLangs = { - "ab": {"name": "Abkhaz", "nativeName": "аҧсуа"}, - "aa": {"name": "Afar", "nativeName": "Afaraf"}, - "af": {"name": "Afrikaans", "nativeName": "Afrikaans"}, - "ak": {"name": "Akan", "nativeName": "Akan"}, - "sq": {"name": "Albanian", "nativeName": "Shqip"}, - "am": {"name": "Amharic", "nativeName": "አማርኛ"}, - "ar": {"name": "Arabic", "nativeName": "العربية"}, - "an": {"name": "Aragonese", "nativeName": "Aragonés"}, - "hy": {"name": "Armenian", "nativeName": "Հայերեն"}, - "as": {"name": "Assamese", "nativeName": "অসমীয়া"}, - "av": {"name": "Avaric", "nativeName": "авар мацӀ, магӀарул мацӀ"}, - "ae": {"name": "Avestan", "nativeName": "avesta"}, - "ay": {"name": "Aymara", "nativeName": "aymar aru"}, - "az": {"name": "Azerbaijani", "nativeName": "azərbaycan dili"}, - "bm": {"name": "Bambara", "nativeName": "bamanankan"}, - "ba": {"name": "Bashkir", "nativeName": "башҡорт теле"}, - "eu": {"name": "Basque", "nativeName": "euskara, euskera"}, - "be": {"name": "Belarusian", "nativeName": "Беларуская"}, - "bn": {"name": "Bengali", "nativeName": "বাংলা"}, - "bh": {"name": "Bihari", "nativeName": "भोजपुरी"}, - "bi": {"name": "Bislama", "nativeName": "Bislama"}, - "bs": {"name": "Bosnian", "nativeName": "bosanski jezik"}, - "br": {"name": "Breton", "nativeName": "brezhoneg"}, - "bg": {"name": "Bulgarian", "nativeName": "български език"}, - "my": {"name": "Burmese", "nativeName": "ဗမာစာ"}, - "ca": {"name": "Catalan, Valencian", "nativeName": "Català"}, - "ch": {"name": "Chamorro", "nativeName": "Chamoru"}, - "ce": {"name": "Chechen", "nativeName": "нохчийн мотт"}, - "ny": { - "name": "Chichewa, Chewa, Nyanja", - "nativeName": "chiCheŵa, chinyanja", - }, - "zh": {"name": "Chinese", "nativeName": "中文 (Zhōngwén), 汉语, 漢語"}, - "cv": {"name": "Chuvash", "nativeName": "чӑваш чӗлхи"}, - "kw": {"name": "Cornish", "nativeName": "Kernewek"}, - "co": {"name": "Corsican", "nativeName": "corsu, lingua corsa"}, - "cr": {"name": "Cree", "nativeName": "ᓀᐦᐃᔭᐍᐏᐣ"}, - "hr": {"name": "Croatian", "nativeName": "hrvatski"}, - "cs": {"name": "Czech", "nativeName": "česky, čeština"}, - "da": {"name": "Danish", "nativeName": "dansk"}, - "dv": {"name": "Divehi; Dhivehi; Maldivian;", "nativeName": "ދިވެހި"}, - "nl": {"name": "Dutch", "nativeName": "Nederlands, Vlaams"}, - "en": {"name": "English", "nativeName": "English"}, - "eo": {"name": "Esperanto", "nativeName": "Esperanto"}, - "et": {"name": "Estonian", "nativeName": "eesti, eesti keel"}, - "ee": {"name": "Ewe", "nativeName": "Evegbe"}, - "fo": {"name": "Faroese", "nativeName": "føroyskt"}, - "fj": {"name": "Fijian", "nativeName": "vosa Vakaviti"}, - "fi": {"name": "Finnish", "nativeName": "suomi, suomen kieli"}, - "fr": {"name": "French", "nativeName": "français, langue française"}, - "ff": { - "name": "Fula; Fulah; Pulaar; Pular", - "nativeName": "Fulfulde, Pulaar, Pular", - }, - "gl": {"name": "Galician", "nativeName": "Galego"}, - "ka": {"name": "Georgian", "nativeName": "ქართული"}, - "de": {"name": "German", "nativeName": "Deutsch"}, - "el": {"name": "Greek, Modern", "nativeName": "Ελληνικά"}, - "gn": {"name": "Guaraní", "nativeName": "Avañeẽ"}, - "gu": {"name": "Gujarati", "nativeName": "ગુજરાતી"}, - "ht": {"name": "Haitian, Haitian Creole", "nativeName": "Kreyòl ayisyen"}, - "ha": {"name": "Hausa", "nativeName": "Hausa, هَوُسَ"}, - "he": {"name": "Hebrew (modern)", "nativeName": "עברית"}, - "hz": {"name": "Herero", "nativeName": "Otjiherero"}, - "hi": {"name": "Hindi", "nativeName": "हिन्दी, हिंदी"}, - "ho": {"name": "Hiri Motu", "nativeName": "Hiri Motu"}, - "hu": {"name": "Hungarian", "nativeName": "Magyar"}, - "ia": {"name": "Interlingua", "nativeName": "Interlingua"}, - "id": {"name": "Indonesian", "nativeName": "Bahasa Indonesia"}, - "ie": { - "name": "Interlingue", - "nativeName": "Originally called Occidental; then Interlingue after WWII", - }, - "ga": {"name": "Irish", "nativeName": "Gaeilge"}, - "ig": {"name": "Igbo", "nativeName": "Asụsụ Igbo"}, - "ik": {"name": "Inupiaq", "nativeName": "Iñupiaq, Iñupiatun"}, - "io": {"name": "Ido", "nativeName": "Ido"}, - "is": {"name": "Icelandic", "nativeName": "Íslenska"}, - "it": {"name": "Italian", "nativeName": "Italiano"}, - "iu": {"name": "Inuktitut", "nativeName": "ᐃᓄᒃᑎᑐᑦ"}, - "ja": {"name": "Japanese", "nativeName": "日本語 (にほんご/にっぽんご)"}, - "jv": {"name": "Javanese", "nativeName": "basa Jawa"}, - "kl": { - "name": "Kalaallisut, Greenlandic", - "nativeName": "kalaallisut, kalaallit oqaasii", - }, - "kn": {"name": "Kannada", "nativeName": "ಕನ್ನಡ"}, - "kr": {"name": "Kanuri", "nativeName": "Kanuri"}, - "ks": {"name": "Kashmiri", "nativeName": "कश्मीरी, كشميري"}, - "kk": {"name": "Kazakh", "nativeName": "Қазақ тілі"}, - "km": {"name": "Khmer", "nativeName": "ភាសាខ្មែរ"}, - "ki": {"name": "Kikuyu, Gikuyu", "nativeName": "Gĩkũyũ"}, - "rw": {"name": "Kinyarwanda", "nativeName": "Ikinyarwanda"}, - "ky": {"name": "Kirghiz, Kyrgyz", "nativeName": "кыргыз тили"}, - "kv": {"name": "Komi", "nativeName": "коми кыв"}, - "kg": {"name": "Kongo", "nativeName": "KiKongo"}, - "ko": {"name": "Korean", "nativeName": "한국어 (韓國語), 조선말 (朝鮮語)"}, - "ku": {"name": "Kurdish", "nativeName": "Kurdî, كوردی"}, - "kj": {"name": "Kwanyama, Kuanyama", "nativeName": "Kuanyama"}, - "la": {"name": "Latin", "nativeName": "latine, lingua latina"}, - "lb": { - "name": "Luxembourgish, Letzeburgesch", - "nativeName": "Lëtzebuergesch", - }, - "lg": {"name": "Luganda", "nativeName": "Luganda"}, - "li": { - "name": "Limburgish, Limburgan, Limburger", - "nativeName": "Limburgs", - }, - "ln": {"name": "Lingala", "nativeName": "Lingála"}, - "lo": {"name": "Lao", "nativeName": "ພາສາລາວ"}, - "lt": {"name": "Lithuanian", "nativeName": "lietuvių kalba"}, - "lu": {"name": "Luba-Katanga", "nativeName": ""}, - "lv": {"name": "Latvian", "nativeName": "latviešu valoda"}, - "gv": {"name": "Manx", "nativeName": "Gaelg, Gailck"}, - "mk": {"name": "Macedonian", "nativeName": "македонски јазик"}, - "mg": {"name": "Malagasy", "nativeName": "Malagasy fiteny"}, - "ms": {"name": "Malay", "nativeName": "bahasa Melayu, بهاس ملايو"}, - "ml": {"name": "Malayalam", "nativeName": "മലയാളം"}, - "mt": {"name": "Maltese", "nativeName": "Malti"}, - "mi": {"name": "Māori", "nativeName": "te reo Māori"}, - "mr": {"name": "Marathi (Marāṭhī)", "nativeName": "मराठी"}, - "mh": {"name": "Marshallese", "nativeName": "Kajin M̧ajeļ"}, - "mn": {"name": "Mongolian", "nativeName": "монгол"}, - "na": {"name": "Nauru", "nativeName": "Ekakairũ Naoero"}, - "nv": {"name": "Navajo, Navaho", "nativeName": "Diné bizaad, Dinék'ehǰí"}, - "nb": {"name": "Norwegian Bokmål", "nativeName": "Norsk bokmål"}, - "nd": {"name": "North Ndebele", "nativeName": "isiNdebele"}, - "ne": {"name": "Nepali", "nativeName": "नेपाली"}, - "ng": {"name": "Ndonga", "nativeName": "Owambo"}, - "nn": {"name": "Norwegian Nynorsk", "nativeName": "Norsk nynorsk"}, - "no": {"name": "Norwegian", "nativeName": "Norsk"}, - "ii": {"name": "Nuosu", "nativeName": "ꆈꌠ꒿ Nuosuhxop"}, - "nr": {"name": "South Ndebele", "nativeName": "isiNdebele"}, - "oc": {"name": "Occitan", "nativeName": "Occitan"}, - "oj": {"name": "Ojibwe, Ojibwa", "nativeName": "ᐊᓂᔑᓈᐯᒧᐎᓐ"}, - "cu": { - "name": - "Old Church Slavonic, Church Slavic, Church Slavonic, Old Bulgarian, Old Slavonic", - "nativeName": "ѩзыкъ словѣньскъ", - }, - "om": {"name": "Oromo", "nativeName": "Afaan Oromoo"}, - "or": {"name": "Oriya", "nativeName": "ଓଡ଼ିଆ"}, - "os": {"name": "Ossetian, Ossetic", "nativeName": "ирон æвзаг"}, - "pa": {"name": "Panjabi, Punjabi", "nativeName": "ਪੰਜਾਬੀ, پنجابی"}, - "pi": {"name": "Pāli", "nativeName": "पाऴि"}, - "fa": {"name": "Persian", "nativeName": "فارسی"}, - "pl": {"name": "Polish", "nativeName": "polski"}, - "ps": {"name": "Pashto, Pushto", "nativeName": "پښتو"}, - "pt": {"name": "Portuguese", "nativeName": "Português"}, - "qu": {"name": "Quechua", "nativeName": "Runa Simi, Kichwa"}, - "rm": {"name": "Romansh", "nativeName": "rumantsch grischun"}, - "rn": {"name": "Kirundi", "nativeName": "kiRundi"}, - "ro": {"name": "Romanian, Moldavian, Moldovan", "nativeName": "română"}, - "ru": {"name": "Russian", "nativeName": "русский язык"}, - "sa": {"name": "Sanskrit (Saṁskṛta)", "nativeName": "संस्कृतम्"}, - "sc": {"name": "Sardinian", "nativeName": "sardu"}, - "sd": {"name": "Sindhi", "nativeName": "सिन्धी, سنڌي، سندھی"}, - "se": {"name": "Northern Sami", "nativeName": "Davvisámegiella"}, - "sm": {"name": "Samoan", "nativeName": "gagana faa Samoa"}, - "sg": {"name": "Sango", "nativeName": "yângâ tî sängö"}, - "sr": {"name": "Serbian", "nativeName": "српски језик"}, - "gd": {"name": "Scottish Gaelic, Gaelic", "nativeName": "Gàidhlig"}, - "sn": {"name": "Shona", "nativeName": "chiShona"}, - "si": {"name": "Sinhala, Sinhalese", "nativeName": "සිංහල"}, - "sk": {"name": "Slovak", "nativeName": "Slovenčina"}, - "sl": {"name": "Slovene", "nativeName": "Slovenščina"}, - "so": {"name": "Somali", "nativeName": "Soomaaliga, af Soomaali"}, - "st": {"name": "Southern Sotho", "nativeName": "Sesotho"}, - "es": {"name": "Spanish, Castilian", "nativeName": "Español, Castellano"}, - "su": {"name": "Sundanese", "nativeName": "Basa Sunda"}, - "sw": {"name": "Swahili", "nativeName": "Kiswahili"}, - "ss": {"name": "Swati", "nativeName": "SiSwati"}, - "sv": {"name": "Swedish", "nativeName": "svenska"}, - "ta": {"name": "Tamil", "nativeName": "தமிழ்"}, - "te": {"name": "Telugu", "nativeName": "తెలుగు"}, - "tg": {"name": "Tajik", "nativeName": "тоҷикӣ, toğikī, تاجیکی"}, - "th": {"name": "Thai", "nativeName": "ไทย"}, - "ti": {"name": "Tigrinya", "nativeName": "ትግርኛ"}, - "bo": { - "name": "Tibetan Standard, Tibetan, Central", - "nativeName": "བོད་ཡིག", - }, - "tk": {"name": "Turkmen", "nativeName": "Türkmen, Түркмен"}, - "tl": {"name": "Tagalog", "nativeName": "Wikang Tagalog, ᜏᜒᜃᜅ᜔ ᜆᜄᜎᜓᜄ᜔"}, - "tn": {"name": "Tswana", "nativeName": "Setswana"}, - "to": {"name": "Tonga (Tonga Islands)", "nativeName": "faka Tonga"}, - "tr": {"name": "Turkish", "nativeName": "Türkçe"}, - "ts": {"name": "Tsonga", "nativeName": "Xitsonga"}, - "tt": {"name": "Tatar", "nativeName": "татарча, tatarça, تاتارچا"}, - "tw": {"name": "Twi", "nativeName": "Twi"}, - "ty": {"name": "Tahitian", "nativeName": "Reo Tahiti"}, - "ug": {"name": "Uighur, Uyghur", "nativeName": "Uyƣurqə, ئۇيغۇرچە"}, - "uk": {"name": "Ukrainian", "nativeName": "українська"}, - "ur": {"name": "Urdu", "nativeName": "اردو"}, - "uz": {"name": "Uzbek", "nativeName": "zbek, Ўзбек, أۇزبېك"}, - "ve": {"name": "Venda", "nativeName": "Tshivenḓa"}, - "vi": {"name": "Vietnamese", "nativeName": "Tiếng Việt"}, - "vo": {"name": "Volapük", "nativeName": "Volapük"}, - "wa": {"name": "Walloon", "nativeName": "Walon"}, - "cy": {"name": "Welsh", "nativeName": "Cymraeg"}, - "wo": {"name": "Wolof", "nativeName": "Wollof"}, - "fy": {"name": "Western Frisian", "nativeName": "Frysk"}, - "xh": {"name": "Xhosa", "nativeName": "isiXhosa"}, - "yi": {"name": "Yiddish", "nativeName": "ייִדיש"}, - "yo": {"name": "Yoruba", "nativeName": "Yorùbá"}, - "za": {"name": "Zhuang, Chuang", "nativeName": "Saw cueŋƅ, Saw cuengh"}, - "unk": {"name": "Unknown", "nativeName": "Saw cueŋƅ, Saw cuengh"}, - "zu": {"name": "Zulu", "nativeName": "Zulu"}, - "haw": {"name": "Hawaiian", "nativeName": "Hawaiian"}, - "hmn": {"name": "Hmong", "nativeName": "Hmong"}, - 'multi': {"name": "Multi", "nativeName": "Multi"}, - "ceb": {"name": "Cebuano", "nativeName": "Cebuano"}, - "dz": {"name": "Dzongkha", "nativeName": "Dzongkha"}, - "iw": {"name": "Hebrew", "nativeName": "Hebrew"}, - "jw": {"name": "Javanese", "nativeName": "Javanese"}, - "mo": {"name": "Moldavian", "nativeName": "Moldavian"}, - "sh": {"name": "Serbo-Croatian", "nativeName": "Serbo-Croatian"}, - }; - - static String getDisplayName(String key, [native = false]) { - final Map? item = isoLangs[key]; - if (item == null) { - // debugger(when: kDebugMode); - // ErrorHandler.logError(m: "Bad language key $key", s: StackTrace.current); - } - if (item == null || - (native && !item.containsKey("nativeName") || - (!native && !item.containsKey("name")))) { - return key; - } - - return (native ? item["nativeName"]! : item["name"]!).split(",")[0]; - } - - static String langCodeFromName(String? name) { - if (name == null) return LanguageKeys.unknownLanguage; - if (isoLangs.containsKey(name)) return name; - - final String searchName = name.toLowerCase().split(" ")[0]; - for (final entry in isoLangs.entries) { - if (entry.value.containsKey("name") && - entry.value["name"]!.toLowerCase().contains(searchName)) { - return entry.key; - } - } - // debugger(when: kDebugMode); - // ErrorHandler.logError(m: "Bad language name $name", s: StackTrace.current); - return LanguageKeys.unknownLanguage; + return displayName; } + + String get langCodeShort => langCode.split('-').first; + + @override + bool operator ==(Object other) { + if (other is LanguageModel) { + return langCode == other.langCode; + } + return false; + } + + @override + int get hashCode => langCode.hashCode; } diff --git a/lib/pangea/learning_settings/pages/settings_learning.dart b/lib/pangea/learning_settings/pages/settings_learning.dart index be99b28a7..d032c4b25 100644 --- a/lib/pangea/learning_settings/pages/settings_learning.dart +++ b/lib/pangea/learning_settings/pages/settings_learning.dart @@ -131,8 +131,8 @@ class SettingsLearningController extends State { LanguageModel? get selectedTargetLanguage { return userL2 ?? ((selectedSourceLanguage?.langCode != 'en') - ? PangeaLanguage.byLangCode('en')! - : PangeaLanguage.byLangCode('es')!); + ? PangeaLanguage.byLangCode('en') + : PangeaLanguage.byLangCode('es')); } LanguageModel? get userL1 => _profile.userSettings.sourceLanguage != null diff --git a/lib/pangea/learning_settings/pages/settings_learning_view.dart b/lib/pangea/learning_settings/pages/settings_learning_view.dart index afc2f660a..5aeb99f1a 100644 --- a/lib/pangea/learning_settings/pages/settings_learning_view.dart +++ b/lib/pangea/learning_settings/pages/settings_learning_view.dart @@ -103,104 +103,89 @@ class SettingsLearningView extends StatelessWidget { initialLevel: controller.cefrLevel, onChanged: controller.setCefrLevel, ), - const Divider(height: 1), - Column( - children: [ - ListTile( - title: Text( - L10n.of(context) - .toggleToolSettingsDescription, - ), - ), - for (final toolSetting in ToolSetting.values - .where((tool) => tool.isAvailableSetting)) - Column( - children: [ - ProfileSettingsSwitchListTile.adaptive( - defaultValue: controller - .getToolSetting(toolSetting), - title: toolSetting.toolName(context), - subtitle: toolSetting == - ToolSetting.enableTTS && - !controller.tts - .isLanguageFullySupported - ? null - : toolSetting - .toolDescription(context), - onChange: (bool value) => - controller.updateToolSetting( - toolSetting, - value, - ), - enabled: toolSetting == - ToolSetting.enableTTS + for (final toolSetting in ToolSetting.values + .where((tool) => tool.isAvailableSetting)) + Column( + children: [ + ProfileSettingsSwitchListTile.adaptive( + defaultValue: controller + .getToolSetting(toolSetting), + title: toolSetting.toolName(context), + subtitle: toolSetting == + ToolSetting.enableTTS && + !controller + .tts.isLanguageFullySupported + ? null + : toolSetting + .toolDescription(context), + onChange: (bool value) => + controller.updateToolSetting( + toolSetting, + value, + ), + enabled: + toolSetting == ToolSetting.enableTTS ? controller .tts.isLanguageFullySupported : true, - ), - if (toolSetting == - ToolSetting.enableTTS && - !controller - .tts.isLanguageFullySupported) - ListTile( - trailing: const Padding( - padding: EdgeInsets.symmetric( - horizontal: 16.0, - ), - child: Icon(Icons.info_outlined), - ), - subtitle: RichText( - text: TextSpan( - text: L10n.of(context) - .couldNotFindTTS, - style: - DefaultTextStyle.of(context) - .style, - children: [ - if (PlatformInfos.isWindows || - PlatformInfos.isAndroid) - TextSpan( - text: L10n.of(context) - .ttsInstructionsHyperlink, - style: const TextStyle( - color: Colors.blue, - fontWeight: - FontWeight.bold, - decoration: - TextDecoration - .underline, - ), - recognizer: - TapGestureRecognizer() - ..onTap = () { - launchUrlString( - PlatformInfos - .isWindows - ? AppConfig - .windowsTTSDownloadInstructions - : AppConfig - .androidTTSDownloadInstructions, - ); - }, - ), - ], - ), - ), + ), + if (toolSetting == ToolSetting.enableTTS && + !controller + .tts.isLanguageFullySupported) + ListTile( + trailing: const Padding( + padding: EdgeInsets.symmetric( + horizontal: 16.0, ), - ], - ), - SwitchListTile.adaptive( - value: controller.publicProfile, - onChanged: controller.setPublicProfile, - title: Text( - L10n.of(context).publicProfileTitle, - ), - subtitle: Text( - L10n.of(context).publicProfileDesc, - ), - activeColor: AppConfig.activeToggleColor, - ), - ], + child: Icon(Icons.info_outlined), + ), + subtitle: RichText( + text: TextSpan( + text: L10n.of(context) + .couldNotFindTTS, + style: DefaultTextStyle.of(context) + .style, + children: [ + if (PlatformInfos.isWindows || + PlatformInfos.isAndroid) + TextSpan( + text: L10n.of(context) + .ttsInstructionsHyperlink, + style: const TextStyle( + color: Colors.blue, + fontWeight: FontWeight.bold, + decoration: TextDecoration + .underline, + ), + recognizer: + TapGestureRecognizer() + ..onTap = () { + launchUrlString( + PlatformInfos + .isWindows + ? AppConfig + .windowsTTSDownloadInstructions + : AppConfig + .androidTTSDownloadInstructions, + ); + }, + ), + ], + ), + ), + ), + ], + ), + SwitchListTile.adaptive( + value: controller.publicProfile, + onChanged: controller.setPublicProfile, + title: Text( + L10n.of(context).publicProfileTitle, + ), + subtitle: Text( + L10n.of(context).publicProfileDesc, + ), + activeColor: AppConfig.activeToggleColor, ), ], ), @@ -213,7 +198,7 @@ class SettingsLearningView extends StatelessWidget { width: double.infinity, child: ElevatedButton( onPressed: controller.submit, - child: Text(L10n.of(context).submit), + child: Text(L10n.of(context).saveChanges), ), ), ), diff --git a/lib/pangea/learning_settings/utils/language_list_util.dart b/lib/pangea/learning_settings/utils/language_list_util.dart index 319b64eaa..c24929cf4 100644 --- a/lib/pangea/learning_settings/utils/language_list_util.dart +++ b/lib/pangea/learning_settings/utils/language_list_util.dart @@ -21,25 +21,25 @@ class PangeaLanguage { List get targetOptions => _langList.where((element) => element.l2).toList(); - List get baseOptions => - _langList.where((element) => element.l1).toList(); + List get baseOptions => _langList.toList(); static Future initialize() async { try { - _langList = await _getCachedFlags(); + _langList = await _getCachedLanguages(); if (await _shouldFetch || _langList.isEmpty || _langList.every((lang) => !lang.l2)) { _langList = await LanguageRepo.fetchLanguages(); - await _saveFlags(_langList); + await _saveLanguages(_langList); await saveLastFetchDate(); } _langList.removeWhere( - (element) => - LanguageModel.codeFromNameOrCode(element.langCode) == - LanguageKeys.unknownLanguage, + (element) => element.langCode == LanguageKeys.unknownLanguage, ); + // remove any duplicates + _langList = _langList.toSet().toList(); + _langList.sort((a, b) => a.displayName.compareTo(b.displayName)); _langList.insert(0, LanguageModel.multiLingual()); } catch (err, stack) { @@ -77,27 +77,27 @@ class PangeaLanguage { return (now - lastFetched) >= fetchIntervalInMilliseconds ? true : false; } - static Future _saveFlags(List langFlags) async { - final Map flagMap = { - PrefKey.flags: langFlags.map((e) => e.toJson()).toList(), + static Future _saveLanguages(List languages) async { + final Map languagesMaps = { + PrefKey.languagesKey: languages.map((e) => e.toJson()).toList(), }; - await MyShared.saveJson(PrefKey.flags, flagMap); + await MyShared.saveJson(PrefKey.languagesKey, languagesMaps); } - static Future> _getCachedFlags() async { - final Map? flagsMap = - await MyShared.readJson(PrefKey.flags); - if (flagsMap == null) { + static Future> _getCachedLanguages() async { + final Map? languagesMap = + await MyShared.readJson(PrefKey.languagesKey); + if (languagesMap == null) { return []; } - final List flags = []; - final List mapList = flagsMap[PrefKey.flags] as List; + final List languages = []; + final List mapList = languagesMap[PrefKey.languagesKey] as List; for (final element in mapList) { - flags.add(LanguageModel.fromJson(element)); + languages.add(LanguageModel.fromJson(element)); } - return flags; + return languages; } static LanguageModel? byLangCode(String langCode) { diff --git a/lib/pangea/learning_settings/widgets/p_language_dropdown.dart b/lib/pangea/learning_settings/widgets/p_language_dropdown.dart index 747a509d8..686a857ec 100644 --- a/lib/pangea/learning_settings/widgets/p_language_dropdown.dart +++ b/lib/pangea/learning_settings/widgets/p_language_dropdown.dart @@ -48,7 +48,11 @@ class PLanguageDropdownState extends State { Widget build(BuildContext context) { final List sortedLanguages = widget.languages; final String systemLang = Localizations.localeOf(context).languageCode; - final List languagePriority = [systemLang, 'en', 'es']; + + // if there is no initial language, the system language should be the first in the list + // otherwise, display in alphabetical order + final List languagePriority = + widget.initialLanguage == null ? [systemLang] : []; int sortLanguages(LanguageModel a, LanguageModel b) { final String aLang = a.langCode; diff --git a/lib/pangea/morphs/morph_repo.dart b/lib/pangea/morphs/morph_repo.dart index cbfa812a0..7bfc3b607 100644 --- a/lib/pangea/morphs/morph_repo.dart +++ b/lib/pangea/morphs/morph_repo.dart @@ -9,6 +9,7 @@ import 'package:http/http.dart'; import 'package:fluffychat/pangea/common/config/environment.dart'; import 'package:fluffychat/pangea/common/network/urls.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; +import 'package:fluffychat/pangea/learning_settings/models/language_model.dart'; import 'package:fluffychat/pangea/morphs/default_morph_mapping.dart'; import 'package:fluffychat/pangea/morphs/morph_models.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -76,34 +77,36 @@ class MorphsRepo { /// if the morphs are not yet fetched. we'll see if this works well /// if not, we can make it async and update uses of this function /// to be async as well - static Future get([String? languageCode]) async { - languageCode ??= - MatrixState.pangeaController.languageController.userL2?.langCode; + static Future get([LanguageModel? language]) async { + language ??= MatrixState.pangeaController.languageController.userL2; - if (languageCode == null) { + if (language == null) { return defaultMorphMapping; } + // does not differ based on locale + final langCodeShort = language.langCodeShort; + // check if we have a cached morphs for this language code - final cachedJson = _morphsStorage.read(languageCode); + final cachedJson = _morphsStorage.read(langCodeShort); if (cachedJson != null) { return MorphsRepo.fromJson(cachedJson); } // check if we have a cached call for this language code - final _APICallCacheItem? cachedCall = shortTermCache[languageCode]; + final _APICallCacheItem? cachedCall = shortTermCache[langCodeShort]; if (cachedCall != null) { if (DateTime.now().difference(cachedCall.time).inMinutes < _cacheDurationMinutes) { return cachedCall.future; } else { - shortTermCache.remove(languageCode); + shortTermCache.remove(langCodeShort); } } // fetch the morphs but don't wait for it - final future = _fetch(languageCode); - shortTermCache[languageCode] = _APICallCacheItem(DateTime.now(), future); + final future = _fetch(langCodeShort); + shortTermCache[langCodeShort] = _APICallCacheItem(DateTime.now(), future); return future; } } diff --git a/lib/pangea/toolbar/models/speech_to_text_models.dart b/lib/pangea/toolbar/models/speech_to_text_models.dart index fb424c532..d43f45643 100644 --- a/lib/pangea/toolbar/models/speech_to_text_models.dart +++ b/lib/pangea/toolbar/models/speech_to_text_models.dart @@ -92,13 +92,15 @@ class STTToken { int get length => token.text.length; Color color(BuildContext context) { - if (confidence == null) { - return Theme.of(context).colorScheme.onSurface; - } - if (confidence! > thresholdForGreen) { - return AppConfig.success; - } - return AppConfig.warning; + // turning off the color coding for now + // whisper doesn't include word-level confidence + // if (confidence == null) { + return Theme.of(context).colorScheme.onSurface; + // } + // if (confidence! > thresholdForGreen) { + // return AppConfig.success; + // } + // return AppConfig.warning; } factory STTToken.fromJson(Map json) { diff --git a/lib/pangea/toolbar/widgets/message_speech_to_text_card.dart b/lib/pangea/toolbar/widgets/message_speech_to_text_card.dart index 538928f6c..90fc722fe 100644 --- a/lib/pangea/toolbar/widgets/message_speech_to_text_card.dart +++ b/lib/pangea/toolbar/widgets/message_speech_to_text_card.dart @@ -1,7 +1,6 @@ import 'dart:developer'; import 'package:flutter/foundation.dart'; -import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; @@ -112,20 +111,20 @@ class MessageSpeechToTextCardState extends State { setColor: false, ), // gesturRecognizer that sets selectedToken on click - recognizer: TapGestureRecognizer() - ..onTap = () { - debugPrint('Token tapped'); - debugPrint(token.toJson().toString()); - if (mounted) { - setState(() { - if (selectedToken == token) { - selectedToken = null; - } else { - selectedToken = token; - } - }); - } - }, + // recognizer: TapGestureRecognizer() + // ..onTap = () { + // debugPrint('Token tapped'); + // debugPrint(token.toJson().toString()); + // if (mounted) { + // setState(() { + // if (selectedToken == token) { + // selectedToken = null; + // } else { + // selectedToken = token; + // } + // }); + // } + // }, ), ); diff --git a/lib/pangea/user/controllers/user_controller.dart b/lib/pangea/user/controllers/user_controller.dart index 17a554c56..970351bce 100644 --- a/lib/pangea/user/controllers/user_controller.dart +++ b/lib/pangea/user/controllers/user_controller.dart @@ -80,12 +80,12 @@ class UserController extends BaseController { Profile Function(Profile) update, { waitForDataInSync = false, }) async { - final prevTargetLang = profile.userSettings.targetLanguage; + final prevTargetLang = _pangeaController.languageController.userL2; final Profile updatedProfile = update(profile); await updatedProfile.saveProfileData(waitForDataInSync: waitForDataInSync); - if (prevTargetLang != updatedProfile.userSettings.targetLanguage) { + if (prevTargetLang != _pangeaController.languageController.userL2) { setState({'prev_target_lang': prevTargetLang}); } }