Merge branch 'main' into language-detect-api

pull/1183/head
ggurdin 2 years ago
commit 20853ef547

@ -232,20 +232,26 @@ abstract class AppRoutes {
pageBuilder: (context, state) => defaultPageBuilder( pageBuilder: (context, state) => defaultPageBuilder(
context, context,
state, state,
const NewGroup(), NewGroup(
// #Pangea
spaceId: state.uri.queryParameters['spaceId'],
// Pangea#
),
), ),
redirect: loggedOutRedirect, redirect: loggedOutRedirect,
routes: [ // #Pangea
GoRoute( // routes: [
path: ':spaceid', // GoRoute(
pageBuilder: (context, state) => defaultPageBuilder( // path: ':spaceid',
context, // pageBuilder: (context, state) => defaultPageBuilder(
state, // context,
const NewGroup(), // state,
), // const NewGroup(),
redirect: loggedOutRedirect, // ),
), // redirect: loggedOutRedirect,
], // ),
// ],
// Pangea#
), ),
GoRoute( GoRoute(
path: 'newspace', path: 'newspace',

@ -1,13 +1,12 @@
import 'package:flutter/material.dart';
import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:fluffychat/pages/archive/archive_view.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'package:fluffychat/pages/archive/archive_view.dart';
import 'package:fluffychat/widgets/matrix.dart';
class Archive extends StatefulWidget { class Archive extends StatefulWidget {
const Archive({super.key}); const Archive({super.key});
@ -20,7 +19,12 @@ class ArchiveController extends State<Archive> {
Future<List<Room>> getArchive(BuildContext context) async { Future<List<Room>> getArchive(BuildContext context) async {
if (archive.isNotEmpty) return archive; if (archive.isNotEmpty) return archive;
return archive = await Matrix.of(context).client.loadArchive(); // #Pangea
//return archive = await Matrix.of(context).client.loadArchive();
return archive = (await Matrix.of(context).client.loadArchive())
.where((e) => (!e.isSpace && !e.isAnalyticsRoom))
.toList();
// Pangea#
} }
void forgetRoomAction(int i) async { void forgetRoomAction(int i) async {

@ -1078,6 +1078,9 @@ class ChatController extends State<ChatPageWithRoom>
bool get canEditSelectedEvents { bool get canEditSelectedEvents {
if (isArchived || if (isArchived ||
selectedEvents.length != 1 || selectedEvents.length != 1 ||
// #Pangea
selectedEvents.single.messageType != MessageTypes.Text ||
// Pangea#
!selectedEvents.first.status.isSent) { !selectedEvents.first.status.isSent) {
return false; return false;
} }

@ -116,7 +116,8 @@ class ChatView extends StatelessWidget {
// #Pangea // #Pangea
} else { } else {
return [ return [
ChatSettingsPopupMenu(controller.room, !controller.room.isDirectChat), ChatSettingsPopupMenu(controller.room,
(!controller.room.isDirectChat && !controller.room.isArchived)),
]; ];
} }

@ -38,6 +38,7 @@ class MessageContent extends StatelessWidget {
//further down in the chain is also using pangeaController so its not constant //further down in the chain is also using pangeaController so its not constant
final bool immersionMode; final bool immersionMode;
final ToolbarDisplayController? toolbarController; final ToolbarDisplayController? toolbarController;
final bool isOverlay;
// Pangea# // Pangea#
const MessageContent( const MessageContent(
@ -50,6 +51,7 @@ class MessageContent extends StatelessWidget {
this.pangeaMessageEvent, this.pangeaMessageEvent,
required this.immersionMode, required this.immersionMode,
required this.toolbarController, required this.toolbarController,
this.isOverlay = false,
// Pangea# // Pangea#
required this.borderRadius, required this.borderRadius,
}); });
@ -203,7 +205,8 @@ class MessageContent extends StatelessWidget {
&& &&
!(pangeaMessageEvent?.showRichText( !(pangeaMessageEvent?.showRichText(
selected, selected,
toolbarController?.highlighted ?? false, isOverlay: isOverlay,
highlighted: toolbarController?.highlighted ?? false,
) ?? ) ??
false) false)
// Pangea# // Pangea#
@ -305,7 +308,8 @@ class MessageContent extends StatelessWidget {
); );
if (pangeaMessageEvent?.showRichText( if (pangeaMessageEvent?.showRichText(
selected, selected,
toolbarController?.highlighted ?? false, isOverlay: isOverlay,
highlighted: toolbarController?.highlighted ?? false,
) ?? ) ??
false) { false) {
return PangeaRichText( return PangeaRichText(

@ -237,6 +237,10 @@ class _SpaceViewState extends State<SpaceView> {
icon: Icons.send_outlined, icon: Icons.send_outlined,
), ),
if (spaceChild != null && if (spaceChild != null &&
// #Pangea
room != null &&
room.ownPowerLevel >= ClassDefaultValues.powerLevelOfAdmin &&
// Pangea#
(activeSpace?.canChangeStateEvent(EventTypes.spaceChild) ?? false)) (activeSpace?.canChangeStateEvent(EventTypes.spaceChild) ?? false))
SheetAction( SheetAction(
key: SpaceChildContextAction.removeFromSpace, key: SpaceChildContextAction.removeFromSpace,

@ -30,7 +30,9 @@ class StartChatFloatingActionButton extends StatelessWidget {
void _onPressed(BuildContext context) async { void _onPressed(BuildContext context) async {
//#Pangea //#Pangea
if (controller.activeSpaceId != null) { if (controller.activeSpaceId != null) {
context.go('/rooms/newgroup/${controller.activeSpaceId ?? ''}'); context.go(
'/rooms/newgroup${controller.activeSpaceId != null ? '?spaceId=${controller.activeSpaceId}' : ''}',
);
return; return;
} }
//Pangea# //Pangea#
@ -44,7 +46,9 @@ class StartChatFloatingActionButton extends StatelessWidget {
case ActiveFilter.groups: case ActiveFilter.groups:
// #Pangea // #Pangea
// context.go('/rooms/newgroup'); // context.go('/rooms/newgroup');
context.go('/rooms/newgroup/${controller.activeSpaceId ?? ''}'); context.go(
'/rooms/newgroup${controller.activeSpaceId != null ? '?spaceId=${controller.activeSpaceId}' : ''}',
);
// Pangea# // Pangea#
break; break;
case ActiveFilter.spaces: case ActiveFilter.spaces:

@ -17,7 +17,14 @@ import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart' as sdk; import 'package:matrix/matrix.dart' as sdk;
class NewGroup extends StatefulWidget { class NewGroup extends StatefulWidget {
const NewGroup({super.key}); // #Pangea
final String? spaceId;
const NewGroup({
super.key,
this.spaceId,
});
// Pangea#
@override @override
NewGroupController createState() => NewGroupController(); NewGroupController createState() => NewGroupController();
@ -50,7 +57,7 @@ class NewGroupController extends State<NewGroup> {
void setVocab(List<Lemma> vocab) => setState(() => chatTopic.vocab = vocab); void setVocab(List<Lemma> vocab) => setState(() => chatTopic.vocab = vocab);
String? get activeSpaceId => String? get activeSpaceId =>
GoRouterState.of(context).pathParameters['spaceid']; GoRouterState.of(context).uri.queryParameters['spaceId'];
// Pangea# // Pangea#
void setPublicGroup(bool b) => setState(() => publicGroup = b); void setPublicGroup(bool b) => setState(() => publicGroup = b);

@ -57,6 +57,9 @@ class NewGroupView extends StatelessWidget {
const SizedBox(width: 16), const SizedBox(width: 16),
Expanded( Expanded(
child: TextField( child: TextField(
// #Pangea
maxLength: 32,
// Pangea#
controller: controller.nameController, controller: controller.nameController,
autocorrect: false, autocorrect: false,
readOnly: controller.loading, readOnly: controller.loading,

@ -95,6 +95,9 @@ class NewSpaceView extends StatelessWidget {
const SizedBox(width: 16), const SizedBox(width: 16),
Expanded( Expanded(
child: TextField( child: TextField(
// #Pangea
maxLength: 32,
// Pangea#
controller: controller.nameController, controller: controller.nameController,
autocorrect: false, autocorrect: false,
readOnly: controller.loading, readOnly: controller.loading,

@ -42,6 +42,9 @@ class SettingsController extends State<Settings> {
cancelLabel: L10n.of(context)!.cancel, cancelLabel: L10n.of(context)!.cancel,
textFields: [ textFields: [
DialogTextField( DialogTextField(
// #Pangea
maxLength: 32,
// Pangea#
initialText: profile?.displayName ?? initialText: profile?.displayName ??
Matrix.of(context).client.userID!.localpart, Matrix.of(context).client.userID!.localpart,
), ),

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
import 'package:matrix/matrix.dart';
enum MessageMode { translation, definition, speechToText, textToSpeech } enum MessageMode { translation, definition, speechToText, textToSpeech }
@ -52,4 +53,17 @@ extension MessageModeExtension on MessageMode {
.oopsSomethingWentWrong; // Title to indicate an error or unsupported mode .oopsSomethingWentWrong; // Title to indicate an error or unsupported mode
} }
} }
bool isValidMode(Event event) {
switch (this) {
case MessageMode.translation:
case MessageMode.textToSpeech:
case MessageMode.definition:
return event.messageType == MessageTypes.Text;
case MessageMode.speechToText:
return event.messageType == MessageTypes.Audio;
default:
return true;
}
}
} }

@ -815,6 +815,9 @@ extension PangeaRoom on Room {
); );
return false; return false;
} }
if (room != null && !room.isRoomAdmin) {
return false;
}
if (!pangeaCanSendEvent(EventTypes.spaceChild) && !isRoomAdmin) { if (!pangeaCanSendEvent(EventTypes.spaceChild) && !isRoomAdmin) {
return false; return false;
} }

@ -80,18 +80,26 @@ class PangeaMessageEvent {
return _latestEdit; return _latestEdit;
} }
bool showRichText(bool selected, bool highlighted) { bool showRichText(
bool selected, {
bool highlighted = false,
bool isOverlay = false,
}) {
if (!_isValidPangeaMessageEvent) { if (!_isValidPangeaMessageEvent) {
return false; return false;
} }
// if (URLFinder.getMatches(event.body).isNotEmpty) {
// return false;
// }
if ([EventStatus.error, EventStatus.sending].contains(_event.status)) { if ([EventStatus.error, EventStatus.sending].contains(_event.status)) {
return false; return false;
} }
if (ownMessage && !selected && !highlighted) return false;
if (isOverlay) return true;
// if ownMessage, don't show rich text if not selected or highlighted
// and don't show is the message is not an overlay
if (ownMessage && ((!selected && !highlighted) || !isOverlay)) {
return false;
}
return true; return true;
} }
@ -346,6 +354,19 @@ class PangeaMessageEvent {
), ),
); );
_representations?.add(
RepresentationEvent(
timeline: timeline,
content: PangeaRepresentation(
langCode: response.langCode,
text: response.transcript.text,
originalSent: false,
originalWritten: false,
speechToText: response,
),
),
);
return response; return response;
} }

@ -3,7 +3,6 @@ import 'dart:developer';
import 'package:fluffychat/pangea/extensions/pangea_event_extension.dart'; import 'package:fluffychat/pangea/extensions/pangea_event_extension.dart';
import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_choreo_event.dart'; import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_choreo_event.dart';
import 'package:fluffychat/pangea/models/pangea_token_model.dart'; import 'package:fluffychat/pangea/models/pangea_token_model.dart';
import 'package:fluffychat/pangea/models/speech_to_text_models.dart';
import 'package:fluffychat/pangea/models/tokens_event_content_model.dart'; import 'package:fluffychat/pangea/models/tokens_event_content_model.dart';
import 'package:fluffychat/pangea/repo/tokens_repo.dart'; import 'package:fluffychat/pangea/repo/tokens_repo.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -27,15 +26,12 @@ class RepresentationEvent {
ChoreoRecord? _choreo; ChoreoRecord? _choreo;
Timeline timeline; Timeline timeline;
SpeechToTextModel? _speechToTextResponse;
RepresentationEvent({ RepresentationEvent({
required this.timeline, required this.timeline,
Event? event, Event? event,
PangeaRepresentation? content, PangeaRepresentation? content,
PangeaMessageTokens? tokens, PangeaMessageTokens? tokens,
ChoreoRecord? choreo, ChoreoRecord? choreo,
SpeechToTextModel? speechToTextResponse,
}) { }) {
if (event != null && event.type != PangeaEventTypes.representation) { if (event != null && event.type != PangeaEventTypes.representation) {
throw Exception( throw Exception(
@ -46,7 +42,6 @@ class RepresentationEvent {
_content = content; _content = content;
_tokens = tokens; _tokens = tokens;
_choreo = choreo; _choreo = choreo;
_speechToTextResponse = speechToTextResponse;
} }
Event? get event => _event; Event? get event => _event;

@ -1,9 +1,8 @@
import 'dart:developer'; import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:fluffychat/pangea/constants/model_keys.dart'; import 'package:fluffychat/pangea/constants/model_keys.dart';
import 'package:fluffychat/pangea/widgets/igc/word_data_card.dart'; import 'package:fluffychat/pangea/widgets/igc/word_data_card.dart';
import 'package:flutter/foundation.dart';
class WordData { class WordData {
final String word; final String word;
@ -102,10 +101,11 @@ class WordData {
}) => }) =>
word == w && userL1 == l1 && userL2 == l2 && fullText == f; word == w && userL1 == l1 && userL2 == l2 && fullText == f;
String formattedPartOfSpeech(LanguageType languageType) { String? formattedPartOfSpeech(LanguageType languageType) {
final String pos = languageType == LanguageType.base final String pos = languageType == LanguageType.base
? basePartOfSpeech ? basePartOfSpeech
: targetPartOfSpeech; : targetPartOfSpeech;
if (pos.isEmpty) return null;
return pos[0].toUpperCase() + pos.substring(1); return pos[0].toUpperCase() + pos.substring(1);
} }

@ -1,10 +1,10 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart';
import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/pages/settings_learning/settings_learning_view.dart'; import 'package:fluffychat/pangea/pages/settings_learning/settings_learning_view.dart';
import 'package:fluffychat/pangea/widgets/user_settings/p_language_dialog.dart';
import 'package:fluffychat/widgets/matrix.dart'; import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
class SettingsLearning extends StatefulWidget { class SettingsLearning extends StatefulWidget {
const SettingsLearning({super.key}); const SettingsLearning({super.key});
@ -32,6 +32,11 @@ class SettingsLearningController extends State<SettingsLearning> {
}); });
} }
Future<void> changeLanguage() async {
await pLanguageDialog(context, () {});
setState(() {});
}
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();

@ -31,7 +31,7 @@ class SettingsLearningView extends StatelessWidget {
withScrolling: true, withScrolling: true,
child: Column( child: Column(
children: [ children: [
LanguageTile(), LanguageTile(controller),
CountryPickerTile(), CountryPickerTile(),
const SizedBox(height: 8), const SizedBox(height: 8),
const Divider(height: 1), const Divider(height: 1),

@ -27,6 +27,7 @@ void setClassDisplayname(BuildContext context, String? roomId) async {
: L10n.of(context)!.changeTheNameOfTheChat, : L10n.of(context)!.changeTheNameOfTheChat,
), ),
content: TextField( content: TextField(
maxLength: 32,
controller: textFieldController, controller: textFieldController,
), ),
actions: [ actions: [

@ -138,7 +138,7 @@ class MessageSpeechToTextCardState extends State<MessageSpeechToTextCard> {
} }
String? get wordsPerMinuteString => String? get wordsPerMinuteString =>
speechToTextResponse?.transcript.wordsPerMinute?.toString(); speechToTextResponse?.transcript.wordsPerMinute?.toStringAsFixed(2);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

@ -134,8 +134,11 @@ class ToolbarDisplayController {
}); });
} }
bool get highlighted => bool get highlighted {
MatrixState.pAnyState.overlay.hashCode.toString() == overlayId; if (overlayId == null) return false;
if (MatrixState.pAnyState.overlay == null) overlayId = null;
return MatrixState.pAnyState.overlay.hashCode.toString() == overlayId;
}
} }
class MessageToolbar extends StatefulWidget { class MessageToolbar extends StatefulWidget {
@ -172,6 +175,19 @@ class MessageToolbarState extends State<MessageToolbar> {
debugPrint("updating toolbar mode"); debugPrint("updating toolbar mode");
final bool subscribed = final bool subscribed =
MatrixState.pangeaController.subscriptionController.isSubscribed; MatrixState.pangeaController.subscriptionController.isSubscribed;
if (!newMode.isValidMode(widget.pangeaMessageEvent.event)) {
ErrorHandler.logError(
e: "Invalid mode for event",
s: StackTrace.current,
data: {
"newMode": newMode,
"event": widget.pangeaMessageEvent.event,
},
);
return;
}
setState(() { setState(() {
currentMode = newMode; currentMode = newMode;
updatingMode = true; updatingMode = true;
@ -274,12 +290,14 @@ class MessageToolbarState extends State<MessageToolbar> {
PLocalKey.autoPlayMessages, PLocalKey.autoPlayMessages,
) ?? ) ??
true; true;
if (widget.pangeaMessageEvent.isAudioMessage) {
updateMode(MessageMode.speechToText);
return;
}
autoplay autoplay
? updateMode( ? updateMode(MessageMode.textToSpeech)
widget.pangeaMessageEvent.isAudioMessage
? MessageMode.speechToText
: MessageMode.textToSpeech,
)
: updateMode(MessageMode.translation); : updateMode(MessageMode.translation);
}); });

@ -141,6 +141,7 @@ class OverlayMessage extends StatelessWidget {
pangeaMessageEvent: pangeaMessageEvent, pangeaMessageEvent: pangeaMessageEvent,
immersionMode: immersionMode, immersionMode: immersionMode,
toolbarController: toolbarController, toolbarController: toolbarController,
isOverlay: true,
), ),
if (event.hasAggregatedEvents( if (event.hasAggregatedEvents(
timeline, timeline,

@ -235,8 +235,13 @@ class AddToSpaceState extends State<AddToSpaceToggles> {
), ),
activeColor: AppConfig.activeToggleColor, activeColor: AppConfig.activeToggleColor,
value: isSuggestedInSpace(possibleParent), value: isSuggestedInSpace(possibleParent),
onChanged: (bool suggest) => onChanged: (bool suggest) => canAdd
setSuggested(suggest, possibleParent), ? setSuggested(suggest, possibleParent)
: ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(L10n.of(context)!.noPermission),
),
),
) )
: Container(), : Container(),
), ),

@ -48,28 +48,33 @@ class PangeaRichTextState extends State<PangeaRichText> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
updateTextSpan(); setTextSpan();
}
void updateTextSpan() {
setState(() {
textSpan = getTextSpan();
});
} }
@override @override
void didUpdateWidget(PangeaRichText oldWidget) { void didUpdateWidget(PangeaRichText oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
updateTextSpan(); setTextSpan();
}
void _setTextSpan(String newTextSpan) {
widget.toolbarController?.toolbar?.textSelection.setMessageText(
newTextSpan,
);
setState(() {
textSpan = newTextSpan;
});
} }
String getTextSpan() { void setTextSpan() {
if (_fetchingRepresentation == true) { if (_fetchingRepresentation == true) {
return widget.pangeaMessageEvent.body; _setTextSpan(textSpan = widget.pangeaMessageEvent.body);
return;
} }
if (repEvent != null) { if (repEvent != null) {
return repEvent!.text; _setTextSpan(repEvent!.text);
return;
} }
if (widget.pangeaMessageEvent.eventId.contains("webdebug")) { if (widget.pangeaMessageEvent.eventId.contains("webdebug")) {
@ -84,7 +89,6 @@ class PangeaRichTextState extends State<PangeaRichText> {
if (repEvent == null) { if (repEvent == null) {
setState(() => _fetchingRepresentation = true); setState(() => _fetchingRepresentation = true);
widget.pangeaMessageEvent widget.pangeaMessageEvent
.representationByLanguageGlobal( .representationByLanguageGlobal(
langCode: widget.pangeaMessageEvent.messageDisplayLangCode, langCode: widget.pangeaMessageEvent.messageDisplayLangCode,
@ -95,23 +99,17 @@ class PangeaRichTextState extends State<PangeaRichText> {
) )
.then((event) { .then((event) {
repEvent = event; repEvent = event;
widget.toolbarController?.toolbar?.textSelection.setMessageText( _setTextSpan(repEvent?.text ?? widget.pangeaMessageEvent.body);
repEvent?.text ?? widget.pangeaMessageEvent.body,
);
}).whenComplete(() { }).whenComplete(() {
if (mounted) { if (mounted) {
setState(() => _fetchingRepresentation = false); setState(() => _fetchingRepresentation = false);
} }
}); });
return widget.pangeaMessageEvent.body;
_setTextSpan(widget.pangeaMessageEvent.body);
} else { } else {
widget.toolbarController?.toolbar?.textSelection.setMessageText( _setTextSpan(repEvent!.text);
repEvent!.text,
);
setState(() {});
} }
return repEvent!.text;
} }
@override @override
@ -190,7 +188,10 @@ class PangeaRichTextState extends State<PangeaRichText> {
return blur > 0 return blur > 0
? ImageFiltered( ? ImageFiltered(
imageFilter: ImageFilter.blur(sigmaX: blur, sigmaY: blur), imageFilter: ImageFilter.blur(
sigmaX: blur,
sigmaY: blur,
),
child: richText, child: richText,
) )
: richText; : richText;

@ -314,6 +314,23 @@ class PartOfSpeechBlock extends StatelessWidget {
required this.languageType, required this.languageType,
}); });
String get exampleSentence => languageType == LanguageType.target
? wordData.targetExampleSentence
: wordData.baseExampleSentence;
String get definition => languageType == LanguageType.target
? wordData.targetDefinition
: wordData.baseDefinition;
String formattedTitle(BuildContext context) {
final String word = languageType == LanguageType.target
? wordData.targetWord
: wordData.baseWord;
String? pos = wordData.formattedPartOfSpeech(languageType);
if (pos == null || pos.isEmpty) pos = L10n.of(context)!.unkDisplayName;
return "$word (${wordData.formattedPartOfSpeech(languageType)})";
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return Padding(
@ -324,9 +341,7 @@ class PartOfSpeechBlock extends StatelessWidget {
Align( Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
languageType == LanguageType.target formattedTitle(context),
? "${wordData.targetWord} (${wordData.formattedPartOfSpeech(languageType)})"
: "${wordData.baseWord} (${wordData.formattedPartOfSpeech(languageType)})",
style: BotStyle.text(context, italics: true, bold: false), style: BotStyle.text(context, italics: true, bold: false),
), ),
), ),
@ -337,47 +352,43 @@ class PartOfSpeechBlock extends StatelessWidget {
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Column( child: Column(
children: [ children: [
RichText( if (definition.isNotEmpty)
text: TextSpan( RichText(
style: BotStyle.text( text: TextSpan(
context, style: BotStyle.text(
italics: false, context,
bold: false, italics: false,
), bold: false,
children: <TextSpan>[
TextSpan(
text: "${L10n.of(context)!.definition}: ",
style: const TextStyle(fontWeight: FontWeight.bold),
),
TextSpan(
text: languageType == LanguageType.target
? wordData.targetDefinition
: wordData.baseDefinition,
), ),
], children: <TextSpan>[
TextSpan(
text: "${L10n.of(context)!.definition}: ",
style: const TextStyle(fontWeight: FontWeight.bold),
),
TextSpan(text: definition),
],
),
), ),
),
const SizedBox(height: 10), const SizedBox(height: 10),
RichText( if (exampleSentence.isNotEmpty)
text: TextSpan( RichText(
style: BotStyle.text( text: TextSpan(
context, style: BotStyle.text(
italics: false, context,
bold: false, italics: false,
), bold: false,
children: <TextSpan>[
TextSpan(
text: "${L10n.of(context)!.exampleSentence}: ",
style: const TextStyle(fontWeight: FontWeight.bold),
), ),
TextSpan( children: <TextSpan>[
text: languageType == LanguageType.target TextSpan(
? wordData.targetExampleSentence text: "${L10n.of(context)!.exampleSentence}: ",
: wordData.baseExampleSentence, style: const TextStyle(
), fontWeight: FontWeight.bold,
], ),
),
TextSpan(text: exampleSentence),
],
),
), ),
),
], ],
), ),
), ),

@ -1,19 +1,19 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/models/language_model.dart'; import 'package:fluffychat/pangea/models/language_model.dart';
import 'package:fluffychat/pangea/pages/settings_learning/settings_learning.dart';
import 'package:fluffychat/widgets/matrix.dart'; import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import '../flag.dart'; import '../flag.dart';
import 'p_language_dialog.dart';
//PTODO - move this to settings_learning_view.dart and make callback a setState //PTODO - move this to settings_learning_view.dart and make callback a setState
class LanguageTile extends StatelessWidget { class LanguageTile extends StatelessWidget {
final SettingsLearningController learningController;
final PangeaController pangeaController = MatrixState.pangeaController; final PangeaController pangeaController = MatrixState.pangeaController;
LanguageTile({super.key}); LanguageTile(this.learningController, {super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -81,7 +81,9 @@ class LanguageTile extends StatelessWidget {
], ],
), ),
trailing: const Icon(Icons.edit_outlined), trailing: const Icon(Icons.edit_outlined),
onTap: () => pLanguageDialog(context, () {}), onTap: () async {
learningController.changeLanguage();
},
); );
} }
} }

@ -15,7 +15,7 @@ import '../../../widgets/matrix.dart';
import 'p_language_dropdown.dart'; import 'p_language_dropdown.dart';
import 'p_question_container.dart'; import 'p_question_container.dart';
pLanguageDialog(BuildContext parentContext, Function callback) { pLanguageDialog(BuildContext parentContext, Function callback) async {
final PangeaController pangeaController = MatrixState.pangeaController; final PangeaController pangeaController = MatrixState.pangeaController;
//PTODO: if source language not set by user, default to languge from device settings //PTODO: if source language not set by user, default to languge from device settings
final LanguageModel? userL1 = pangeaController.languageController.userL1; final LanguageModel? userL1 = pangeaController.languageController.userL1;

@ -83,19 +83,22 @@ class ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
], ],
), ),
), ),
PopupMenuItem<String>( // #Pangea
value: 'leave', if (!widget.room.isArchived)
child: Row( // Pangea#
children: [ PopupMenuItem<String>(
// #Pangea value: 'leave',
// const Icon(Icons.delete_outlined), child: Row(
const Icon(Icons.arrow_forward), children: [
// Pangea# // #Pangea
const SizedBox(width: 12), // const Icon(Icons.delete_outlined),
Text(L10n.of(context)!.leave), const Icon(Icons.arrow_forward),
], // Pangea#
const SizedBox(width: 12),
Text(L10n.of(context)!.leave),
],
),
), ),
),
// #Pangea // #Pangea
if (classSettings != null) if (classSettings != null)
PopupMenuItem<String>( PopupMenuItem<String>(

Loading…
Cancel
Save