feat: move language dropdowns into learning settings dialog (#1695)
This commit is contained in:
parent
75a0d1e07b
commit
1e40e1d1a6
3 changed files with 176 additions and 95 deletions
|
|
@ -4,11 +4,14 @@ import 'package:country_picker/country_picker.dart';
|
|||
|
||||
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/enums/language_level_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/models/language_model.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/pages/settings_learning_view.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/utils/language_list_util.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/widgets/p_language_dialog.dart';
|
||||
import 'package:fluffychat/pangea/spaces/models/space_model.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/controllers/tts_controller.dart';
|
||||
import 'package:fluffychat/pangea/user/models/user_model.dart';
|
||||
import 'package:fluffychat/widgets/future_loading_dialog.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class SettingsLearning extends StatefulWidget {
|
||||
|
|
@ -22,6 +25,22 @@ class SettingsLearningController extends State<SettingsLearning> {
|
|||
PangeaController pangeaController = MatrixState.pangeaController;
|
||||
final tts = TtsController();
|
||||
|
||||
LanguageModel? get selectedSourceLanguage {
|
||||
return userL1 ?? pangeaController.languageController.systemLanguage;
|
||||
}
|
||||
|
||||
LanguageModel? get selectedTargetLanguage {
|
||||
return userL2 ??
|
||||
((selectedSourceLanguage?.langCode != 'en')
|
||||
? PangeaLanguage.byLangCode('en')!
|
||||
: PangeaLanguage.byLangCode('es')!);
|
||||
}
|
||||
|
||||
LanguageModel? get userL1 => pangeaController.languageController.userL1;
|
||||
LanguageModel? get userL2 => pangeaController.languageController.userL2;
|
||||
|
||||
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
|
@ -34,6 +53,33 @@ class SettingsLearningController extends State<SettingsLearning> {
|
|||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> setSelectedLanguage({
|
||||
LanguageModel? sourceLanguage,
|
||||
LanguageModel? targetLanguage,
|
||||
}) async {
|
||||
if (targetLanguage == null && sourceLanguage == null) return;
|
||||
if (!formKey.currentState!.validate()) return;
|
||||
|
||||
await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () async {
|
||||
pangeaController.userController.updateProfile(
|
||||
(profile) {
|
||||
if (sourceLanguage != null) {
|
||||
profile.userSettings.sourceLanguage = sourceLanguage.langCode;
|
||||
}
|
||||
if (targetLanguage != null) {
|
||||
profile.userSettings.targetLanguage = targetLanguage.langCode;
|
||||
}
|
||||
return profile;
|
||||
},
|
||||
waitForDataInSync: true,
|
||||
);
|
||||
},
|
||||
);
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
void setPublicProfile(bool isPublic) {
|
||||
pangeaController.userController.updateProfile(
|
||||
(profile) {
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@ import 'package:fluffychat/config/app_config.dart';
|
|||
import 'package:fluffychat/pangea/chat_settings/widgets/language_level_dropdown.dart';
|
||||
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/full_width_dialog.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/models/language_model.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/pages/settings_learning.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/widgets/country_picker_tile.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/widgets/language_tile.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/widgets/p_language_dropdown.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/widgets/p_settings_switch_list_tile.dart';
|
||||
import 'package:fluffychat/pangea/spaces/models/space_model.dart';
|
||||
import 'package:fluffychat/utils/platform_infos.dart';
|
||||
|
|
@ -46,88 +47,126 @@ class SettingsLearningView extends StatelessWidget {
|
|||
iconColor: Theme.of(context).textTheme.bodyLarge!.color,
|
||||
child: MaxWidthBody(
|
||||
withScrolling: true,
|
||||
child: Column(
|
||||
children: [
|
||||
LanguageTile(controller),
|
||||
CountryPickerTile(controller),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16.0, bottom: 24.0),
|
||||
child: LanguageLevelDropdown(
|
||||
initialLevel: controller.cefrLevel,
|
||||
onChanged: controller.setCefrLevel,
|
||||
child: Form(
|
||||
key: controller.formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 8.0),
|
||||
PLanguageDropdown(
|
||||
onChange: (lang) =>
|
||||
controller.setSelectedLanguage(sourceLanguage: lang),
|
||||
initialLanguage: controller.selectedSourceLanguage ??
|
||||
LanguageModel.unknown,
|
||||
languages: MatrixState
|
||||
.pangeaController.pLanguageStore.baseOptions,
|
||||
isL2List: false,
|
||||
decorationText: L10n.of(context).myBaseLanguage,
|
||||
validator: (lang) {
|
||||
if (lang == controller.selectedTargetLanguage) {
|
||||
return L10n.of(context).noIdenticalLanguages;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
),
|
||||
const Divider(height: 1),
|
||||
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
|
||||
? 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),
|
||||
const SizedBox(height: 24.0),
|
||||
PLanguageDropdown(
|
||||
onChange: (lang) =>
|
||||
controller.setSelectedLanguage(targetLanguage: lang),
|
||||
initialLanguage: controller.selectedTargetLanguage,
|
||||
languages: MatrixState
|
||||
.pangeaController.pLanguageStore.targetOptions,
|
||||
isL2List: true,
|
||||
decorationText: L10n.of(context).iWantToLearn,
|
||||
validator: (lang) {
|
||||
if (lang == controller.selectedSourceLanguage) {
|
||||
return L10n.of(context).noIdenticalLanguages;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16.0),
|
||||
CountryPickerTile(controller),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16.0, bottom: 24.0),
|
||||
child: LanguageLevelDropdown(
|
||||
initialLevel: controller.cefrLevel,
|
||||
onChanged: controller.setCefrLevel,
|
||||
),
|
||||
),
|
||||
const Divider(height: 1),
|
||||
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,
|
||||
),
|
||||
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,
|
||||
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,
|
||||
);
|
||||
},
|
||||
),
|
||||
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,
|
||||
),
|
||||
SwitchListTile.adaptive(
|
||||
value: controller.publicProfile,
|
||||
onChanged: controller.setPublicProfile,
|
||||
title: Text(L10n.of(context).publicProfileTitle),
|
||||
subtitle: Text(L10n.of(context).publicProfileDesc),
|
||||
activeColor: AppConfig.activeToggleColor,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -2,14 +2,12 @@
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/enums/l2_support_enum.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/models/language_model.dart';
|
||||
import 'flag.dart';
|
||||
|
||||
class PLanguageDropdown extends StatefulWidget {
|
||||
class PLanguageDropdown extends StatelessWidget {
|
||||
final List<LanguageModel> languages;
|
||||
final LanguageModel? initialLanguage;
|
||||
final Function(LanguageModel) onChange;
|
||||
|
|
@ -17,6 +15,7 @@ class PLanguageDropdown extends StatefulWidget {
|
|||
final bool isL2List;
|
||||
final String decorationText;
|
||||
final String? error;
|
||||
final String? Function(LanguageModel?)? validator;
|
||||
|
||||
const PLanguageDropdown({
|
||||
super.key,
|
||||
|
|
@ -27,16 +26,12 @@ class PLanguageDropdown extends StatefulWidget {
|
|||
required this.decorationText,
|
||||
this.isL2List = false,
|
||||
this.error,
|
||||
this.validator,
|
||||
});
|
||||
|
||||
@override
|
||||
State<PLanguageDropdown> createState() => _PLanguageDropdownState();
|
||||
}
|
||||
|
||||
class _PLanguageDropdownState extends State<PLanguageDropdown> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<LanguageModel> sortedLanguages = widget.languages;
|
||||
final List<LanguageModel> sortedLanguages = languages;
|
||||
final String systemLang = Localizations.localeOf(context).languageCode;
|
||||
final List<String> languagePriority = [systemLang, 'en', 'es'];
|
||||
|
||||
|
|
@ -65,16 +60,16 @@ class _PLanguageDropdownState extends State<PLanguageDropdown> {
|
|||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
DropdownButtonFormField2<LanguageModel>(
|
||||
decoration: InputDecoration(labelText: widget.decorationText),
|
||||
DropdownButtonFormField<LanguageModel>(
|
||||
decoration: InputDecoration(labelText: decorationText),
|
||||
isExpanded: true,
|
||||
items: [
|
||||
if (widget.showMultilingual)
|
||||
if (showMultilingual)
|
||||
DropdownMenuItem(
|
||||
value: LanguageModel.multiLingual(context),
|
||||
child: LanguageDropDownEntry(
|
||||
languageModel: LanguageModel.multiLingual(context),
|
||||
isL2List: widget.isL2List,
|
||||
isL2List: isL2List,
|
||||
),
|
||||
),
|
||||
...sortedLanguages.map(
|
||||
|
|
@ -82,17 +77,18 @@ class _PLanguageDropdownState extends State<PLanguageDropdown> {
|
|||
value: languageModel,
|
||||
child: LanguageDropDownEntry(
|
||||
languageModel: languageModel,
|
||||
isL2List: widget.isL2List,
|
||||
isL2List: isL2List,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
onChanged: (value) => widget.onChange(value!),
|
||||
value: widget.initialLanguage,
|
||||
onChanged: (value) => onChange(value!),
|
||||
value: initialLanguage,
|
||||
validator: (value) => validator?.call(value),
|
||||
),
|
||||
AnimatedSize(
|
||||
duration: FluffyThemes.animationDuration,
|
||||
child: widget.error == null
|
||||
child: error == null
|
||||
? const SizedBox.shrink()
|
||||
: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
|
|
@ -100,7 +96,7 @@ class _PLanguageDropdownState extends State<PLanguageDropdown> {
|
|||
vertical: 5,
|
||||
),
|
||||
child: Text(
|
||||
widget.error!,
|
||||
error!,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
fontSize: 12,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue