Merge pull request #644 from pangeachat/merge-in-dev-changes

Merge in dev changes
pull/1384/head
ggurdin 1 year ago committed by GitHub
commit 5dbf127a30
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -4127,5 +4127,6 @@
"createSpace": "Create space",
"createChat": "Create chat",
"error520Title": "Please try again.",
"error520Desc": "Sorry, we could not understand your message..."
"error520Desc": "Sorry, we could not understand your message...",
"translationChoicesBody": "Click and hold an option for a hint."
}

@ -1,9 +1,8 @@
import 'package:animations/animations.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart';
import 'package:fluffychat/pages/chat/input_bar.dart';
import 'package:fluffychat/pangea/choreographer/widgets/send_button.dart';
import 'package:fluffychat/pangea/constants/language_constants.dart';
import 'package:fluffychat/pangea/widgets/chat/input_bar_wrapper.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/matrix.dart';
@ -34,7 +33,7 @@ class ChatInputRow extends StatelessWidget {
controller.pangeaController.languageController.activeL2Model();
String hintText() {
if (controller.choreographer.choreoMode == ChoreoMode.it) {
if (controller.choreographer.itController.willOpen) {
return L10n.of(context)!.buildTranslation;
}
return activel1 != null &&
@ -322,10 +321,7 @@ class ChatInputRow extends StatelessWidget {
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 0.0),
// #Pangea
// child: InputBar(
child: InputBarWrapper(
// Pangea#
child: InputBar(
room: controller.room,
minLines: 1,
maxLines: 8,

@ -5,7 +5,6 @@ import 'package:fluffychat/pages/chat/chat_app_bar_list_tile.dart';
import 'package:fluffychat/pages/chat/chat_app_bar_title.dart';
import 'package:fluffychat/pages/chat/chat_emoji_picker.dart';
import 'package:fluffychat/pages/chat/chat_event_list.dart';
import 'package:fluffychat/pages/chat/chat_input_row.dart';
import 'package:fluffychat/pages/chat/pinned_events.dart';
import 'package:fluffychat/pages/chat/reactions_picker.dart';
import 'package:fluffychat/pages/chat/reply_display.dart';
@ -13,6 +12,7 @@ import 'package:fluffychat/pangea/choreographer/widgets/it_bar.dart';
import 'package:fluffychat/pangea/choreographer/widgets/start_igc_button.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart';
import 'package:fluffychat/pangea/widgets/chat/chat_floating_action_button.dart';
import 'package:fluffychat/pangea/widgets/chat/input_bar_wrapper.dart';
import 'package:fluffychat/utils/account_config.dart';
import 'package:fluffychat/widgets/chat_settings_popup_menu.dart';
import 'package:fluffychat/widgets/connection_status_header.dart';
@ -498,7 +498,9 @@ class ChatView extends StatelessWidget {
),
ReactionsPicker(controller),
ReplyDisplay(controller),
ChatInputRow(controller),
ChatInputRowWrapper(
controller: controller,
),
ChatEmojiPicker(controller),
],
),

@ -41,6 +41,7 @@ class IgcController {
final IGCRequestBody reqBody = IGCRequestBody(
fullText: choreographer.currentText,
userId: choreographer.pangeaController.userController.userId!,
userL1: choreographer.l1LangCode!,
userL2: choreographer.l2LangCode!,
enableIGC: choreographer.igcEnabled && !onlyTokensAndLanguageDetection,

@ -3,6 +3,7 @@ import 'dart:developer';
import 'package:fluffychat/pangea/choreographer/controllers/error_service.dart';
import 'package:fluffychat/pangea/constants/choreo_constants.dart';
import 'package:fluffychat/pangea/enum/instructions_enum.dart';
import 'package:fluffychat/pangea/utils/error_handler.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@ -54,6 +55,23 @@ class ITController {
choreographer.setState();
}
bool _closingHint = false;
Duration get animationSpeed => (_closingHint || !_willOpen)
? const Duration(milliseconds: 500)
: const Duration(milliseconds: 2000);
void closeHint() {
_closingHint = true;
final String hintKey = InlineInstructions.translationChoices.toString();
final instructionsController = choreographer.pangeaController.instructions;
instructionsController.turnOffInstruction(hintKey);
instructionsController.updateEnableInstructions(hintKey, true);
choreographer.setState();
Future.delayed(const Duration(milliseconds: 500), () {
_closingHint = false;
});
}
Future<void> initializeIT(ITStartData itStartData) async {
_willOpen = true;
Future.delayed(const Duration(microseconds: 100), () {

@ -7,7 +7,9 @@ import 'package:fluffychat/pangea/choreographer/widgets/it_bar_buttons.dart';
import 'package:fluffychat/pangea/choreographer/widgets/it_feedback_card.dart';
import 'package:fluffychat/pangea/choreographer/widgets/translation_finished_flow.dart';
import 'package:fluffychat/pangea/constants/choreo_constants.dart';
import 'package:fluffychat/pangea/enum/instructions_enum.dart';
import 'package:fluffychat/pangea/utils/error_handler.dart';
import 'package:fluffychat/pangea/utils/inline_tooltip.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@ -45,12 +47,16 @@ class ITBarState extends State<ITBar> {
super.dispose();
}
bool get instructionsTurnedOff =>
widget.choreographer.pangeaController.instructions
.wereInstructionsTurnedOff(
InlineInstructions.translationChoices.toString(),
);
@override
Widget build(BuildContext context) {
return AnimatedSize(
duration: itController.willOpen
? const Duration(milliseconds: 2000)
: const Duration(milliseconds: 500),
duration: itController.animationSpeed,
curve: Curves.fastOutSlowIn,
clipBehavior: Clip.none,
child: !itController.willOpen
@ -58,9 +64,7 @@ class ITBarState extends State<ITBar> {
: CompositedTransformTarget(
link: widget.choreographer.itBarLinkAndKey.link,
child: AnimatedOpacity(
duration: itController.willOpen
? const Duration(milliseconds: 2000)
: const Duration(milliseconds: 500),
duration: itController.animationSpeed,
opacity: itController.willOpen ? 1.0 : 0.0,
child: Container(
key: widget.choreographer.itBarLinkAndKey.key,
@ -109,6 +113,12 @@ class ITBarState extends State<ITBar> {
// const SizedBox(height: 40.0),
OriginalText(controller: itController),
const SizedBox(height: 7.0),
if (!instructionsTurnedOff)
InlineTooltip(
body: InlineInstructions.translationChoices
.body(context),
onClose: itController.closeHint,
),
IntrinsicHeight(
child: Container(
constraints:
@ -151,6 +161,7 @@ class ITBarState extends State<ITBar> {
),
),
),
// ),
),
);
}
@ -305,7 +316,11 @@ class ITChoices extends StatelessWidget {
chosenContinuance:
controller.currentITStep!.continuances[index].text,
bestContinuance: controller.currentITStep!.best.text,
feedbackLang: controller.targetLangCode,
// TODO: we want this to eventually switch between target and source lang,
// based on the learner's proficiency - maybe with the words involved in the translation
// maybe overall. For now, we'll just use the source lang.
feedbackLang: controller.choreographer.l1Lang?.langCode ??
controller.sourceLangCode,
sourceTextLang: controller.sourceLangCode,
targetLang: controller.targetLangCode,
),

@ -146,8 +146,11 @@ class ITFeedbackCardView extends StatelessWidget {
controller.res!.text,
style: BotStyle.text(context),
),
// if res is not null, show a button to translate the text
if (controller.res != null && controller.translatedFeedback == null)
// if res is not null and feedback not in the userL1, show a button to translate the text
if (controller.res != null &&
controller.translatedFeedback == null &&
controller.widget.req.feedbackLang !=
controller.controller.languageController.userL1?.langCode)
Column(
children: [
const SizedBox(height: 10),

@ -58,6 +58,7 @@ extension InstructionsEnumExtension on InstructionsEnum {
enum InlineInstructions {
speechToText,
l1Translation,
translationChoices,
}
extension InlineInstructionsExtension on InlineInstructions {
@ -67,6 +68,21 @@ extension InlineInstructionsExtension on InlineInstructions {
return L10n.of(context)!.speechToTextBody;
case InlineInstructions.l1Translation:
return L10n.of(context)!.l1TranslationBody;
case InlineInstructions.translationChoices:
return L10n.of(context)!.translationChoicesBody;
}
}
bool get toggledOff {
final instructionSettings =
MatrixState.pangeaController.userController.profile.instructionSettings;
switch (this) {
case InlineInstructions.speechToText:
return instructionSettings.showedSpeechToTextTooltip;
case InlineInstructions.l1Translation:
return instructionSettings.showedL1TranslationTooltip;
case InlineInstructions.translationChoices:
return instructionSettings.showedTranslationChoicesTooltip;
}
}
}

@ -186,11 +186,18 @@ class UserInstructions {
bool showedBlurMeansTranslate;
bool showedTooltipInstructions;
bool showedSpeechToTextTooltip;
bool showedL1TranslationTooltip;
bool showedTranslationChoicesTooltip;
UserInstructions({
this.showedItInstructions = false,
this.showedClickMessage = false,
this.showedBlurMeansTranslate = false,
this.showedTooltipInstructions = false,
this.showedSpeechToTextTooltip = false,
this.showedL1TranslationTooltip = false,
this.showedTranslationChoicesTooltip = false,
});
factory UserInstructions.fromJson(Map<String, dynamic> json) =>
@ -203,6 +210,12 @@ class UserInstructions {
json[InstructionsEnum.blurMeansTranslate.toString()] ?? false,
showedTooltipInstructions:
json[InstructionsEnum.tooltipInstructions.toString()] ?? false,
showedL1TranslationTooltip:
json[InlineInstructions.l1Translation.toString()] ?? false,
showedTranslationChoicesTooltip:
json[InlineInstructions.translationChoices.toString()] ?? false,
showedSpeechToTextTooltip:
json[InlineInstructions.speechToText.toString()] ?? false,
);
Map<String, dynamic> toJson() {
@ -213,6 +226,12 @@ class UserInstructions {
showedBlurMeansTranslate;
data[InstructionsEnum.tooltipInstructions.toString()] =
showedTooltipInstructions;
data[InlineInstructions.l1Translation.toString()] =
showedL1TranslationTooltip;
data[InlineInstructions.translationChoices.toString()] =
showedTranslationChoicesTooltip;
data[InlineInstructions.speechToText.toString()] =
showedSpeechToTextTooltip;
return data;
}
@ -238,6 +257,21 @@ class UserInstructions {
?.content[InstructionsEnum.tooltipInstructions.toString()]
as bool?) ??
false,
showedL1TranslationTooltip:
(accountData[InlineInstructions.l1Translation.toString()]
?.content[InlineInstructions.l1Translation.toString()]
as bool?) ??
false,
showedTranslationChoicesTooltip: (accountData[
InlineInstructions.translationChoices.toString()]
?.content[InlineInstructions.translationChoices.toString()]
as bool?) ??
false,
showedSpeechToTextTooltip:
(accountData[InlineInstructions.speechToText.toString()]
?.content[InlineInstructions.speechToText.toString()]
as bool?) ??
false,
);
}
}

@ -129,6 +129,7 @@ class IGCRequestBody {
String userL2;
bool enableIT;
bool enableIGC;
String userId;
List<PreviousMessage> prevMessages;
IGCRequestBody({
@ -137,6 +138,7 @@ class IGCRequestBody {
required this.userL2,
required this.enableIGC,
required this.enableIT,
required this.userId,
required this.prevMessages,
});
@ -146,6 +148,7 @@ class IGCRequestBody {
ModelKey.userL2: userL2,
"enable_it": enableIT,
"enable_igc": enableIGC,
ModelKey.userId: userId,
ModelKey.prevMessages:
jsonEncode(prevMessages.map((x) => x.toJson()).toList()),
};

@ -26,7 +26,7 @@ class InlineTooltip extends StatelessWidget {
onPressed: onClose,
),
),
child: Container(
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Theme.of(context).colorScheme.primary.withAlpha(20),

@ -25,9 +25,15 @@ class InstructionsController {
final Map<String, bool> _instructionsShown = {};
/// Returns true if the user requested this popup not be shown again
bool? toggledOff(String key) => InstructionsEnum.values
.firstWhereOrNull((value) => value.toString() == key)
?.toggledOff;
bool? toggledOff(String key) {
final bool? instruction = InstructionsEnum.values
.firstWhereOrNull((value) => value.toString() == key)
?.toggledOff;
final bool? tooltip = InlineInstructions.values
.firstWhereOrNull((value) => value.toString() == key)
?.toggledOff;
return instruction ?? tooltip;
}
InstructionsController(PangeaController pangeaController) {
_pangeaController = pangeaController;
@ -58,6 +64,15 @@ class InstructionsController {
if (key == InstructionsEnum.tooltipInstructions.toString()) {
profile.instructionSettings.showedTooltipInstructions = value;
}
if (key == InlineInstructions.speechToText.toString()) {
profile.instructionSettings.showedSpeechToTextTooltip = value;
}
if (key == InlineInstructions.l1Translation.toString()) {
profile.instructionSettings.showedL1TranslationTooltip = value;
}
if (key == InlineInstructions.translationChoices.toString()) {
profile.instructionSettings.showedTranslationChoicesTooltip = value;
}
return profile;
});
}

@ -1,48 +1,23 @@
import 'dart:async';
import 'dart:typed_data';
import 'package:fluffychat/pages/chat/input_bar.dart';
import 'package:fluffychat/pages/chat/chat.dart';
import 'package:fluffychat/pages/chat/chat_input_row.dart';
import 'package:fluffychat/pangea/widgets/igc/pangea_text_controller.dart';
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
class InputBarWrapper extends StatefulWidget {
final Room room;
final int? minLines;
final int? maxLines;
final TextInputType? keyboardType;
final TextInputAction? textInputAction;
final ValueChanged<String>? onSubmitted;
final ValueChanged<Uint8List?>? onSubmitImage;
final FocusNode? focusNode;
final PangeaTextController? controller;
final InputDecoration? decoration;
final ValueChanged<String>? onChanged;
final bool? autofocus;
final bool readOnly;
class ChatInputRowWrapper extends StatefulWidget {
final ChatController controller;
const InputBarWrapper({
required this.room,
this.minLines,
this.maxLines,
this.keyboardType,
this.onSubmitted,
this.onSubmitImage,
this.focusNode,
this.controller,
this.decoration,
this.onChanged,
this.autofocus,
this.textInputAction,
this.readOnly = false,
const ChatInputRowWrapper({
required this.controller,
super.key,
});
@override
State<InputBarWrapper> createState() => InputBarWrapperState();
State<ChatInputRowWrapper> createState() => ChatInputRowWrapperState();
}
class InputBarWrapperState extends State<InputBarWrapper> {
class ChatInputRowWrapperState extends State<ChatInputRowWrapper> {
StreamSubscription? _choreoSub;
String _currentText = '';
@ -50,7 +25,7 @@ class InputBarWrapperState extends State<InputBarWrapper> {
void initState() {
// Rebuild the widget each time there's an update from choreo
_choreoSub =
widget.controller?.choreographer.stateListener.stream.listen((_) {
widget.controller.choreographer.stateListener.stream.listen((_) {
setState(() {});
});
super.initState();
@ -63,10 +38,6 @@ class InputBarWrapperState extends State<InputBarWrapper> {
}
void refreshOnChange(String text) {
if (widget.onChanged != null) {
widget.onChanged!(text);
}
final bool decreasedFromMaxLength =
_currentText.length >= PangeaTextController.maxLength &&
text.length < PangeaTextController.maxLength;
@ -81,21 +52,5 @@ class InputBarWrapperState extends State<InputBarWrapper> {
}
@override
Widget build(BuildContext context) {
return InputBar(
room: widget.room,
minLines: widget.minLines,
maxLines: widget.maxLines,
keyboardType: widget.keyboardType,
onSubmitted: widget.onSubmitted,
onSubmitImage: widget.onSubmitImage,
focusNode: widget.focusNode,
controller: widget.controller,
decoration: widget.decoration,
onChanged: refreshOnChange,
autofocus: widget.autofocus,
textInputAction: widget.textInputAction,
readOnly: widget.readOnly,
);
}
Widget build(BuildContext context) => ChatInputRow(widget.controller);
}

Loading…
Cancel
Save