Merge branch 'main' into language-detect-api
This commit is contained in:
commit
20853ef547
28 changed files with 256 additions and 134 deletions
|
|
@ -232,20 +232,26 @@ abstract class AppRoutes {
|
|||
pageBuilder: (context, state) => defaultPageBuilder(
|
||||
context,
|
||||
state,
|
||||
const NewGroup(),
|
||||
NewGroup(
|
||||
// #Pangea
|
||||
spaceId: state.uri.queryParameters['spaceId'],
|
||||
// Pangea#
|
||||
),
|
||||
),
|
||||
redirect: loggedOutRedirect,
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: ':spaceid',
|
||||
pageBuilder: (context, state) => defaultPageBuilder(
|
||||
context,
|
||||
state,
|
||||
const NewGroup(),
|
||||
),
|
||||
redirect: loggedOutRedirect,
|
||||
),
|
||||
],
|
||||
// #Pangea
|
||||
// routes: [
|
||||
// GoRoute(
|
||||
// path: ':spaceid',
|
||||
// pageBuilder: (context, state) => defaultPageBuilder(
|
||||
// context,
|
||||
// state,
|
||||
// const NewGroup(),
|
||||
// ),
|
||||
// redirect: loggedOutRedirect,
|
||||
// ),
|
||||
// ],
|
||||
// Pangea#
|
||||
),
|
||||
GoRoute(
|
||||
path: 'newspace',
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
import 'package:flutter/material.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:future_loading_dialog/future_loading_dialog.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/pages/archive/archive_view.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class Archive extends StatefulWidget {
|
||||
const Archive({super.key});
|
||||
|
||||
|
|
@ -20,7 +19,12 @@ class ArchiveController extends State<Archive> {
|
|||
|
||||
Future<List<Room>> getArchive(BuildContext context) async {
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -1078,6 +1078,9 @@ class ChatController extends State<ChatPageWithRoom>
|
|||
bool get canEditSelectedEvents {
|
||||
if (isArchived ||
|
||||
selectedEvents.length != 1 ||
|
||||
// #Pangea
|
||||
selectedEvents.single.messageType != MessageTypes.Text ||
|
||||
// Pangea#
|
||||
!selectedEvents.first.status.isSent) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,7 +116,8 @@ class ChatView extends StatelessWidget {
|
|||
// #Pangea
|
||||
} else {
|
||||
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
|
||||
final bool immersionMode;
|
||||
final ToolbarDisplayController? toolbarController;
|
||||
final bool isOverlay;
|
||||
// Pangea#
|
||||
|
||||
const MessageContent(
|
||||
|
|
@ -50,6 +51,7 @@ class MessageContent extends StatelessWidget {
|
|||
this.pangeaMessageEvent,
|
||||
required this.immersionMode,
|
||||
required this.toolbarController,
|
||||
this.isOverlay = false,
|
||||
// Pangea#
|
||||
required this.borderRadius,
|
||||
});
|
||||
|
|
@ -203,7 +205,8 @@ class MessageContent extends StatelessWidget {
|
|||
&&
|
||||
!(pangeaMessageEvent?.showRichText(
|
||||
selected,
|
||||
toolbarController?.highlighted ?? false,
|
||||
isOverlay: isOverlay,
|
||||
highlighted: toolbarController?.highlighted ?? false,
|
||||
) ??
|
||||
false)
|
||||
// Pangea#
|
||||
|
|
@ -305,7 +308,8 @@ class MessageContent extends StatelessWidget {
|
|||
);
|
||||
if (pangeaMessageEvent?.showRichText(
|
||||
selected,
|
||||
toolbarController?.highlighted ?? false,
|
||||
isOverlay: isOverlay,
|
||||
highlighted: toolbarController?.highlighted ?? false,
|
||||
) ??
|
||||
false) {
|
||||
return PangeaRichText(
|
||||
|
|
|
|||
|
|
@ -237,6 +237,10 @@ class _SpaceViewState extends State<SpaceView> {
|
|||
icon: Icons.send_outlined,
|
||||
),
|
||||
if (spaceChild != null &&
|
||||
// #Pangea
|
||||
room != null &&
|
||||
room.ownPowerLevel >= ClassDefaultValues.powerLevelOfAdmin &&
|
||||
// Pangea#
|
||||
(activeSpace?.canChangeStateEvent(EventTypes.spaceChild) ?? false))
|
||||
SheetAction(
|
||||
key: SpaceChildContextAction.removeFromSpace,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,9 @@ class StartChatFloatingActionButton extends StatelessWidget {
|
|||
void _onPressed(BuildContext context) async {
|
||||
//#Pangea
|
||||
if (controller.activeSpaceId != null) {
|
||||
context.go('/rooms/newgroup/${controller.activeSpaceId ?? ''}');
|
||||
context.go(
|
||||
'/rooms/newgroup${controller.activeSpaceId != null ? '?spaceId=${controller.activeSpaceId}' : ''}',
|
||||
);
|
||||
return;
|
||||
}
|
||||
//Pangea#
|
||||
|
|
@ -44,7 +46,9 @@ class StartChatFloatingActionButton extends StatelessWidget {
|
|||
case ActiveFilter.groups:
|
||||
// #Pangea
|
||||
// context.go('/rooms/newgroup');
|
||||
context.go('/rooms/newgroup/${controller.activeSpaceId ?? ''}');
|
||||
context.go(
|
||||
'/rooms/newgroup${controller.activeSpaceId != null ? '?spaceId=${controller.activeSpaceId}' : ''}',
|
||||
);
|
||||
// Pangea#
|
||||
break;
|
||||
case ActiveFilter.spaces:
|
||||
|
|
|
|||
|
|
@ -17,7 +17,14 @@ import 'package:go_router/go_router.dart';
|
|||
import 'package:matrix/matrix.dart' as sdk;
|
||||
|
||||
class NewGroup extends StatefulWidget {
|
||||
const NewGroup({super.key});
|
||||
// #Pangea
|
||||
final String? spaceId;
|
||||
|
||||
const NewGroup({
|
||||
super.key,
|
||||
this.spaceId,
|
||||
});
|
||||
// Pangea#
|
||||
|
||||
@override
|
||||
NewGroupController createState() => NewGroupController();
|
||||
|
|
@ -50,7 +57,7 @@ class NewGroupController extends State<NewGroup> {
|
|||
void setVocab(List<Lemma> vocab) => setState(() => chatTopic.vocab = vocab);
|
||||
|
||||
String? get activeSpaceId =>
|
||||
GoRouterState.of(context).pathParameters['spaceid'];
|
||||
GoRouterState.of(context).uri.queryParameters['spaceId'];
|
||||
// Pangea#
|
||||
|
||||
void setPublicGroup(bool b) => setState(() => publicGroup = b);
|
||||
|
|
|
|||
|
|
@ -57,6 +57,9 @@ class NewGroupView extends StatelessWidget {
|
|||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
// #Pangea
|
||||
maxLength: 32,
|
||||
// Pangea#
|
||||
controller: controller.nameController,
|
||||
autocorrect: false,
|
||||
readOnly: controller.loading,
|
||||
|
|
|
|||
|
|
@ -95,6 +95,9 @@ class NewSpaceView extends StatelessWidget {
|
|||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
// #Pangea
|
||||
maxLength: 32,
|
||||
// Pangea#
|
||||
controller: controller.nameController,
|
||||
autocorrect: false,
|
||||
readOnly: controller.loading,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@ class SettingsController extends State<Settings> {
|
|||
cancelLabel: L10n.of(context)!.cancel,
|
||||
textFields: [
|
||||
DialogTextField(
|
||||
// #Pangea
|
||||
maxLength: 32,
|
||||
// Pangea#
|
||||
initialText: profile?.displayName ??
|
||||
Matrix.of(context).client.userID!.localpart,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
enum MessageMode { translation, definition, speechToText, textToSpeech }
|
||||
|
||||
|
|
@ -52,4 +53,17 @@ extension MessageModeExtension on MessageMode {
|
|||
.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;
|
||||
}
|
||||
if (room != null && !room.isRoomAdmin) {
|
||||
return false;
|
||||
}
|
||||
if (!pangeaCanSendEvent(EventTypes.spaceChild) && !isRoomAdmin) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,18 +80,26 @@ class PangeaMessageEvent {
|
|||
return _latestEdit;
|
||||
}
|
||||
|
||||
bool showRichText(bool selected, bool highlighted) {
|
||||
bool showRichText(
|
||||
bool selected, {
|
||||
bool highlighted = false,
|
||||
bool isOverlay = false,
|
||||
}) {
|
||||
if (!_isValidPangeaMessageEvent) {
|
||||
return false;
|
||||
}
|
||||
// if (URLFinder.getMatches(event.body).isNotEmpty) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
if ([EventStatus.error, EventStatus.sending].contains(_event.status)) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import 'dart:developer';
|
|||
import 'package:fluffychat/pangea/extensions/pangea_event_extension.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/speech_to_text_models.dart';
|
||||
import 'package:fluffychat/pangea/models/tokens_event_content_model.dart';
|
||||
import 'package:fluffychat/pangea/repo/tokens_repo.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
|
@ -27,15 +26,12 @@ class RepresentationEvent {
|
|||
ChoreoRecord? _choreo;
|
||||
Timeline timeline;
|
||||
|
||||
SpeechToTextModel? _speechToTextResponse;
|
||||
|
||||
RepresentationEvent({
|
||||
required this.timeline,
|
||||
Event? event,
|
||||
PangeaRepresentation? content,
|
||||
PangeaMessageTokens? tokens,
|
||||
ChoreoRecord? choreo,
|
||||
SpeechToTextModel? speechToTextResponse,
|
||||
}) {
|
||||
if (event != null && event.type != PangeaEventTypes.representation) {
|
||||
throw Exception(
|
||||
|
|
@ -46,7 +42,6 @@ class RepresentationEvent {
|
|||
_content = content;
|
||||
_tokens = tokens;
|
||||
_choreo = choreo;
|
||||
_speechToTextResponse = speechToTextResponse;
|
||||
}
|
||||
|
||||
Event? get event => _event;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/constants/model_keys.dart';
|
||||
import 'package:fluffychat/pangea/widgets/igc/word_data_card.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
class WordData {
|
||||
final String word;
|
||||
|
|
@ -102,10 +101,11 @@ class WordData {
|
|||
}) =>
|
||||
word == w && userL1 == l1 && userL2 == l2 && fullText == f;
|
||||
|
||||
String formattedPartOfSpeech(LanguageType languageType) {
|
||||
String? formattedPartOfSpeech(LanguageType languageType) {
|
||||
final String pos = languageType == LanguageType.base
|
||||
? basePartOfSpeech
|
||||
: targetPartOfSpeech;
|
||||
if (pos.isEmpty) return null;
|
||||
return pos[0].toUpperCase() + pos.substring(1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/controllers/pangea_controller.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:flutter/material.dart';
|
||||
|
||||
class SettingsLearning extends StatefulWidget {
|
||||
const SettingsLearning({super.key});
|
||||
|
|
@ -32,6 +32,11 @@ class SettingsLearningController extends State<SettingsLearning> {
|
|||
});
|
||||
}
|
||||
|
||||
Future<void> changeLanguage() async {
|
||||
await pLanguageDialog(context, () {});
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class SettingsLearningView extends StatelessWidget {
|
|||
withScrolling: true,
|
||||
child: Column(
|
||||
children: [
|
||||
LanguageTile(),
|
||||
LanguageTile(controller),
|
||||
CountryPickerTile(),
|
||||
const SizedBox(height: 8),
|
||||
const Divider(height: 1),
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ void setClassDisplayname(BuildContext context, String? roomId) async {
|
|||
: L10n.of(context)!.changeTheNameOfTheChat,
|
||||
),
|
||||
content: TextField(
|
||||
maxLength: 32,
|
||||
controller: textFieldController,
|
||||
),
|
||||
actions: [
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ class MessageSpeechToTextCardState extends State<MessageSpeechToTextCard> {
|
|||
}
|
||||
|
||||
String? get wordsPerMinuteString =>
|
||||
speechToTextResponse?.transcript.wordsPerMinute?.toString();
|
||||
speechToTextResponse?.transcript.wordsPerMinute?.toStringAsFixed(2);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
|||
|
|
@ -134,8 +134,11 @@ class ToolbarDisplayController {
|
|||
});
|
||||
}
|
||||
|
||||
bool get highlighted =>
|
||||
MatrixState.pAnyState.overlay.hashCode.toString() == overlayId;
|
||||
bool get highlighted {
|
||||
if (overlayId == null) return false;
|
||||
if (MatrixState.pAnyState.overlay == null) overlayId = null;
|
||||
return MatrixState.pAnyState.overlay.hashCode.toString() == overlayId;
|
||||
}
|
||||
}
|
||||
|
||||
class MessageToolbar extends StatefulWidget {
|
||||
|
|
@ -172,6 +175,19 @@ class MessageToolbarState extends State<MessageToolbar> {
|
|||
debugPrint("updating toolbar mode");
|
||||
final bool subscribed =
|
||||
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(() {
|
||||
currentMode = newMode;
|
||||
updatingMode = true;
|
||||
|
|
@ -274,12 +290,14 @@ class MessageToolbarState extends State<MessageToolbar> {
|
|||
PLocalKey.autoPlayMessages,
|
||||
) ??
|
||||
true;
|
||||
|
||||
if (widget.pangeaMessageEvent.isAudioMessage) {
|
||||
updateMode(MessageMode.speechToText);
|
||||
return;
|
||||
}
|
||||
|
||||
autoplay
|
||||
? updateMode(
|
||||
widget.pangeaMessageEvent.isAudioMessage
|
||||
? MessageMode.speechToText
|
||||
: MessageMode.textToSpeech,
|
||||
)
|
||||
? updateMode(MessageMode.textToSpeech)
|
||||
: updateMode(MessageMode.translation);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ class OverlayMessage extends StatelessWidget {
|
|||
pangeaMessageEvent: pangeaMessageEvent,
|
||||
immersionMode: immersionMode,
|
||||
toolbarController: toolbarController,
|
||||
isOverlay: true,
|
||||
),
|
||||
if (event.hasAggregatedEvents(
|
||||
timeline,
|
||||
|
|
|
|||
|
|
@ -235,8 +235,13 @@ class AddToSpaceState extends State<AddToSpaceToggles> {
|
|||
),
|
||||
activeColor: AppConfig.activeToggleColor,
|
||||
value: isSuggestedInSpace(possibleParent),
|
||||
onChanged: (bool suggest) =>
|
||||
setSuggested(suggest, possibleParent),
|
||||
onChanged: (bool suggest) => canAdd
|
||||
? setSuggested(suggest, possibleParent)
|
||||
: ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(L10n.of(context)!.noPermission),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Container(),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -48,28 +48,33 @@ class PangeaRichTextState extends State<PangeaRichText> {
|
|||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
updateTextSpan();
|
||||
}
|
||||
|
||||
void updateTextSpan() {
|
||||
setState(() {
|
||||
textSpan = getTextSpan();
|
||||
});
|
||||
setTextSpan();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(PangeaRichText oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
updateTextSpan();
|
||||
setTextSpan();
|
||||
}
|
||||
|
||||
String getTextSpan() {
|
||||
void _setTextSpan(String newTextSpan) {
|
||||
widget.toolbarController?.toolbar?.textSelection.setMessageText(
|
||||
newTextSpan,
|
||||
);
|
||||
setState(() {
|
||||
textSpan = newTextSpan;
|
||||
});
|
||||
}
|
||||
|
||||
void setTextSpan() {
|
||||
if (_fetchingRepresentation == true) {
|
||||
return widget.pangeaMessageEvent.body;
|
||||
_setTextSpan(textSpan = widget.pangeaMessageEvent.body);
|
||||
return;
|
||||
}
|
||||
|
||||
if (repEvent != null) {
|
||||
return repEvent!.text;
|
||||
_setTextSpan(repEvent!.text);
|
||||
return;
|
||||
}
|
||||
|
||||
if (widget.pangeaMessageEvent.eventId.contains("webdebug")) {
|
||||
|
|
@ -84,7 +89,6 @@ class PangeaRichTextState extends State<PangeaRichText> {
|
|||
|
||||
if (repEvent == null) {
|
||||
setState(() => _fetchingRepresentation = true);
|
||||
|
||||
widget.pangeaMessageEvent
|
||||
.representationByLanguageGlobal(
|
||||
langCode: widget.pangeaMessageEvent.messageDisplayLangCode,
|
||||
|
|
@ -95,23 +99,17 @@ class PangeaRichTextState extends State<PangeaRichText> {
|
|||
)
|
||||
.then((event) {
|
||||
repEvent = event;
|
||||
widget.toolbarController?.toolbar?.textSelection.setMessageText(
|
||||
repEvent?.text ?? widget.pangeaMessageEvent.body,
|
||||
);
|
||||
_setTextSpan(repEvent?.text ?? widget.pangeaMessageEvent.body);
|
||||
}).whenComplete(() {
|
||||
if (mounted) {
|
||||
setState(() => _fetchingRepresentation = false);
|
||||
}
|
||||
});
|
||||
return widget.pangeaMessageEvent.body;
|
||||
} else {
|
||||
widget.toolbarController?.toolbar?.textSelection.setMessageText(
|
||||
repEvent!.text,
|
||||
);
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
return repEvent!.text;
|
||||
_setTextSpan(widget.pangeaMessageEvent.body);
|
||||
} else {
|
||||
_setTextSpan(repEvent!.text);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -190,7 +188,10 @@ class PangeaRichTextState extends State<PangeaRichText> {
|
|||
|
||||
return blur > 0
|
||||
? ImageFiltered(
|
||||
imageFilter: ImageFilter.blur(sigmaX: blur, sigmaY: blur),
|
||||
imageFilter: ImageFilter.blur(
|
||||
sigmaX: blur,
|
||||
sigmaY: blur,
|
||||
),
|
||||
child: richText,
|
||||
)
|
||||
: richText;
|
||||
|
|
|
|||
|
|
@ -314,6 +314,23 @@ class PartOfSpeechBlock extends StatelessWidget {
|
|||
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
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
|
|
@ -324,9 +341,7 @@ class PartOfSpeechBlock extends StatelessWidget {
|
|||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
languageType == LanguageType.target
|
||||
? "${wordData.targetWord} (${wordData.formattedPartOfSpeech(languageType)})"
|
||||
: "${wordData.baseWord} (${wordData.formattedPartOfSpeech(languageType)})",
|
||||
formattedTitle(context),
|
||||
style: BotStyle.text(context, italics: true, bold: false),
|
||||
),
|
||||
),
|
||||
|
|
@ -337,47 +352,43 @@ class PartOfSpeechBlock extends StatelessWidget {
|
|||
alignment: Alignment.centerLeft,
|
||||
child: Column(
|
||||
children: [
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
style: BotStyle.text(
|
||||
context,
|
||||
italics: false,
|
||||
bold: false,
|
||||
if (definition.isNotEmpty)
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
style: BotStyle.text(
|
||||
context,
|
||||
italics: false,
|
||||
bold: false,
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: "${L10n.of(context)!.definition}: ",
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
TextSpan(text: definition),
|
||||
],
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: "${L10n.of(context)!.definition}: ",
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
TextSpan(
|
||||
text: languageType == LanguageType.target
|
||||
? wordData.targetDefinition
|
||||
: wordData.baseDefinition,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
style: BotStyle.text(
|
||||
context,
|
||||
italics: false,
|
||||
bold: false,
|
||||
if (exampleSentence.isNotEmpty)
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
style: BotStyle.text(
|
||||
context,
|
||||
italics: false,
|
||||
bold: false,
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: "${L10n.of(context)!.exampleSentence}: ",
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
TextSpan(text: exampleSentence),
|
||||
],
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: "${L10n.of(context)!.exampleSentence}: ",
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
TextSpan(
|
||||
text: languageType == LanguageType.target
|
||||
? wordData.targetExampleSentence
|
||||
: wordData.baseExampleSentence,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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/models/language_model.dart';
|
||||
import 'package:fluffychat/pangea/pages/settings_learning/settings_learning.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import '../flag.dart';
|
||||
import 'p_language_dialog.dart';
|
||||
|
||||
//PTODO - move this to settings_learning_view.dart and make callback a setState
|
||||
|
||||
class LanguageTile extends StatelessWidget {
|
||||
final SettingsLearningController learningController;
|
||||
final PangeaController pangeaController = MatrixState.pangeaController;
|
||||
|
||||
LanguageTile({super.key});
|
||||
LanguageTile(this.learningController, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -81,7 +81,9 @@ class LanguageTile extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
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_question_container.dart';
|
||||
|
||||
pLanguageDialog(BuildContext parentContext, Function callback) {
|
||||
pLanguageDialog(BuildContext parentContext, Function callback) async {
|
||||
final PangeaController pangeaController = MatrixState.pangeaController;
|
||||
//PTODO: if source language not set by user, default to languge from device settings
|
||||
final LanguageModel? userL1 = pangeaController.languageController.userL1;
|
||||
|
|
|
|||
|
|
@ -83,19 +83,22 @@ class ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
|
|||
],
|
||||
),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
value: 'leave',
|
||||
child: Row(
|
||||
children: [
|
||||
// #Pangea
|
||||
// const Icon(Icons.delete_outlined),
|
||||
const Icon(Icons.arrow_forward),
|
||||
// Pangea#
|
||||
const SizedBox(width: 12),
|
||||
Text(L10n.of(context)!.leave),
|
||||
],
|
||||
// #Pangea
|
||||
if (!widget.room.isArchived)
|
||||
// Pangea#
|
||||
PopupMenuItem<String>(
|
||||
value: 'leave',
|
||||
child: Row(
|
||||
children: [
|
||||
// #Pangea
|
||||
// const Icon(Icons.delete_outlined),
|
||||
const Icon(Icons.arrow_forward),
|
||||
// Pangea#
|
||||
const SizedBox(width: 12),
|
||||
Text(L10n.of(context)!.leave),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
// #Pangea
|
||||
if (classSettings != null)
|
||||
PopupMenuItem<String>(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue