added enabled tts learning setting, give user a warning message when tts not available for target language (#1227)

pull/1544/head
ggurdin 11 months ago committed by GitHub
parent 43040c4010
commit 9444aecfd3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -4058,7 +4058,7 @@
"roomDataMissing": "Some data may be missing from rooms in which you are not a member.",
"updatePhoneOS": "You may need to update your device's OS version.",
"wordsPerMinute": "Words per minute",
"autoIGCToolName": "Run Language Assistance Automatically",
"autoIGCToolName": "Run language assistance automatically",
"autoIGCToolDescription": "Automatically run language assistance after typing messages",
"runGrammarCorrection": "Check message",
"grammarCorrectionFailed": "Issues to address",
@ -4623,5 +4623,9 @@
"maxXP": {}
}
},
"registrationEmailMessage": "Please verify your email with a link sent there. In some cases, the email takes up to 5 minutes to arrive. Please also check your spam folder."
"registrationEmailMessage": "Please verify your email with a link sent there. In some cases, the email takes up to 5 minutes to arrive. Please also check your spam folder.",
"enableTTSToolName": "Enabled text-to-speech",
"enableTTSToolDescription": "Allow the app to generate text-to-speech output for portions of text in your target language",
"couldNotFindTTS": "We couldn't find a text-to-speech engine for your current target language. ",
"ttsInstructionsHyperlink": "Click here to view instructions for downloading a new voice on your device."
}

@ -159,6 +159,11 @@ abstract class AppConfig {
static String androidUpdateURL =
"https://play.google.com/store/apps/details?id=com.talktolearn.chat";
static String iosUpdateURL = "itms-apps://itunes.apple.com/app/id1445118630";
static String windowsTTSDownloadInstructions =
"https://support.microsoft.com/en-us/topic/download-languages-and-voices-for-immersive-reader-read-mode-and-read-aloud-4c83a8d8-7486-42f7-8e46-2b0fdf753130";
static String androidTTSDownloadInstructions =
"https://support.google.com/accessibility/android/answer/6006983?hl=en";
// Pangea#
static void loadFromJson(Map<String, dynamic> json) {

@ -232,6 +232,7 @@ enum ToolSetting {
definitions,
// translations,
autoIGC,
enableTTS,
}
extension SettingCopy on ToolSetting {
@ -249,6 +250,8 @@ extension SettingCopy on ToolSetting {
// return L10n.of(context).messageTranslationsToolName;
case ToolSetting.autoIGC:
return L10n.of(context).autoIGCToolName;
case ToolSetting.enableTTS:
return L10n.of(context).enableTTSToolName;
}
}
@ -267,6 +270,8 @@ extension SettingCopy on ToolSetting {
// return L10n.of(context).translationsToolDescrption;
case ToolSetting.autoIGC:
return L10n.of(context).autoIGCToolDescription;
case ToolSetting.enableTTS:
return L10n.of(context).enableTTSToolDescription;
}
}
@ -278,6 +283,7 @@ extension SettingCopy on ToolSetting {
case ToolSetting.immersionMode:
return false;
case ToolSetting.autoIGC:
case ToolSetting.enableTTS:
return true;
}
}

@ -126,6 +126,7 @@ class UserToolSettings {
bool immersionMode;
bool definitions;
bool autoIGC;
bool enableTTS;
UserToolSettings({
this.interactiveTranslator = true,
@ -133,6 +134,7 @@ class UserToolSettings {
this.immersionMode = false,
this.definitions = true,
this.autoIGC = true,
this.enableTTS = true,
});
factory UserToolSettings.fromJson(Map<String, dynamic> json) =>
@ -144,6 +146,7 @@ class UserToolSettings {
immersionMode: false,
definitions: json[ToolSetting.definitions.toString()] ?? true,
autoIGC: json[ToolSetting.autoIGC.toString()] ?? true,
enableTTS: json[ToolSetting.enableTTS.toString()] ?? true,
);
Map<String, dynamic> toJson() {
@ -153,6 +156,7 @@ class UserToolSettings {
data[ToolSetting.immersionMode.toString()] = immersionMode;
data[ToolSetting.definitions.toString()] = definitions;
data[ToolSetting.autoIGC.toString()] = autoIGC;
data[ToolSetting.enableTTS.toString()] = enableTTS;
return data;
}

@ -3,6 +3,7 @@ import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/models/space_model.dart';
import 'package:fluffychat/pangea/models/user_model.dart';
import 'package:fluffychat/pangea/pages/settings_learning/settings_learning_view.dart';
import 'package:fluffychat/pangea/widgets/chat/tts_controller.dart';
import 'package:fluffychat/pangea/widgets/user_settings/p_language_dialog.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
@ -16,6 +17,19 @@ class SettingsLearning extends StatefulWidget {
class SettingsLearningController extends State<SettingsLearning> {
PangeaController pangeaController = MatrixState.pangeaController;
final tts = TtsController();
@override
void initState() {
super.initState();
tts.setupTTS().then((_) => setState(() {}));
}
@override
void dispose() {
tts.dispose();
super.dispose();
}
setPublicProfile(bool isPublic) {
pangeaController.userController.updateProfile((profile) {
@ -50,6 +64,8 @@ class SettingsLearningController extends State<SettingsLearning> {
return profile..toolSettings.definitions = value;
case ToolSetting.autoIGC:
return profile..toolSettings.autoIGC = value;
case ToolSetting.enableTTS:
return profile..toolSettings.enableTTS = value;
}
});
}
@ -67,6 +83,8 @@ class SettingsLearningController extends State<SettingsLearning> {
return toolSettings.definitions;
case ToolSetting.autoIGC:
return toolSettings.autoIGC;
case ToolSetting.enableTTS:
return toolSettings.enableTTS;
}
}

@ -1,12 +1,18 @@
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pangea/constants/model_keys.dart';
import 'package:fluffychat/pangea/models/space_model.dart';
import 'package:fluffychat/pangea/pages/settings_learning/settings_learning.dart';
import 'package:fluffychat/pangea/widgets/user_settings/country_picker_tile.dart';
import 'package:fluffychat/pangea/widgets/user_settings/language_tile.dart';
import 'package:fluffychat/pangea/widgets/user_settings/p_settings_switch_list_tile.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/layouts/max_width_body.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:url_launcher/url_launcher_string.dart';
class SettingsLearningView extends StatelessWidget {
final SettingsLearningController controller;
@ -14,6 +20,14 @@ class SettingsLearningView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: Matrix.of(context).client.onSync.stream.where((update) {
return update.accountData != null &&
update.accountData!.any(
(event) => event.type == ModelKey.userProfile,
);
}),
builder: (context, _) {
final dialogContent = Scaffold(
appBar: AppBar(
centerTitle: true,
@ -39,40 +53,63 @@ class SettingsLearningView extends StatelessWidget {
),
for (final toolSetting in ToolSetting.values
.where((tool) => tool.isAvailableSetting))
Column(
children: [
ProfileSettingsSwitchListTile.adaptive(
defaultValue: controller.getToolSetting(toolSetting),
title: toolSetting.toolName(context),
subtitle: toolSetting.toolDescription(context),
onChange: (bool value) => controller.updateToolSetting(
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,
);
},
),
],
),
),
),
],
),
// ProfileSettingsSwitchListTile.adaptive(
// defaultValue: controller.pangeaController.userController.profile
// .userSettings.itAutoPlay,
// title:
// L10n.of(context).interactiveTranslatorAutoPlaySliderHeader,
// subtitle: L10n.of(context).interactiveTranslatorAutoPlayDesc,
// onChange: (bool value) => controller
// .pangeaController.userController
// .updateProfile((profile) {
// profile.userSettings.itAutoPlay = value;
// return profile;
// }),
// ),
// ProfileSettingsSwitchListTile.adaptive(
// defaultValue: controller.pangeaController.userController.profile
// .userSettings.autoPlayMessages,
// title: L10n.of(context).autoPlayTitle,
// subtitle: L10n.of(context).autoPlayDesc,
// onChange: (bool value) => controller
// .pangeaController.userController
// .updateProfile((profile) {
// profile.userSettings.autoPlayMessages = value;
// return profile;
// }),
// ),
],
),
),
@ -98,5 +135,7 @@ class SettingsLearningView extends StatelessWidget {
child: dialogContent,
),
);
},
);
}
}

@ -1,5 +1,7 @@
import 'dart:async';
import 'dart:developer';
import 'package:fluffychat/pangea/controllers/user_controller.dart';
import 'package:fluffychat/pangea/enum/instructions_enum.dart';
import 'package:fluffychat/pangea/utils/error_handler.dart';
import 'package:fluffychat/pangea/widgets/chat/missing_voice_button.dart';
@ -18,17 +20,24 @@ class TtsController {
List<String> _availableLangCodes = [];
final flutter_tts.FlutterTts _tts = flutter_tts.FlutterTts();
final TextToSpeech _alternativeTTS = TextToSpeech();
StreamSubscription? _languageSubscription;
UserController get userController =>
MatrixState.pangeaController.userController;
TtsController() {
setupTTS();
_languageSubscription =
userController.stateStream.listen((_) => setupTTS());
}
bool get _useAlternativeTTS {
return PlatformInfos.getOperatingSystem() == 'Windows';
return PlatformInfos.isWindows;
}
Future<void> dispose() async {
await _tts.stop();
await _languageSubscription?.cancel();
}
void _onError(dynamic message) => ErrorHandler.logError(
@ -40,12 +49,10 @@ class TtsController {
);
Future<void> setupTTS() async {
try {
if (_useAlternativeTTS) {
await _setupAltTTS();
return;
}
try {
} else {
_tts.setErrorHandler(_onError);
debugger(when: kDebugMode && targetLanguage == null);
@ -66,13 +73,22 @@ class TtsController {
.toSet()
.cast<String>()
.toList();
debugPrint("availableLangCodes: $_availableLangCodes");
debugger(when: kDebugMode && !_isLanguageFullySupported);
}
} catch (e, s) {
debugger(when: kDebugMode);
ErrorHandler.logError(e: e, s: s);
} finally {
debugPrint("availableLangCodes: $_availableLangCodes");
final enableTTSSetting = userController.profile.toolSettings.enableTTS;
if (enableTTSSetting != isLanguageFullySupported) {
await userController.updateProfile(
(profile) {
profile.toolSettings.enableTTS = isLanguageFullySupported;
return profile;
},
waitForDataInSync: true,
);
}
}
}
@ -148,7 +164,12 @@ class TtsController {
// TODO - make non-nullable again
String? eventID,
) async {
if (_isLanguageFullySupported) {
if (!MatrixState
.pangeaController.userController.profile.toolSettings.enableTTS) {
return;
}
if (isLanguageFullySupported) {
await _speak(text);
} else {
ErrorHandler.logError(
@ -200,6 +221,6 @@ class TtsController {
}
}
bool get _isLanguageFullySupported =>
bool get isLanguageFullySupported =>
_availableLangCodes.contains(targetLanguage);
}

@ -7,12 +7,14 @@ class ProfileSettingsSwitchListTile extends StatefulWidget {
final String title;
final String? subtitle;
final Function(bool) onChange;
final bool enabled;
const ProfileSettingsSwitchListTile.adaptive({
super.key,
required this.defaultValue,
required this.title,
required this.onChange,
this.enabled = true,
this.subtitle,
});
@ -30,6 +32,14 @@ class PSettingsSwitchListTileState
super.initState();
}
@override
void didUpdateWidget(ProfileSettingsSwitchListTile oldWidget) {
if (oldWidget.defaultValue != widget.defaultValue) {
setState(() => currentValue = widget.defaultValue);
}
super.didUpdateWidget(oldWidget);
}
@override
Widget build(BuildContext context) {
return SwitchListTile.adaptive(
@ -37,7 +47,8 @@ class PSettingsSwitchListTileState
title: Text(widget.title),
activeColor: AppConfig.activeToggleColor,
subtitle: widget.subtitle != null ? Text(widget.subtitle!) : null,
onChanged: (bool newValue) async {
onChanged: widget.enabled
? (bool newValue) async {
try {
widget.onChange(newValue);
setState(() => currentValue = newValue);
@ -48,7 +59,8 @@ class PSettingsSwitchListTileState
s: s,
);
}
},
}
: null,
);
}
}

@ -13,7 +13,10 @@ import '../config/app_config.dart';
abstract class PlatformInfos {
static bool get isWeb => kIsWeb;
static bool get isLinux => !kIsWeb && Platform.isLinux;
static bool get isWindows => !kIsWeb && Platform.isWindows;
// #Pangea
// static bool get isWindows => !kIsWeb && Platform.isWindows;
static bool get isWindows => getOperatingSystem() == 'Windows';
// Pangea#
static bool get isMacOS => !kIsWeb && Platform.isMacOS;
static bool get isIOS => !kIsWeb && Platform.isIOS;
static bool get isAndroid => !kIsWeb && Platform.isAndroid;

Loading…
Cancel
Save