merge main, resolve conflicts
This commit is contained in:
commit
14bed0f430
26 changed files with 284 additions and 92 deletions
|
|
@ -4233,5 +4233,9 @@
|
|||
"reportContentIssueTitle": "Report content issue",
|
||||
"feedback": "Optional feedback",
|
||||
"reportContentIssueDescription": "Uh oh! AI can faciliate personalized learning experiences but... also hallucinates. Please provide any feedback you have and we'll try again.",
|
||||
"clickTheWordAgainToDeselect": "Click the selected word to deselect it."
|
||||
"clickTheWordAgainToDeselect": "Click the selected word to deselect it.",
|
||||
"l2SupportNa": "Not Available",
|
||||
"l2SupportAlpha": "Alpha",
|
||||
"l2SupportBeta": "Beta",
|
||||
"l2SupportFull": "Full"
|
||||
}
|
||||
|
|
@ -470,6 +470,14 @@ class ChatController extends State<ChatPageWithRoom>
|
|||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
// #Pangea
|
||||
// On iOS, if the toolbar is open and the app is closed, then the user goes
|
||||
// back to do more toolbar activities, the toolbar buttons / selection don't
|
||||
// update properly. So, when the user closes the app, close the toolbar overlay.
|
||||
if (state == AppLifecycleState.paused) {
|
||||
clearSelectedEvents();
|
||||
}
|
||||
// Pangea#
|
||||
if (state != AppLifecycleState.resumed) return;
|
||||
setReadMarker();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -391,18 +391,19 @@ class AudioPlayerState extends State<AudioPlayerWidget> {
|
|||
// #Pangea
|
||||
// const SizedBox(width: 8),
|
||||
const SizedBox(width: 5),
|
||||
// SizedBox(
|
||||
// width: 36,
|
||||
// child:
|
||||
// Pangea#
|
||||
SizedBox(
|
||||
width: 36,
|
||||
child: Text(
|
||||
statusText,
|
||||
style: TextStyle(
|
||||
color: widget.color,
|
||||
fontSize: 12,
|
||||
),
|
||||
Text(
|
||||
statusText,
|
||||
style: TextStyle(
|
||||
color: widget.color,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
// #Pangea
|
||||
// ),
|
||||
// const SizedBox(width: 8),
|
||||
// Badge(
|
||||
// isLabelVisible: audioPlayer != null,
|
||||
|
|
|
|||
|
|
@ -384,9 +384,12 @@ class _SpaceViewState extends State<SpaceView> {
|
|||
} else {
|
||||
roomId = await client.createGroupChat(
|
||||
groupName: names.first,
|
||||
preset: activeSpace.joinRules == JoinRules.public
|
||||
? CreateRoomPreset.publicChat
|
||||
: CreateRoomPreset.privateChat,
|
||||
// #Pangea
|
||||
// preset: activeSpace.joinRules == JoinRules.public
|
||||
// ? CreateRoomPreset.publicChat
|
||||
// : CreateRoomPreset.privateChat,
|
||||
preset: CreateRoomPreset.publicChat,
|
||||
// Pangea#
|
||||
visibility: activeSpace.joinRules == JoinRules.public
|
||||
? sdk.Visibility.public
|
||||
: sdk.Visibility.private,
|
||||
|
|
|
|||
|
|
@ -152,9 +152,12 @@ class NewSpaceController extends State<NewSpace> {
|
|||
avatarUrl ??= avatar == null ? null : await client.uploadContent(avatar);
|
||||
|
||||
final spaceId = await client.createRoom(
|
||||
preset: publicGroup
|
||||
? sdk.CreateRoomPreset.publicChat
|
||||
: sdk.CreateRoomPreset.privateChat,
|
||||
// #Pangea
|
||||
// preset: publicGroup
|
||||
// ? sdk.CreateRoomPreset.publicChat
|
||||
// : sdk.CreateRoomPreset.privateChat,
|
||||
preset: sdk.CreateRoomPreset.publicChat,
|
||||
// Pangea#
|
||||
creationContent: {'type': RoomCreationTypes.mSpace},
|
||||
visibility: publicGroup ? sdk.Visibility.public : null,
|
||||
// #Pangea
|
||||
|
|
|
|||
|
|
@ -255,7 +255,12 @@ class UserBottomSheetController extends State<UserBottomSheet> {
|
|||
sendError = null;
|
||||
});
|
||||
try {
|
||||
final roomId = await client.startDirectChat(userId);
|
||||
final roomId = await client.startDirectChat(
|
||||
userId,
|
||||
// #Pangea
|
||||
enableEncryption: false,
|
||||
// Pangea#
|
||||
);
|
||||
if (!mounted) return;
|
||||
final room = client.getRoomById(roomId);
|
||||
if (room == null) {
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ class IgcController {
|
|||
return;
|
||||
}
|
||||
|
||||
choreographer.chatController.inputFocus.unfocus();
|
||||
OverlayUtil.showPositionedCard(
|
||||
context: context,
|
||||
cardToShow: SpanCard(
|
||||
|
|
@ -124,8 +125,8 @@ class IgcController {
|
|||
),
|
||||
roomId: choreographer.roomId,
|
||||
),
|
||||
maxHeight: match.isITStart ? 260 : 400,
|
||||
maxWidth: match.isITStart ? 350 : 400,
|
||||
maxHeight: match.isITStart ? 260 : 350,
|
||||
maxWidth: 350,
|
||||
transformTargetId: choreographer.inputTransformTargetKey,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -308,6 +308,8 @@ class ITChoices extends StatelessWidget {
|
|||
);
|
||||
return;
|
||||
}
|
||||
|
||||
controller.choreographer.chatController.inputFocus.unfocus();
|
||||
OverlayUtil.showPositionedCard(
|
||||
context: context,
|
||||
cardToShow: choiceFeedback == null
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
class BotMode {
|
||||
static const direct = "direct";
|
||||
static const discussion = "discussion";
|
||||
static const custom = "custom";
|
||||
static const storyGame = "story_game";
|
||||
|
|
|
|||
|
|
@ -27,7 +27,9 @@ class PangeaLanguage {
|
|||
static Future<void> initialize() async {
|
||||
try {
|
||||
_langList = await _getCachedFlags();
|
||||
if (await _shouldFetch || _langList.isEmpty) {
|
||||
if (await _shouldFetch ||
|
||||
_langList.isEmpty ||
|
||||
_langList.every((lang) => !lang.l2)) {
|
||||
_langList = await LanguageRepo.fetchLanguages();
|
||||
|
||||
await _saveFlags(_langList);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import 'package:fluffychat/pangea/controllers/subscription_controller.dart';
|
|||
import 'package:fluffychat/pangea/controllers/text_to_speech_controller.dart';
|
||||
import 'package:fluffychat/pangea/controllers/user_controller.dart';
|
||||
import 'package:fluffychat/pangea/controllers/word_net_controller.dart';
|
||||
import 'package:fluffychat/pangea/extensions/client_extension/client_extension.dart';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart';
|
||||
import 'package:fluffychat/pangea/guard/p_vguard.dart';
|
||||
import 'package:fluffychat/pangea/utils/bot_name.dart';
|
||||
|
|
@ -193,19 +192,53 @@ class PangeaController {
|
|||
void startChatWithBotIfNotPresent() {
|
||||
Future.delayed(const Duration(milliseconds: 10000), () async {
|
||||
// check if user is logged in
|
||||
if (!matrixState.client.isLogged() ||
|
||||
(await matrixState.client.hasBotDM)) {
|
||||
if (!matrixState.client.isLogged()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await matrixState.client.startDirectChat(
|
||||
BotName.byEnvironment,
|
||||
enableEncryption: false,
|
||||
);
|
||||
} catch (err, stack) {
|
||||
debugger(when: kDebugMode);
|
||||
ErrorHandler.logError(e: err, s: stack);
|
||||
const List<Room> botDMs = [];
|
||||
for (final room in matrixState.client.rooms) {
|
||||
if (await room.isBotDM) {
|
||||
botDMs.add(room);
|
||||
}
|
||||
}
|
||||
|
||||
if (botDMs.isEmpty) {
|
||||
try {
|
||||
await matrixState.client.startDirectChat(
|
||||
BotName.byEnvironment,
|
||||
enableEncryption: false,
|
||||
);
|
||||
} catch (err, stack) {
|
||||
debugger(when: kDebugMode);
|
||||
ErrorHandler.logError(e: err, s: stack);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final Room botDMWithLatestActivity = botDMs.reduce((a, b) {
|
||||
if (a.timeline == null || b.timeline == null) {
|
||||
return a;
|
||||
}
|
||||
final aLastEvent = a.timeline!.events.last;
|
||||
final bLastEvent = b.timeline!.events.last;
|
||||
return aLastEvent.originServerTs.isAfter(bLastEvent.originServerTs)
|
||||
? a
|
||||
: b;
|
||||
});
|
||||
|
||||
for (final room in botDMs) {
|
||||
if (room.id != botDMWithLatestActivity.id) {
|
||||
await room.leave();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
final participants = await botDMWithLatestActivity.requestParticipants();
|
||||
final joinedParticipants =
|
||||
participants.where((e) => e.membership == Membership.join).toList();
|
||||
if (joinedParticipants.length < 2) {
|
||||
await botDMWithLatestActivity.invite(BotName.byEnvironment);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,6 +118,11 @@ class PracticeGenerationController {
|
|||
requestModel: req,
|
||||
);
|
||||
|
||||
if (res.finished) {
|
||||
debugPrint('Activity generation finished');
|
||||
return null;
|
||||
}
|
||||
|
||||
// if the server points to an existing event, return that event
|
||||
if (res.existingActivityEventId != null) {
|
||||
final Event? existingEvent =
|
||||
|
|
|
|||
98
lib/pangea/enum/l2_support_enum.dart
Normal file
98
lib/pangea/enum/l2_support_enum.dart
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
enum L2SupportEnum {
|
||||
na,
|
||||
alpha,
|
||||
beta,
|
||||
full,
|
||||
}
|
||||
|
||||
extension L2SupportEnumExtension on L2SupportEnum {
|
||||
String get storageString {
|
||||
switch (this) {
|
||||
case L2SupportEnum.na:
|
||||
return 'na';
|
||||
case L2SupportEnum.alpha:
|
||||
return 'alpha';
|
||||
case L2SupportEnum.beta:
|
||||
return 'beta';
|
||||
case L2SupportEnum.full:
|
||||
return 'full';
|
||||
}
|
||||
}
|
||||
|
||||
L2SupportEnum fromStorageString(String storageString) {
|
||||
switch (storageString) {
|
||||
case 'na':
|
||||
case 'L2SupportEnum.na':
|
||||
return L2SupportEnum.na;
|
||||
case 'alpha':
|
||||
case 'L2SupportEnum.alpha':
|
||||
return L2SupportEnum.alpha;
|
||||
case 'beta':
|
||||
case 'L2SupportEnum.beta':
|
||||
return L2SupportEnum.beta;
|
||||
case 'full':
|
||||
case 'L2SupportEnum.full':
|
||||
return L2SupportEnum.full;
|
||||
default:
|
||||
throw Exception('Unknown L2SupportEnum storage string: $storageString');
|
||||
}
|
||||
}
|
||||
|
||||
String toLocalizedString(BuildContext context) {
|
||||
final l10n = L10n.of(context)!;
|
||||
|
||||
switch (this) {
|
||||
case L2SupportEnum.na:
|
||||
return l10n.l2SupportNa;
|
||||
case L2SupportEnum.alpha:
|
||||
return l10n.l2SupportAlpha;
|
||||
case L2SupportEnum.beta:
|
||||
return l10n.l2SupportBeta;
|
||||
case L2SupportEnum.full:
|
||||
return l10n.l2SupportFull;
|
||||
}
|
||||
}
|
||||
|
||||
Badge toBadge(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
Color color;
|
||||
String label;
|
||||
|
||||
switch (this) {
|
||||
case L2SupportEnum.na:
|
||||
color = theme.colorScheme.onSurface.withOpacity(0.4); // Muted grey
|
||||
label = toLocalizedString(context);
|
||||
break;
|
||||
case L2SupportEnum.alpha:
|
||||
color = theme.colorScheme.primary.withOpacity(0.4); // Subtle primary
|
||||
label = toLocalizedString(context);
|
||||
break;
|
||||
case L2SupportEnum.beta:
|
||||
color =
|
||||
theme.colorScheme.secondary.withOpacity(0.4); // Subtle secondary
|
||||
label = toLocalizedString(context);
|
||||
break;
|
||||
case L2SupportEnum.full:
|
||||
color = theme.colorScheme.tertiary.withOpacity(0.4); // Subtle tertiary
|
||||
label = toLocalizedString(context);
|
||||
break;
|
||||
}
|
||||
|
||||
return Badge(
|
||||
label: Text(
|
||||
label,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: theme.colorScheme.onSurface.withOpacity(0.8), // Dimmed text
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
backgroundColor: color,
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
smallSize: 20, // A smaller badge for subtlety
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import 'dart:developer';
|
|||
|
||||
import 'package:adaptive_dialog/adaptive_dialog.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:fluffychat/pangea/constants/bot_mode.dart';
|
||||
import 'package:fluffychat/pangea/constants/class_default_values.dart';
|
||||
import 'package:fluffychat/pangea/constants/language_constants.dart';
|
||||
import 'package:fluffychat/pangea/constants/model_keys.dart';
|
||||
|
|
@ -253,7 +254,7 @@ extension PangeaRoom on Room {
|
|||
|
||||
// bool isMadeForLang(String langCode) => _isMadeForLang(langCode);
|
||||
|
||||
Future<bool> get isBotRoom async => await _isBotRoom;
|
||||
Future<bool> get botIsInRoom async => await _botIsInRoom;
|
||||
|
||||
Future<bool> get isBotDM async => await _isBotDM;
|
||||
|
||||
|
|
|
|||
|
|
@ -49,15 +49,14 @@ extension RoomInformationRoomExtension on Room {
|
|||
// creationContent?.tryGet<String>(ModelKey.oldLangCode) == langCode;
|
||||
// }
|
||||
|
||||
Future<bool> get _isBotRoom async {
|
||||
Future<bool> get _botIsInRoom async {
|
||||
final List<User> participants = await requestParticipants();
|
||||
return participants.any(
|
||||
(User user) => user.id == BotName.byEnvironment,
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> get _isBotDM async =>
|
||||
(await isBotRoom) && getParticipants().length == 2;
|
||||
Future<bool> get _isBotDM async => botOptions?.mode == BotMode.direct;
|
||||
|
||||
bool get _isLocked {
|
||||
if (isDirectChat) return false;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:fluffychat/pangea/constants/language_constants.dart';
|
||||
import 'package:fluffychat/pangea/enum/l2_support_enum.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
|
@ -12,15 +13,15 @@ class LanguageModel {
|
|||
final String languageFlag;
|
||||
final String displayName;
|
||||
final String? languageEmoji;
|
||||
final bool l2;
|
||||
final bool l1;
|
||||
final L2SupportEnum l2Support;
|
||||
|
||||
LanguageModel({
|
||||
required this.langCode,
|
||||
required this.languageFlag,
|
||||
required this.displayName,
|
||||
required this.l2,
|
||||
required this.l1,
|
||||
this.l2Support = L2SupportEnum.na,
|
||||
this.languageEmoji,
|
||||
});
|
||||
|
||||
|
|
@ -37,9 +38,11 @@ class LanguageModel {
|
|||
displayName: _LanguageLocal.getDisplayName(
|
||||
code != LanguageKeys.unknownLanguage ? code : json['language_name'],
|
||||
),
|
||||
l2: json["l2"] ?? code.contains("es") || code.contains("en"),
|
||||
l1: json["l1"] ?? !code.contains("es") && !code.contains("en"),
|
||||
languageEmoji: json['language_emoji'],
|
||||
l2Support: json['l2_support'] != null
|
||||
? L2SupportEnum.na.fromStorageString(json['l2_support'])
|
||||
: L2SupportEnum.na,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -47,11 +50,13 @@ class LanguageModel {
|
|||
'language_code': langCode,
|
||||
'language_name': displayName,
|
||||
'language_flag': languageFlag,
|
||||
'l2': l2,
|
||||
'l1': l1,
|
||||
'language_emoji': languageEmoji,
|
||||
'l2_support': l2Support.storageString,
|
||||
};
|
||||
|
||||
bool get l2 => l2Support != L2SupportEnum.na;
|
||||
|
||||
// Discuss with Jordan - adding langCode field to language objects as separate from displayName
|
||||
static String codeFromNameOrCode(String codeOrName, [String? url]) {
|
||||
if (codeOrName.isEmpty) return LanguageKeys.unknownLanguage;
|
||||
|
|
@ -73,7 +78,6 @@ class LanguageModel {
|
|||
langCode: LanguageKeys.unknownLanguage,
|
||||
languageFlag: "",
|
||||
displayName: "Unknown",
|
||||
l2: false,
|
||||
l1: false,
|
||||
);
|
||||
|
||||
|
|
@ -81,16 +85,12 @@ class LanguageModel {
|
|||
displayName: context != null
|
||||
? L10n.of(context)!.multiLingualSpace
|
||||
: "Multilingual Space",
|
||||
l2: false,
|
||||
l1: false,
|
||||
langCode: LanguageKeys.multiLanguage,
|
||||
languageFlag: 'assets/colors.png',
|
||||
languageEmoji: "🌎",
|
||||
);
|
||||
|
||||
// Discuss with Jordan
|
||||
bool get hasContextualDefinitionSupport => l2;
|
||||
|
||||
String? getDisplayName(BuildContext context) {
|
||||
switch (langCode) {
|
||||
case 'ab':
|
||||
|
|
|
|||
|
|
@ -156,6 +156,20 @@ class ActivityQualityFeedback {
|
|||
'bad_activity': badActivity.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other is ActivityQualityFeedback &&
|
||||
other.feedbackText == feedbackText &&
|
||||
other.badActivity == badActivity;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return feedbackText.hashCode ^ badActivity.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
class MessageActivityRequest {
|
||||
|
|
@ -231,7 +245,9 @@ class MessageActivityRequest {
|
|||
|
||||
@override
|
||||
int get hashCode {
|
||||
return messageId.hashCode ^ const ListEquality().hash(tokensWithXP);
|
||||
return messageId.hashCode ^
|
||||
const ListEquality().hash(tokensWithXP) ^
|
||||
activityQualityFeedback.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -234,6 +234,7 @@ class LanguageSelectionRow extends StatelessWidget {
|
|||
targetLanguage: isSource ? null : language,
|
||||
);
|
||||
},
|
||||
isL2List: !isSource,
|
||||
initialLanguage: isSource
|
||||
? controller.sourceLanguageSearch
|
||||
: controller.targetLanguageSearch,
|
||||
|
|
|
|||
|
|
@ -40,13 +40,15 @@ class InlineTooltip extends StatelessWidget {
|
|||
const SizedBox(width: 8),
|
||||
// Text in the middle
|
||||
Expanded(
|
||||
child: Text(
|
||||
instructionsEnum.body(context),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
height: 1.5,
|
||||
child: Center(
|
||||
child: Text(
|
||||
instructionsEnum.body(context),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
height: 1.5,
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
),
|
||||
// Close button on the right
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import 'package:flutter/material.dart';
|
|||
|
||||
const double minCardHeight = 70;
|
||||
|
||||
class MessageToolbar extends StatefulWidget {
|
||||
class MessageToolbar extends StatelessWidget {
|
||||
final PangeaMessageEvent pangeaMessageEvent;
|
||||
final MessageOverlayController overLayController;
|
||||
|
||||
|
|
@ -29,55 +29,45 @@ class MessageToolbar extends StatefulWidget {
|
|||
required this.overLayController,
|
||||
});
|
||||
|
||||
@override
|
||||
MessageToolbarState createState() => MessageToolbarState();
|
||||
}
|
||||
|
||||
class MessageToolbarState extends State<MessageToolbar> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
Widget get toolbarContent {
|
||||
final bool subscribed =
|
||||
MatrixState.pangeaController.subscriptionController.isSubscribed;
|
||||
|
||||
if (!subscribed) {
|
||||
return MessageUnsubscribedCard(
|
||||
controller: widget.overLayController,
|
||||
controller: overLayController,
|
||||
);
|
||||
}
|
||||
|
||||
switch (widget.overLayController.toolbarMode) {
|
||||
switch (overLayController.toolbarMode) {
|
||||
case MessageMode.translation:
|
||||
return MessageTranslationCard(
|
||||
messageEvent: widget.pangeaMessageEvent,
|
||||
selection: widget.overLayController.selectedSpan,
|
||||
messageEvent: pangeaMessageEvent,
|
||||
selection: overLayController.selectedSpan,
|
||||
);
|
||||
case MessageMode.textToSpeech:
|
||||
return MessageAudioCard(
|
||||
messageEvent: widget.pangeaMessageEvent,
|
||||
overlayController: widget.overLayController,
|
||||
messageEvent: pangeaMessageEvent,
|
||||
overlayController: overLayController,
|
||||
);
|
||||
case MessageMode.speechToText:
|
||||
return MessageSpeechToTextCard(
|
||||
messageEvent: widget.pangeaMessageEvent,
|
||||
messageEvent: pangeaMessageEvent,
|
||||
);
|
||||
case MessageMode.definition:
|
||||
if (!widget.overLayController.isSelection) {
|
||||
if (!overLayController.isSelection) {
|
||||
return const SelectToDefine();
|
||||
} else {
|
||||
try {
|
||||
final selectedText = widget.overLayController.targetText;
|
||||
final selectedText = overLayController.targetText;
|
||||
|
||||
return WordDataCard(
|
||||
word: selectedText,
|
||||
wordLang: widget.pangeaMessageEvent.messageDisplayLangCode,
|
||||
fullText: widget.pangeaMessageEvent.messageDisplayText,
|
||||
fullTextLang: widget.pangeaMessageEvent.messageDisplayLangCode,
|
||||
wordLang: pangeaMessageEvent.messageDisplayLangCode,
|
||||
fullText: pangeaMessageEvent.messageDisplayText,
|
||||
fullTextLang: pangeaMessageEvent.messageDisplayLangCode,
|
||||
hasInfo: true,
|
||||
room: widget.overLayController.widget.chatController.room,
|
||||
room: overLayController.widget.chatController.room,
|
||||
);
|
||||
} catch (e, s) {
|
||||
debugger(when: kDebugMode);
|
||||
|
|
@ -85,8 +75,8 @@ class MessageToolbarState extends State<MessageToolbar> {
|
|||
e: "Error in WordDataCard",
|
||||
s: s,
|
||||
data: {
|
||||
"word": widget.overLayController.targetText,
|
||||
"fullText": widget.pangeaMessageEvent.messageDisplayText,
|
||||
"word": overLayController.targetText,
|
||||
"fullText": pangeaMessageEvent.messageDisplayText,
|
||||
},
|
||||
);
|
||||
return const SizedBox();
|
||||
|
|
@ -94,30 +84,25 @@ class MessageToolbarState extends State<MessageToolbar> {
|
|||
}
|
||||
case MessageMode.practiceActivity:
|
||||
return PracticeActivityCard(
|
||||
pangeaMessageEvent: widget.pangeaMessageEvent,
|
||||
overlayController: widget.overLayController,
|
||||
pangeaMessageEvent: pangeaMessageEvent,
|
||||
overlayController: overLayController,
|
||||
);
|
||||
default:
|
||||
debugger(when: kDebugMode);
|
||||
ErrorHandler.logError(
|
||||
e: "Invalid toolbar mode",
|
||||
s: StackTrace.current,
|
||||
data: {"newMode": widget.overLayController.toolbarMode},
|
||||
data: {"newMode": overLayController.toolbarMode},
|
||||
);
|
||||
return const SizedBox();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
key: MatrixState.pAnyState
|
||||
.layerLinkAndKey('${widget.pangeaMessageEvent.eventId}-toolbar')
|
||||
.layerLinkAndKey('${pangeaMessageEvent.eventId}-toolbar')
|
||||
.key,
|
||||
type: MaterialType.transparency,
|
||||
child: Row(
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ class ConversationBotSettingsState extends State<ConversationBotSettings> {
|
|||
botOptions = widget.room?.botOptions != null
|
||||
? BotOptionsModel.fromJson(widget.room?.botOptions?.toJson())
|
||||
: BotOptionsModel();
|
||||
widget.room?.isBotRoom.then((bool isBotRoom) {
|
||||
widget.room?.botIsInRoom.then((bool isBotRoom) {
|
||||
setState(() {
|
||||
addBot = isBotRoom;
|
||||
});
|
||||
|
|
@ -260,7 +260,7 @@ class ConversationBotSettingsState extends State<ConversationBotSettings> {
|
|||
botOptions = botOptions;
|
||||
});
|
||||
final bool isBotRoomMember =
|
||||
await widget.room?.isBotRoom ?? false;
|
||||
await widget.room?.botIsInRoom ?? false;
|
||||
if (addBot && !isBotRoomMember) {
|
||||
await widget.room?.invite(BotName.byEnvironment);
|
||||
} else if (!addBot && isBotRoomMember) {
|
||||
|
|
|
|||
|
|
@ -231,6 +231,10 @@ class MessagePracticeActivityCardState extends State<PracticeActivityCard> {
|
|||
return;
|
||||
}
|
||||
|
||||
// clear the current activity and record
|
||||
currentActivity = null;
|
||||
currentCompletionRecord = null;
|
||||
|
||||
_fetchNewActivity(
|
||||
ActivityQualityFeedback(
|
||||
feedbackText: feedback,
|
||||
|
|
@ -248,12 +252,13 @@ class MessagePracticeActivityCardState extends State<PracticeActivityCard> {
|
|||
'record': currentCompletionRecord,
|
||||
},
|
||||
);
|
||||
|
||||
// clear the current activity and record
|
||||
currentActivity = null;
|
||||
currentCompletionRecord = null;
|
||||
|
||||
widget.overlayController.exitPracticeFlow();
|
||||
});
|
||||
|
||||
// clear the current activity and record
|
||||
currentActivity = null;
|
||||
currentCompletionRecord = null;
|
||||
}
|
||||
|
||||
RepresentationEvent? get representation =>
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ Future<void> pLanguageDialog(
|
|||
setState(() => selectedSourceLanguage = p0),
|
||||
initialLanguage: selectedSourceLanguage,
|
||||
languages: pangeaController.pLanguageStore.baseOptions,
|
||||
isL2List: false,
|
||||
),
|
||||
PQuestionContainer(
|
||||
title: L10n.of(parentContext)!.whatLanguageYouWantToLearn,
|
||||
|
|
@ -72,6 +73,7 @@ Future<void> pLanguageDialog(
|
|||
setState(() => selectedTargetLanguage = p0),
|
||||
initialLanguage: selectedTargetLanguage,
|
||||
languages: pangeaController.pLanguageStore.targetOptions,
|
||||
isL2List: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
// Flutter imports:
|
||||
|
||||
import 'package:fluffychat/pangea/enum/l2_support_enum.dart';
|
||||
import 'package:fluffychat/pangea/models/language_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
|
@ -10,6 +11,7 @@ class PLanguageDropdown extends StatefulWidget {
|
|||
final LanguageModel initialLanguage;
|
||||
final Function(LanguageModel) onChange;
|
||||
final bool showMultilingual;
|
||||
final bool isL2List;
|
||||
|
||||
const PLanguageDropdown({
|
||||
super.key,
|
||||
|
|
@ -17,6 +19,7 @@ class PLanguageDropdown extends StatefulWidget {
|
|||
required this.onChange,
|
||||
required this.initialLanguage,
|
||||
this.showMultilingual = false,
|
||||
required this.isL2List,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -98,6 +101,7 @@ class _PLanguageDropdownState extends State<PLanguageDropdown> {
|
|||
value: LanguageModel.multiLingual(context),
|
||||
child: LanguageDropDownEntry(
|
||||
languageModel: LanguageModel.multiLingual(context),
|
||||
isL2List: widget.isL2List,
|
||||
),
|
||||
),
|
||||
...sortedLanguages.map(
|
||||
|
|
@ -105,6 +109,7 @@ class _PLanguageDropdownState extends State<PLanguageDropdown> {
|
|||
value: languageModel,
|
||||
child: LanguageDropDownEntry(
|
||||
languageModel: languageModel,
|
||||
isL2List: widget.isL2List,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -118,9 +123,11 @@ class _PLanguageDropdownState extends State<PLanguageDropdown> {
|
|||
|
||||
class LanguageDropDownEntry extends StatelessWidget {
|
||||
final LanguageModel languageModel;
|
||||
final bool isL2List;
|
||||
const LanguageDropDownEntry({
|
||||
super.key,
|
||||
required this.languageModel,
|
||||
required this.isL2List,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -144,6 +151,9 @@ class LanguageDropDownEntry extends StatelessWidget {
|
|||
overflow: TextOverflow.clip,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
if (isL2List && languageModel.l2Support != L2SupportEnum.full)
|
||||
languageModel.l2Support.toBadge(context),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,11 @@ extension IsStateExtension on Event {
|
|||
(isState || !AppConfig.hideAllStateEvents) &&
|
||||
// #Pangea
|
||||
content.tryGet(ModelKey.transcription) == null &&
|
||||
// if sending of transcription fails,
|
||||
// don't show it as a errored audio event in timeline.
|
||||
((unsigned?['extra_content']
|
||||
as Map<String, dynamic>?)?[ModelKey.transcription] ==
|
||||
null) &&
|
||||
// hide unimportant state events
|
||||
(!AppConfig.hideUnimportantStateEvents ||
|
||||
!isState ||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ description: Learn a language while texting your friends.
|
|||
# Pangea#
|
||||
publish_to: none
|
||||
# On version bump also increase the build number for F-Droid
|
||||
version: 1.21.4+3539
|
||||
version: 1.21.4+3540
|
||||
|
||||
environment:
|
||||
sdk: ">=3.0.0 <4.0.0"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue