Merge branch 'main' into sentry
This commit is contained in:
commit
a4c346b07c
33 changed files with 344 additions and 170 deletions
|
|
@ -4303,6 +4303,7 @@
|
|||
"grammarCopyAccDat": "Accusative, Dative",
|
||||
"grammarCopyInf": "Infinitive",
|
||||
"grammarCopyLong": "Long",
|
||||
"grammarCopyLoc": "Locative",
|
||||
"grammarCopyInd": "Indicative",
|
||||
"grammarCopyCmp": "Comparative",
|
||||
"grammarCopyRelative_case": "Relative Case",
|
||||
|
|
|
|||
|
|
@ -4962,6 +4962,7 @@
|
|||
"grammarCopyAccDat": "Acusativo, Dativo",
|
||||
"grammarCopyInf": "Infinitivo",
|
||||
"grammarCopyLong": "Largo",
|
||||
"grammarCopyLoc": "Locativa",
|
||||
"grammarCopyInd": "Indicativo",
|
||||
"grammarCopyCmp": "Comparativa",
|
||||
"grammarCopyRelative_case": "Caso relativo",
|
||||
|
|
@ -5008,4 +5009,4 @@
|
|||
"spaceCapacityNotSet": "Este espacio no tiene límite de capacidad.",
|
||||
"chatExceedsCapacity": "Este chat supera su capacidad.",
|
||||
"spaceExceedsCapacity": "Este espacio supera su capacidad."
|
||||
}
|
||||
}
|
||||
|
|
@ -691,6 +691,7 @@ class ChatController extends State<ChatPageWithRoom>
|
|||
metadata: metadata,
|
||||
)),
|
||||
],
|
||||
origin: AnalyticsUpdateOrigin.sendMessage,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:animations/animations.dart';
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/widgets/send_button.dart';
|
||||
import 'package:fluffychat/pangea/constants/language_constants.dart';
|
||||
import 'package:fluffychat/utils/platform_infos.dart';
|
||||
|
|
@ -299,11 +298,12 @@ class ChatInputRow extends StatelessWidget {
|
|||
maxLines: 8,
|
||||
autofocus: !PlatformInfos.isMobile,
|
||||
keyboardType: TextInputType.multiline,
|
||||
textInputAction: AppConfig.sendOnEnter == true &&
|
||||
PlatformInfos.isMobile
|
||||
? TextInputAction.send
|
||||
: null,
|
||||
// #Pangea
|
||||
// textInputAction: AppConfig.sendOnEnter == true &&
|
||||
// PlatformInfos.isMobile
|
||||
// ? TextInputAction.send
|
||||
// : null,
|
||||
textInputAction: TextInputAction.send,
|
||||
// onSubmitted: controller.onInputBarSubmitted,
|
||||
onSubmitted: (String value) =>
|
||||
controller.onInputBarSubmitted(value, context),
|
||||
|
|
@ -336,36 +336,36 @@ class ChatInputRow extends StatelessWidget {
|
|||
height: height,
|
||||
width: height,
|
||||
alignment: Alignment.center,
|
||||
child: PlatformInfos.platformCanRecord &&
|
||||
controller.sendController.text.isEmpty
|
||||
? FloatingActionButton.small(
|
||||
tooltip: L10n.of(context)!.voiceMessage,
|
||||
onPressed: controller.voiceMessageAction,
|
||||
elevation: 0,
|
||||
heroTag: null,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(height),
|
||||
),
|
||||
backgroundColor: theme.colorScheme.primary,
|
||||
foregroundColor: theme.colorScheme.onPrimary,
|
||||
child: const Icon(Icons.mic_none_outlined),
|
||||
)
|
||||
:
|
||||
child:
|
||||
// #Pangea
|
||||
// PlatformInfos.platformCanRecord &&
|
||||
// controller.sendController.text.isEmpty
|
||||
// ? FloatingActionButton.small(
|
||||
// tooltip: L10n.of(context)!.voiceMessage,
|
||||
// onPressed: controller.voiceMessageAction,
|
||||
// elevation: 0,
|
||||
// heroTag: null,
|
||||
// shape: RoundedRectangleBorder(
|
||||
// borderRadius: BorderRadius.circular(height),
|
||||
// ),
|
||||
// backgroundColor: theme.colorScheme.primary,
|
||||
// foregroundColor: theme.colorScheme.onPrimary,
|
||||
// child: const Icon(Icons.mic_none_outlined),
|
||||
// )
|
||||
// : FloatingActionButton.small(
|
||||
// tooltip: L10n.of(context)!.send,
|
||||
// onPressed: controller.send,
|
||||
// elevation: 0,
|
||||
// heroTag: null,
|
||||
// shape: RoundedRectangleBorder(
|
||||
// borderRadius: BorderRadius.circular(height),
|
||||
// ),
|
||||
// backgroundColor:
|
||||
// theme.colorScheme.onPrimaryContainer,
|
||||
// foregroundColor: theme.colorScheme.onPrimary,
|
||||
// child: const Icon(Icons.send_outlined),
|
||||
// ),
|
||||
ChoreographerSendButton(controller: controller),
|
||||
// FloatingActionButton.small(
|
||||
// tooltip: L10n.of(context)!.send,
|
||||
// onPressed: controller.send,
|
||||
// elevation: 0,
|
||||
// heroTag: null,
|
||||
// shape: RoundedRectangleBorder(
|
||||
// borderRadius: BorderRadius.circular(height),
|
||||
// ),
|
||||
// backgroundColor:
|
||||
// theme.colorScheme.onPrimaryContainer,
|
||||
// foregroundColor: theme.colorScheme.onPrimary,
|
||||
// child: const Icon(Icons.send_outlined),
|
||||
// ),
|
||||
// Pangea#
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import 'package:fluffychat/pages/chat/pinned_events.dart';
|
|||
import 'package:fluffychat/pages/chat/reply_display.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/widgets/it_bar.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/widgets/start_igc_button.dart';
|
||||
import 'package:fluffychat/pangea/controllers/my_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart';
|
||||
import 'package:fluffychat/pangea/widgets/animations/gain_points.dart';
|
||||
import 'package:fluffychat/pangea/widgets/chat/chat_floating_action_button.dart';
|
||||
|
|
@ -454,6 +455,8 @@ class ChatView extends StatelessWidget {
|
|||
gainColor: Theme.of(context)
|
||||
.colorScheme
|
||||
.onPrimary,
|
||||
origin: AnalyticsUpdateOrigin
|
||||
.sendMessage,
|
||||
),
|
||||
const SizedBox(width: 100),
|
||||
ChatFloatingActionButton(
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import 'package:fluffychat/pangea/pages/class_settings/class_name_header.dart';
|
|||
import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_description_button.dart';
|
||||
import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_details_toggle_add_students_tile.dart';
|
||||
import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_invitation_buttons.dart';
|
||||
import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_name_button.dart';
|
||||
import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/room_capacity_button.dart';
|
||||
import 'package:fluffychat/pangea/utils/lock_room.dart';
|
||||
import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings.dart';
|
||||
|
|
@ -213,11 +212,6 @@ class ChatDetailsView extends StatelessWidget {
|
|||
),
|
||||
Divider(color: theme.dividerColor),
|
||||
// #Pangea
|
||||
if (room.isRoomAdmin)
|
||||
ClassNameButton(
|
||||
room: room,
|
||||
controller: controller,
|
||||
),
|
||||
if (room.canSendEvent('m.room.topic'))
|
||||
ClassDescriptionButton(
|
||||
room: room,
|
||||
|
|
|
|||
|
|
@ -68,7 +68,12 @@ class Choreographer {
|
|||
}
|
||||
|
||||
void send(BuildContext context) {
|
||||
if (!canSendMessage) return;
|
||||
if (!canSendMessage) {
|
||||
if (igc.igcTextData != null) {
|
||||
igc.showFirstMatch(context);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (pangeaController.subscriptionController.subscriptionStatus ==
|
||||
SubscriptionStatus.showPaywall) {
|
||||
|
|
@ -84,7 +89,7 @@ class Choreographer {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!igc.hasRelevantIGCTextData) {
|
||||
if (!igc.hasRelevantIGCTextData && !itController.dismissed) {
|
||||
getLanguageHelp().then((value) => _sendWithIGC(context));
|
||||
} else {
|
||||
_sendWithIGC(context);
|
||||
|
|
@ -201,7 +206,8 @@ class Choreographer {
|
|||
return;
|
||||
}
|
||||
|
||||
if (_textController.editType == EditType.igc) {
|
||||
if (_textController.editType == EditType.igc ||
|
||||
_textController.editType == EditType.itDismissed) {
|
||||
_lastChecked = _textController.text;
|
||||
_textController.editType = EditType.keyboard;
|
||||
return;
|
||||
|
|
@ -603,7 +609,9 @@ class Choreographer {
|
|||
if (isFetching) return false;
|
||||
|
||||
// they're supposed to run IGC but haven't yet, don't let them send
|
||||
if (isAutoIGCEnabled && igc.igcTextData == null) return false;
|
||||
if (igc.igcTextData == null) {
|
||||
return itController.dismissed;
|
||||
}
|
||||
|
||||
// if they have relevant matches, don't let them send
|
||||
final hasITMatches =
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ import 'dart:developer';
|
|||
|
||||
import 'package:fluffychat/pangea/choreographer/controllers/error_service.dart';
|
||||
import 'package:fluffychat/pangea/constants/choreo_constants.dart';
|
||||
import 'package:fluffychat/pangea/controllers/my_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/enum/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/enum/edit_type.dart';
|
||||
import 'package:fluffychat/pangea/models/pangea_token_model.dart';
|
||||
import 'package:fluffychat/pangea/utils/error_handler.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
|
@ -25,6 +27,7 @@ class ITController {
|
|||
bool _willOpen = false;
|
||||
bool _isEditingSourceText = false;
|
||||
bool showChoiceFeedback = false;
|
||||
bool dismissed = false;
|
||||
|
||||
ITStartData? _itStartData;
|
||||
String? sourceText;
|
||||
|
|
@ -41,6 +44,7 @@ class ITController {
|
|||
_willOpen = false;
|
||||
showChoiceFeedback = false;
|
||||
_isEditingSourceText = false;
|
||||
dismissed = false;
|
||||
|
||||
_itStartData = null;
|
||||
sourceText = null;
|
||||
|
|
@ -70,9 +74,11 @@ class ITController {
|
|||
void closeIT() {
|
||||
// if the user hasn't gone through any IT steps, reset the text
|
||||
if (completedITSteps.isEmpty && sourceText != null) {
|
||||
choreographer.textController.editType = EditType.itDismissed;
|
||||
choreographer.textController.text = sourceText!;
|
||||
}
|
||||
clear();
|
||||
dismissed = true;
|
||||
}
|
||||
|
||||
/// if IGC isn't positive that text is full L1 then translate to L1
|
||||
|
|
@ -200,6 +206,7 @@ class ITController {
|
|||
|
||||
final ITResponseModel res =
|
||||
await _customInputTranslation(currentText + nextText);
|
||||
if (sourceText == null) return;
|
||||
|
||||
nextITStep = CurrentITStep(
|
||||
sourceText: sourceText!,
|
||||
|
|
@ -315,6 +322,7 @@ class ITController {
|
|||
ignoredTokens ?? [],
|
||||
choreographer.roomId,
|
||||
ConstructUseTypeEnum.ignIt,
|
||||
AnalyticsUpdateOrigin.it,
|
||||
);
|
||||
|
||||
Future.delayed(
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ 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/controllers/my_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/enum/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/enum/instructions_enum.dart';
|
||||
import 'package:fluffychat/pangea/utils/error_handler.dart';
|
||||
|
|
@ -80,7 +81,9 @@ class ITBarState extends State<ITBar> {
|
|||
children: [
|
||||
const Positioned(
|
||||
top: 60,
|
||||
child: PointsGainedAnimation(),
|
||||
child: PointsGainedAnimation(
|
||||
origin: AnalyticsUpdateOrigin.it,
|
||||
),
|
||||
),
|
||||
SingleChildScrollView(
|
||||
child: Column(
|
||||
|
|
@ -352,7 +355,7 @@ class ITChoices extends StatelessWidget {
|
|||
void selectContinuance(int index, BuildContext context) {
|
||||
final Continuance continuance =
|
||||
controller.currentITStep!.continuances[index];
|
||||
if (continuance.level == 1 || continuance.wasClicked) {
|
||||
if (continuance.level == 1) {
|
||||
Future.delayed(
|
||||
const Duration(milliseconds: 500),
|
||||
() => controller.selectTranslation(index),
|
||||
|
|
@ -372,6 +375,7 @@ class ITChoices extends StatelessWidget {
|
|||
continuance.level > 1
|
||||
? ConstructUseTypeEnum.incIt
|
||||
: ConstructUseTypeEnum.corIt,
|
||||
AnalyticsUpdateOrigin.it,
|
||||
);
|
||||
}
|
||||
controller.currentITStep!.continuances[index].wasClicked = true;
|
||||
|
|
|
|||
|
|
@ -56,10 +56,7 @@ class ChoreographerSendButtonState extends State<ChoreographerSendButton> {
|
|||
color: widget.controller.choreographer.assistanceState
|
||||
.stateColor(context),
|
||||
onPressed: () {
|
||||
widget.controller.choreographer.canSendMessage
|
||||
? widget.controller.choreographer.send(context)
|
||||
: widget.controller.choreographer.igc
|
||||
.showFirstMatch(context);
|
||||
widget.controller.choreographer.send(context);
|
||||
},
|
||||
tooltip: L10n.of(context)!.send,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ class GetAnalyticsController {
|
|||
late PangeaController _pangeaController;
|
||||
final List<AnalyticsCacheEntry> _cache = [];
|
||||
StreamSubscription<AnalyticsUpdate>? _analyticsUpdateSubscription;
|
||||
CachedStreamController<List<OneConstructUse>> analyticsStream =
|
||||
CachedStreamController<List<OneConstructUse>>();
|
||||
CachedStreamController<AnalyticsStreamUpdate> analyticsStream =
|
||||
CachedStreamController<AnalyticsStreamUpdate>();
|
||||
|
||||
/// The previous XP points of the user, before the last update.
|
||||
/// Used for animating analytics updates.
|
||||
|
|
@ -83,7 +83,7 @@ class GetAnalyticsController {
|
|||
_analyticsUpdateSubscription?.cancel();
|
||||
_analyticsUpdateSubscription = null;
|
||||
_cache.clear();
|
||||
analyticsStream.add([]);
|
||||
analyticsStream.add(AnalyticsStreamUpdate(constructs: []));
|
||||
prevXP = null;
|
||||
}
|
||||
|
||||
|
|
@ -92,24 +92,30 @@ class GetAnalyticsController {
|
|||
if (analyticsUpdate.type == AnalyticsUpdateType.server) {
|
||||
await getConstructs(forceUpdate: true);
|
||||
}
|
||||
updateAnalyticsStream();
|
||||
updateAnalyticsStream(origin: analyticsUpdate.origin);
|
||||
}
|
||||
|
||||
void updateAnalyticsStream() {
|
||||
void updateAnalyticsStream({AnalyticsUpdateOrigin? origin}) {
|
||||
// if there are no construct uses, or if the last update in this
|
||||
// stream has the same length as this update, don't update the stream
|
||||
if (allConstructUses.isEmpty ||
|
||||
allConstructUses.length == analyticsStream.value?.length) {
|
||||
allConstructUses.length == analyticsStream.value?.constructs.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set the previous XP to the currentXP
|
||||
if (analyticsStream.value != null && analyticsStream.value!.isNotEmpty) {
|
||||
prevXP = calcXP(analyticsStream.value!);
|
||||
if (analyticsStream.value != null &&
|
||||
analyticsStream.value!.constructs.isNotEmpty) {
|
||||
prevXP = calcXP(analyticsStream.value!.constructs);
|
||||
}
|
||||
|
||||
// finally, add to the stream
|
||||
analyticsStream.add(allConstructUses);
|
||||
analyticsStream.add(
|
||||
AnalyticsStreamUpdate(
|
||||
constructs: allConstructUses,
|
||||
origin: origin,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Calculates the user's xpPoints for their current L2,
|
||||
|
|
@ -347,3 +353,13 @@ class AnalyticsCacheEntry {
|
|||
return _createdAt.isBefore(lastEventUpdated);
|
||||
}
|
||||
}
|
||||
|
||||
class AnalyticsStreamUpdate {
|
||||
final List<OneConstructUse> constructs;
|
||||
final AnalyticsUpdateOrigin? origin;
|
||||
|
||||
AnalyticsStreamUpdate({
|
||||
required this.constructs,
|
||||
this.origin,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ class MyAnalyticsController extends BaseController<AnalyticsStream> {
|
|||
_addLocalMessage(eventID, filtered).then(
|
||||
(_) {
|
||||
_clearDraftUses(roomID);
|
||||
_decideWhetherToUpdateAnalyticsRoom(level);
|
||||
_decideWhetherToUpdateAnalyticsRoom(level, data.origin);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
|
@ -135,6 +135,7 @@ class MyAnalyticsController extends BaseController<AnalyticsStream> {
|
|||
List<PangeaToken> tokens,
|
||||
String roomID,
|
||||
ConstructUseTypeEnum useType,
|
||||
AnalyticsUpdateOrigin origin,
|
||||
) {
|
||||
final metadata = ConstructUseMetaData(
|
||||
roomId: roomID,
|
||||
|
|
@ -178,7 +179,7 @@ class MyAnalyticsController extends BaseController<AnalyticsStream> {
|
|||
|
||||
final level = _pangeaController.analytics.level;
|
||||
_addLocalMessage('draft$roomID', uses).then(
|
||||
(_) => _decideWhetherToUpdateAnalyticsRoom(level),
|
||||
(_) => _decideWhetherToUpdateAnalyticsRoom(level, origin),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -218,7 +219,10 @@ class MyAnalyticsController extends BaseController<AnalyticsStream> {
|
|||
/// If the addition brought the total number of messages in the cache
|
||||
/// to the max, or if the addition triggered a level-up, update the analytics.
|
||||
/// Otherwise, add a local update to the alert stream.
|
||||
void _decideWhetherToUpdateAnalyticsRoom(int prevLevel) {
|
||||
void _decideWhetherToUpdateAnalyticsRoom(
|
||||
int prevLevel,
|
||||
AnalyticsUpdateOrigin? origin,
|
||||
) {
|
||||
// cancel the last timer that was set on message event and
|
||||
// reset it to fire after _minutesBeforeUpdate minutes
|
||||
_updateTimer?.cancel();
|
||||
|
|
@ -238,7 +242,7 @@ class MyAnalyticsController extends BaseController<AnalyticsStream> {
|
|||
newLevel > prevLevel
|
||||
? sendLocalAnalyticsToAnalyticsRoom()
|
||||
: analyticsUpdateStream.add(
|
||||
AnalyticsUpdate(AnalyticsUpdateType.local),
|
||||
AnalyticsUpdate(AnalyticsUpdateType.local, origin: origin),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -345,6 +349,7 @@ class MyAnalyticsController extends BaseController<AnalyticsStream> {
|
|||
class AnalyticsStream {
|
||||
final String eventId;
|
||||
final String roomId;
|
||||
final AnalyticsUpdateOrigin? origin;
|
||||
|
||||
final List<OneConstructUse> constructs;
|
||||
|
||||
|
|
@ -352,12 +357,21 @@ class AnalyticsStream {
|
|||
required this.eventId,
|
||||
required this.roomId,
|
||||
required this.constructs,
|
||||
this.origin,
|
||||
});
|
||||
}
|
||||
|
||||
enum AnalyticsUpdateOrigin {
|
||||
it,
|
||||
igc,
|
||||
sendMessage,
|
||||
practiceActivity,
|
||||
}
|
||||
|
||||
class AnalyticsUpdate {
|
||||
final AnalyticsUpdateType type;
|
||||
final AnalyticsUpdateOrigin? origin;
|
||||
final bool isLogout;
|
||||
|
||||
AnalyticsUpdate(this.type, {this.isLogout = false});
|
||||
AnalyticsUpdate(this.type, {this.isLogout = false, this.origin});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
|||
import 'dart:developer';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:fluffychat/pangea/constants/bot_mode.dart';
|
||||
import 'package:fluffychat/pangea/constants/class_default_values.dart';
|
||||
import 'package:fluffychat/pangea/constants/pangea_event_types.dart';
|
||||
import 'package:fluffychat/pangea/controllers/class_controller.dart';
|
||||
|
|
@ -22,6 +23,7 @@ import 'package:fluffychat/pangea/controllers/user_controller.dart';
|
|||
import 'package:fluffychat/pangea/controllers/word_net_controller.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/models/bot_options_model.dart';
|
||||
import 'package:fluffychat/pangea/utils/bot_name.dart';
|
||||
import 'package:fluffychat/pangea/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/utils/instructions.dart';
|
||||
|
|
@ -205,15 +207,88 @@ class PangeaController {
|
|||
|
||||
if (botDMs.isEmpty) {
|
||||
try {
|
||||
await matrixState.client.startDirectChat(
|
||||
BotName.byEnvironment,
|
||||
enableEncryption: false,
|
||||
// Copied from client.dart.startDirectChat
|
||||
final directChatRoomId =
|
||||
matrixState.client.getDirectChatFromUserId(BotName.byEnvironment);
|
||||
if (directChatRoomId != null) {
|
||||
final room = matrixState.client.getRoomById(directChatRoomId);
|
||||
if (room != null) {
|
||||
if (room.membership == Membership.join) {
|
||||
return null;
|
||||
} else if (room.membership == Membership.invite) {
|
||||
// we might already have an invite into a DM room. If that is the case, we should try to join. If the room is
|
||||
// unjoinable, that will automatically leave the room, so in that case we need to continue creating a new
|
||||
// room. (This implicitly also prevents the room from being returned as a DM room by getDirectChatFromUserId,
|
||||
// because it only returns joined or invited rooms atm.)
|
||||
await room.join();
|
||||
if (room.membership != Membership.leave) {
|
||||
if (room.membership != Membership.join) {
|
||||
// Wait for room actually appears in sync with the right membership
|
||||
await matrixState.client
|
||||
.waitForRoomInSync(directChatRoomId, join: true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// enableEncryption ??=
|
||||
// encryptionEnabled && await userOwnsEncryptionKeys(mxid);
|
||||
// if (enableEncryption) {
|
||||
// initialState ??= [];
|
||||
// if (!initialState.any((s) => s.type == EventTypes.Encryption)) {
|
||||
// initialState.add(
|
||||
// StateEvent(
|
||||
// content: {
|
||||
// 'algorithm': supportedGroupEncryptionAlgorithms.first,
|
||||
// },
|
||||
// type: EventTypes.Encryption,
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
// Start a new direct chat
|
||||
final roomId = await matrixState.client.createRoom(
|
||||
invite: [], // intentionally not invite bot yet
|
||||
isDirect: true,
|
||||
preset: CreateRoomPreset.trustedPrivateChat,
|
||||
initialState: [
|
||||
BotOptionsModel(mode: BotMode.directChat).toStateEvent,
|
||||
],
|
||||
);
|
||||
|
||||
final room = matrixState.client.getRoomById(roomId);
|
||||
if (room == null || room.membership != Membership.join) {
|
||||
// Wait for room actually appears in sync
|
||||
await matrixState.client.waitForRoomInSync(roomId, join: true);
|
||||
}
|
||||
|
||||
final botOptions = room!.getState(PangeaEventTypes.botOptions);
|
||||
if (botOptions == null) {
|
||||
await matrixState.client.setRoomStateWithKey(
|
||||
roomId,
|
||||
PangeaEventTypes.botOptions,
|
||||
"",
|
||||
BotOptionsModel(mode: BotMode.directChat).toJson(),
|
||||
);
|
||||
await matrixState.client
|
||||
.getRoomStateWithKey(roomId, PangeaEventTypes.botOptions, "");
|
||||
}
|
||||
|
||||
// invite bot to direct chat
|
||||
await matrixState.client.setRoomStateWithKey(
|
||||
roomId, EventTypes.RoomMember, BotName.byEnvironment, {
|
||||
"membership": Membership.invite.name,
|
||||
"is_direct": true,
|
||||
});
|
||||
await room.addToDirectChat(BotName.byEnvironment);
|
||||
|
||||
return null;
|
||||
} catch (err, stack) {
|
||||
debugger(when: kDebugMode);
|
||||
ErrorHandler.logError(e: err, s: stack);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final Room botDMWithLatestActivity = botDMs.reduce((a, b) {
|
||||
|
|
|
|||
|
|
@ -5,4 +5,5 @@ enum EditType {
|
|||
alternativeTranslation,
|
||||
itGold,
|
||||
itStart,
|
||||
itDismissed,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@ class ConstructListModel {
|
|||
/// All unique lemmas used in the construct events
|
||||
List<String> get lemmas => constructList.map((e) => e.lemma).toSet().toList();
|
||||
|
||||
/// All unique lemmas used in the construct events with non-zero points
|
||||
List<String> get lemmasWithPoints =>
|
||||
constructListWithPoints.map((e) => e.lemma).toSet().toList();
|
||||
|
||||
/// A map of lemmas to ConstructUses, each of which contains a lemma
|
||||
/// key = lemmma + constructType.string, value = ConstructUses
|
||||
void _buildConstructMap() {
|
||||
|
|
@ -72,6 +76,9 @@ class ConstructListModel {
|
|||
return _constructList!;
|
||||
}
|
||||
|
||||
List<ConstructUses> get constructListWithPoints =>
|
||||
constructList.where((constructUse) => constructUse.points > 0).toList();
|
||||
|
||||
get maxXPPerLemma {
|
||||
return type != null
|
||||
? type!.maxXPPerLemma
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ class ClassDescriptionButton extends StatelessWidget {
|
|||
? (room.isRoomAdmin
|
||||
? (room.isSpace
|
||||
? L10n.of(context)!.classDescriptionDesc
|
||||
: L10n.of(context)!.chatTopicDesc)
|
||||
: L10n.of(context)!.setChatDescription)
|
||||
: L10n.of(context)!.topicNotSet)
|
||||
: room.topic,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import 'dart:developer';
|
|||
|
||||
import 'package:fluffychat/pangea/constants/age_limits.dart';
|
||||
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
|
||||
import 'package:fluffychat/pangea/extensions/client_extension/client_extension.dart';
|
||||
import 'package:fluffychat/pangea/pages/p_user_age/p_user_age_view.dart';
|
||||
import 'package:fluffychat/pangea/utils/p_extension.dart';
|
||||
import 'package:fluffychat/widgets/fluffy_chat_app.dart';
|
||||
|
|
@ -11,7 +10,6 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import '../../utils/bot_name.dart';
|
||||
import '../../utils/error_handler.dart';
|
||||
|
||||
class PUserAge extends StatefulWidget {
|
||||
|
|
@ -34,20 +32,7 @@ class PUserAgeController extends State<PUserAge> {
|
|||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
Future.delayed(Duration.zero, () async {
|
||||
if (!(await Matrix.of(context).client.hasBotDM)) {
|
||||
Matrix.of(context)
|
||||
.client
|
||||
.startDirectChat(
|
||||
BotName.byEnvironment,
|
||||
enableEncryption: false,
|
||||
)
|
||||
.onError(
|
||||
(error, stackTrace) =>
|
||||
ErrorHandler.logError(e: error, s: stackTrace),
|
||||
);
|
||||
}
|
||||
});
|
||||
pangeaController.startChatWithBotIfNotPresent();
|
||||
}
|
||||
|
||||
String? dobValidator() {
|
||||
|
|
|
|||
|
|
@ -41,14 +41,16 @@ class InlineTooltip extends StatelessWidget {
|
|||
),
|
||||
const SizedBox(width: 8),
|
||||
// Text in the middle
|
||||
Center(
|
||||
child: Text(
|
||||
instructionsEnum.body(L10n.of(context)!),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
height: 1.5,
|
||||
Flexible(
|
||||
child: Center(
|
||||
child: Text(
|
||||
instructionsEnum.body(L10n.of(context)!),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
height: 1.5,
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
),
|
||||
// Close button on the right
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:fluffychat/pangea/models/analytics/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/controllers/get_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/controllers/my_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/utils/bot_style.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
|
@ -8,8 +9,11 @@ import 'package:flutter/material.dart';
|
|||
class PointsGainedAnimation extends StatefulWidget {
|
||||
final Color? gainColor;
|
||||
final Color? loseColor;
|
||||
final AnalyticsUpdateOrigin origin;
|
||||
|
||||
const PointsGainedAnimation({
|
||||
super.key,
|
||||
required this.origin,
|
||||
this.gainColor,
|
||||
this.loseColor = Colors.red,
|
||||
});
|
||||
|
|
@ -69,7 +73,8 @@ class PointsGainedAnimationState extends State<PointsGainedAnimation>
|
|||
super.dispose();
|
||||
}
|
||||
|
||||
void _showPointsGained(List<OneConstructUse> constructs) {
|
||||
void _showPointsGained(AnalyticsStreamUpdate update) {
|
||||
if (update.origin != widget.origin) return;
|
||||
setState(() => _addedPoints = (_currentXP ?? 0) - (_prevXP ?? 0));
|
||||
if (_prevXP != _currentXP) {
|
||||
_controller.reset();
|
||||
|
|
|
|||
|
|
@ -40,23 +40,27 @@ class MissingVoiceButton extends StatelessWidget {
|
|||
),
|
||||
padding: const EdgeInsets.all(8),
|
||||
margin: const EdgeInsets.only(top: 8),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
L10n.of(context)!.voiceNotAvailable,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => launchTTSSettings,
|
||||
// commenting out as suspecting this is causing an issue
|
||||
// #freeze-activity
|
||||
style: const ButtonStyle(
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
child: SizedBox(
|
||||
width: AppConfig.toolbarMinWidth,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
L10n.of(context)!.voiceNotAvailable,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
child: Text(L10n.of(context)!.openVoiceSettings),
|
||||
),
|
||||
],
|
||||
TextButton(
|
||||
onPressed: () => launchTTSSettings,
|
||||
// commenting out as suspecting this is causing an issue
|
||||
// #freeze-activity
|
||||
style: const ButtonStyle(
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
child: Text(L10n.of(context)!.openVoiceSettings),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,33 +65,71 @@ class OverlayMessageTextState extends State<OverlayMessageText> {
|
|||
);
|
||||
}
|
||||
|
||||
int lastEnd = 0;
|
||||
// Convert the entire message into a list of characters
|
||||
final Characters messageCharacters =
|
||||
widget.pangeaMessageEvent.event.body.characters;
|
||||
|
||||
// When building token positions, use grapheme cluster indices
|
||||
final List<TokenPosition> tokenPositions = [];
|
||||
int globalIndex = 0;
|
||||
|
||||
for (int i = 0; i < tokens!.length; i++) {
|
||||
final token = tokens![i];
|
||||
final start = token.start;
|
||||
final end = token.end;
|
||||
|
||||
if (lastEnd < start) {
|
||||
tokenPositions.add(TokenPosition(start: lastEnd, end: start));
|
||||
// Calculate the number of grapheme clusters up to the start and end positions
|
||||
final int startIndex = messageCharacters.take(start).length;
|
||||
final int endIndex = messageCharacters.take(end).length;
|
||||
|
||||
if (globalIndex < startIndex) {
|
||||
tokenPositions.add(TokenPosition(start: globalIndex, end: startIndex));
|
||||
}
|
||||
|
||||
tokenPositions.add(
|
||||
TokenPosition(
|
||||
start: start,
|
||||
end: end,
|
||||
start: startIndex,
|
||||
end: endIndex,
|
||||
tokenIndex: i,
|
||||
token: token,
|
||||
),
|
||||
);
|
||||
lastEnd = end;
|
||||
globalIndex = endIndex;
|
||||
}
|
||||
|
||||
// debug prints for fixing words sticking together
|
||||
// void printEscapedString(String input) {
|
||||
// // Escaped string using Unicode escape sequences
|
||||
// final String escapedString = input.replaceAllMapped(
|
||||
// RegExp(r'[^\w\s]', unicode: true),
|
||||
// (match) {
|
||||
// final codeUnits = match.group(0)!.runes;
|
||||
// String unicodeEscapes = '';
|
||||
// for (final rune in codeUnits) {
|
||||
// unicodeEscapes += '\\u{${rune.toRadixString(16)}}';
|
||||
// }
|
||||
// return unicodeEscapes;
|
||||
// },
|
||||
// );
|
||||
// print("Escaped String: $escapedString");
|
||||
|
||||
// // Printing each character with its index
|
||||
// int index = 0;
|
||||
// for (final char in input.characters) {
|
||||
// print("Index $index: $char");
|
||||
// index++;
|
||||
// }
|
||||
// }
|
||||
|
||||
//TODO - take out of build function of every message
|
||||
return RichText(
|
||||
text: TextSpan(
|
||||
children: tokenPositions.map((tokenPosition) {
|
||||
final substring = messageCharacters
|
||||
.skip(tokenPosition.start)
|
||||
.take(tokenPosition.end - tokenPosition.start)
|
||||
.toString();
|
||||
|
||||
if (tokenPosition.token != null) {
|
||||
final isSelected =
|
||||
widget.overlayController.isTokenSelected(tokenPosition.token!);
|
||||
|
|
@ -106,7 +144,7 @@ class OverlayMessageTextState extends State<OverlayMessageText> {
|
|||
);
|
||||
if (mounted) setState(() {});
|
||||
},
|
||||
text: tokenPosition.token!.text.content,
|
||||
text: substring,
|
||||
style: style.merge(
|
||||
TextStyle(
|
||||
backgroundColor: isSelected
|
||||
|
|
@ -119,10 +157,7 @@ class OverlayMessageTextState extends State<OverlayMessageText> {
|
|||
);
|
||||
} else {
|
||||
return TextSpan(
|
||||
text: widget.pangeaMessageEvent.event.body.substring(
|
||||
tokenPosition.start,
|
||||
tokenPosition.end,
|
||||
),
|
||||
text: substring,
|
||||
style: style,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,11 +16,6 @@ class AnalyticsPopup extends StatelessWidget {
|
|||
super.key,
|
||||
});
|
||||
|
||||
// we just want to show the constructs that have points
|
||||
List<ConstructUses> get constructs => constructsModel.constructList
|
||||
.where((constructUse) => constructUse.points > 0)
|
||||
.toList();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
|
|
@ -41,29 +36,31 @@ class AnalyticsPopup extends StatelessWidget {
|
|||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
child: constructs.isEmpty
|
||||
child: constructsModel.constructListWithPoints.isEmpty
|
||||
? Center(
|
||||
child: Text(L10n.of(context)!.noDataFound),
|
||||
)
|
||||
: ListView.builder(
|
||||
itemCount: constructs.length,
|
||||
itemCount: constructsModel.constructListWithPoints.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Tooltip(
|
||||
message:
|
||||
"${constructs[index].points} / ${constructsModel.maxXPPerLemma}",
|
||||
"${constructsModel.constructListWithPoints[index].points} / ${constructsModel.maxXPPerLemma}",
|
||||
child: ListTile(
|
||||
onTap: () {},
|
||||
title: Text(
|
||||
constructsModel.type == ConstructTypeEnum.morph
|
||||
? getGrammarCopy(
|
||||
constructsModel
|
||||
.constructList[index].lemma,
|
||||
.constructListWithPoints[index].lemma,
|
||||
context,
|
||||
)
|
||||
: constructs[index].lemma,
|
||||
: constructsModel
|
||||
.constructListWithPoints[index].lemma,
|
||||
),
|
||||
subtitle: LinearProgressIndicator(
|
||||
value: constructs[index].points /
|
||||
value: constructsModel
|
||||
.constructListWithPoints[index].points /
|
||||
constructsModel.maxXPPerLemma,
|
||||
minHeight: 20,
|
||||
borderRadius: const BorderRadius.all(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pangea/controllers/get_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
|
||||
import 'package:fluffychat/pangea/enum/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/enum/progress_indicators_enum.dart';
|
||||
|
|
@ -37,7 +38,7 @@ class LearningProgressIndicatorsState
|
|||
|
||||
/// A stream subscription to listen for updates to
|
||||
/// the analytics data, either locally or from events
|
||||
StreamSubscription<List<OneConstructUse>>? _analyticsUpdateSubscription;
|
||||
StreamSubscription<AnalyticsStreamUpdate>? _analyticsUpdateSubscription;
|
||||
|
||||
/// Vocabulary constructs model
|
||||
ConstructListModel? words;
|
||||
|
|
@ -65,11 +66,11 @@ class LearningProgressIndicatorsState
|
|||
void initState() {
|
||||
super.initState();
|
||||
updateAnalyticsData(
|
||||
_pangeaController.analytics.analyticsStream.value ?? [],
|
||||
_pangeaController.analytics.analyticsStream.value?.constructs ?? [],
|
||||
);
|
||||
_analyticsUpdateSubscription = _pangeaController
|
||||
.analytics.analyticsStream.stream
|
||||
.listen(updateAnalyticsData);
|
||||
.listen((update) => updateAnalyticsData(update.constructs));
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -111,9 +112,9 @@ class LearningProgressIndicatorsState
|
|||
int? getProgressPoints(ProgressIndicatorEnum indicator) {
|
||||
switch (indicator) {
|
||||
case ProgressIndicatorEnum.wordsUsed:
|
||||
return words?.lemmas.length;
|
||||
return words?.lemmasWithPoints.length;
|
||||
case ProgressIndicatorEnum.morphsUsed:
|
||||
return morphs?.lemmas.length;
|
||||
return morphs?.lemmasWithPoints.length;
|
||||
case ProgressIndicatorEnum.level:
|
||||
return level;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ class ConversationBotModeDynamicZone extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final discussionChildren = [
|
||||
TextFormField(
|
||||
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
decoration: InputDecoration(
|
||||
hintText: L10n.of(context)!
|
||||
.conversationBotDiscussionZone_discussionTopicPlaceholder,
|
||||
|
|
@ -43,6 +44,7 @@ class ConversationBotModeDynamicZone extends StatelessWidget {
|
|||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
decoration: InputDecoration(
|
||||
hintText: L10n.of(context)!
|
||||
.conversationBotDiscussionZone_discussionKeywordsPlaceholder,
|
||||
|
|
@ -58,6 +60,7 @@ class ConversationBotModeDynamicZone extends StatelessWidget {
|
|||
|
||||
final customChildren = [
|
||||
TextFormField(
|
||||
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
decoration: InputDecoration(
|
||||
hintText: L10n.of(context)!
|
||||
.conversationBotCustomZone_customSystemPromptPlaceholder,
|
||||
|
|
|
|||
|
|
@ -200,27 +200,31 @@ class ConversationBotSettingsDialogState
|
|||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 20),
|
||||
AnimatedOpacity(
|
||||
duration: FluffyThemes.animationDuration,
|
||||
opacity: addBot ? 1.0 : 0.5,
|
||||
child: ConversationBotSettingsForm(
|
||||
botOptions: botOptions,
|
||||
discussionKeywordsController:
|
||||
discussionKeywordsController,
|
||||
discussionTopicController: discussionTopicController,
|
||||
customSystemPromptController:
|
||||
customSystemPromptController,
|
||||
enabled: addBot,
|
||||
onUpdateBotMode: onUpdateChatMode,
|
||||
onUpdateBotLanguage: onUpdateBotLanguage,
|
||||
onUpdateBotVoice: onUpdateBotVoice,
|
||||
onUpdateBotLanguageLevel: onUpdateBotLanguageLevel,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 20),
|
||||
AnimatedOpacity(
|
||||
duration: FluffyThemes.animationDuration,
|
||||
opacity: addBot ? 1.0 : 0.5,
|
||||
child: ConversationBotSettingsForm(
|
||||
botOptions: botOptions,
|
||||
discussionKeywordsController:
|
||||
discussionKeywordsController,
|
||||
discussionTopicController:
|
||||
discussionTopicController,
|
||||
customSystemPromptController:
|
||||
customSystemPromptController,
|
||||
enabled: addBot,
|
||||
onUpdateBotMode: onUpdateChatMode,
|
||||
onUpdateBotLanguage: onUpdateBotLanguage,
|
||||
onUpdateBotVoice: onUpdateBotVoice,
|
||||
onUpdateBotLanguageLevel: onUpdateBotLanguageLevel,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/controllers/my_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/enum/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/enum/span_data_type.dart';
|
||||
import 'package:fluffychat/pangea/models/pangea_token_model.dart';
|
||||
|
|
@ -130,6 +131,7 @@ class SpanCardState extends State<SpanCard> {
|
|||
selectedChoice!.isBestCorrection
|
||||
? ConstructUseTypeEnum.corIGC
|
||||
: ConstructUseTypeEnum.incIGC,
|
||||
AnalyticsUpdateOrigin.igc,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -160,6 +162,7 @@ class SpanCardState extends State<SpanCard> {
|
|||
ignoredTokens ?? [],
|
||||
widget.roomId,
|
||||
ConstructUseTypeEnum.ignIGC,
|
||||
AnalyticsUpdateOrigin.igc,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -226,7 +229,9 @@ class WordMatchContent extends StatelessWidget {
|
|||
children: [
|
||||
const Positioned(
|
||||
top: 40,
|
||||
child: PointsGainedAnimation(),
|
||||
child: PointsGainedAnimation(
|
||||
origin: AnalyticsUpdateOrigin.igc,
|
||||
),
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
|
|
|
|||
|
|
@ -70,7 +70,6 @@ class MultipleChoiceActivityState extends State<MultipleChoiceActivity> {
|
|||
return;
|
||||
}
|
||||
|
||||
// #freeze-activity
|
||||
MatrixState.pangeaController.myAnalytics.setState(
|
||||
AnalyticsStream(
|
||||
// note - this maybe should be the activity event id
|
||||
|
|
@ -81,6 +80,7 @@ class MultipleChoiceActivityState extends State<MultipleChoiceActivity> {
|
|||
widget.practiceCardController.currentActivity!,
|
||||
widget.practiceCardController.metadata,
|
||||
),
|
||||
origin: AnalyticsUpdateOrigin.practiceActivity,
|
||||
),
|
||||
);
|
||||
|
||||
|
|
@ -112,7 +112,6 @@ class MultipleChoiceActivityState extends State<MultipleChoiceActivity> {
|
|||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
// #freeze-activity
|
||||
if (practiceActivity.activityType ==
|
||||
ActivityTypeEnum.wordFocusListening)
|
||||
WordAudioButton(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:async';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:fluffychat/pangea/controllers/my_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
|
||||
import 'package:fluffychat/pangea/enum/activity_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart';
|
||||
|
|
@ -335,7 +336,9 @@ class PracticeActivityCardState extends State<PracticeActivityCard> {
|
|||
children: [
|
||||
// Main content
|
||||
const Positioned(
|
||||
child: PointsGainedAnimation(),
|
||||
child: PointsGainedAnimation(
|
||||
origin: AnalyticsUpdateOrigin.practiceActivity,
|
||||
),
|
||||
),
|
||||
if (activityWidget != null)
|
||||
Padding(
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@ class TargetTokensController {
|
|||
_targetTokens = await _initialize(context, pangeaMessageEvent);
|
||||
|
||||
await updateTokensWithConstructs(
|
||||
MatrixState.pangeaController.analytics.analyticsStream.value ?? [],
|
||||
MatrixState
|
||||
.pangeaController.analytics.analyticsStream.value?.constructs ??
|
||||
[],
|
||||
context,
|
||||
pangeaMessageEvent,
|
||||
);
|
||||
|
|
@ -58,9 +60,8 @@ class TargetTokensController {
|
|||
return _targetTokens = [];
|
||||
}
|
||||
|
||||
return _targetTokens = tokens
|
||||
.map((token) => token.emptyTokenWithXP)
|
||||
.toList();
|
||||
return _targetTokens =
|
||||
tokens.map((token) => token.emptyTokenWithXP).toList();
|
||||
}
|
||||
|
||||
Future<void> updateTokensWithConstructs(
|
||||
|
|
@ -76,9 +77,8 @@ class TargetTokensController {
|
|||
_targetTokens ??= await _initialize(context, pangeaMessageEvent);
|
||||
|
||||
for (final token in _targetTokens!) {
|
||||
|
||||
// we don't need to do this for tokens that don't have saveVocab set to true
|
||||
if (!token.token.lemma.saveVocab){
|
||||
if (!token.token.lemma.saveVocab) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ class WordAudioButtonState extends State<WordAudioButton> {
|
|||
}
|
||||
}, // Disable button if language isn't supported
|
||||
),
|
||||
// #freeze-activity
|
||||
widget.ttsController.missingVoiceButton,
|
||||
],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ class WordFocusListeningActivityState
|
|||
widget.practiceCardController.currentActivity!,
|
||||
widget.practiceCardController.metadata,
|
||||
),
|
||||
origin: AnalyticsUpdateOrigin.practiceActivity,
|
||||
),
|
||||
);
|
||||
setState(() {
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ packages:
|
|||
source: hosted
|
||||
version: "1.1.2"
|
||||
characters:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: characters
|
||||
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
|
||||
|
|
|
|||
|
|
@ -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.23.2+3561
|
||||
version: 1.23.3+3562
|
||||
|
||||
environment:
|
||||
sdk: ">=3.0.0 <4.0.0"
|
||||
|
|
@ -19,6 +19,7 @@ dependencies:
|
|||
badges: ^3.1.2
|
||||
blurhash_dart: ^1.2.1
|
||||
callkeep: ^0.3.2
|
||||
characters: ^1.2.0
|
||||
chewie: ^1.8.1
|
||||
collection: ^1.18.0
|
||||
cupertino_icons: any
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue