Skip to content

Commit

Permalink
Merge pull request #1025 from pangeachat/use-queue
Browse files Browse the repository at this point in the history
Use-queue
  • Loading branch information
ggurdin authored Nov 15, 2024
2 parents 1a4dc0b + c82ce34 commit 981c635
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 55 deletions.
25 changes: 19 additions & 6 deletions lib/pangea/controllers/message_analytics_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -127,15 +127,28 @@ class MessageAnalyticsEntry {
return queue.take(3).toList();
}

/// Removes the last activity from the queue
/// This should only used when there is a startingToken in practice flow
/// and we want to go down to 2 activities + the activity with the startingToken
void goDownTo2Activities() {
if (_activityQueue.isNotEmpty && _activityQueue.length > 2) {
_activityQueue.removeLast();
/// Adds a word focus listening activity to the front of the queue
/// And limits to 3 activities
void addForWordMeaning(PangeaToken selectedToken) {
_activityQueue.insert(
0,
TargetTokensAndActivityType(
tokens: [selectedToken],
activityType: ActivityTypeEnum.wordMeaning,
),
);
// remove down to three activities
if (_activityQueue.length > 3) {
_activityQueue.removeRange(3, _activityQueue.length);
}
}

int get numActivities => _activityQueue.length;

void clearActivityQueue() {
_activityQueue.clear();
}

/// Returns a hidden word activity if there is a sequence of tokens that have hiddenWordListening in their eligibleActivityTypes
TargetTokensAndActivityType? getHiddenWordActivity(int numOtherActivities) {
// don't do hidden word listening on own messages
Expand Down
39 changes: 18 additions & 21 deletions lib/pangea/widgets/chat/message_selection_overlay.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
/// The number of activities that need to be completed before the toolbar is unlocked
/// If we don't have any good activities for them, we'll decrease this number
static const int neededActivities = 3;
int activitiesLeftToComplete = neededActivities;

bool get messageInUserL2 =>
pangeaMessageEvent.messageDisplayLangCode ==
Expand Down Expand Up @@ -121,9 +120,6 @@ class MessageOverlayController extends State<MessageSelectionOverlay>

_getTokens();

activitiesLeftToComplete = activitiesLeftToComplete -
widget._pangeaMessageEvent.numberOfActivitiesCompleted;

_reactionSubscription =
widget.chatController.room.client.onSync.stream.where(
(update) {
Expand All @@ -146,7 +142,12 @@ class MessageOverlayController extends State<MessageSelectionOverlay>

tts.setupTTS();

_setInitialToolbarModeAndSelectedSpan();
if (selectedTargetTokenForWordMeaning != null) {
messageAnalyticsEntry
?.addForWordMeaning(selectedTargetTokenForWordMeaning!);
}

_setInitialToolbarMode();
}

MessageAnalyticsEntry? get messageAnalyticsEntry => tokens != null
Expand All @@ -171,7 +172,7 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
.then((tokens) {
// this isn't currently working because originalSent's _event is null
this.tokens = tokens;
_setInitialToolbarModeAndSelectedSpan();
_setInitialToolbarMode();
});
}
}
Expand Down Expand Up @@ -209,43 +210,39 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
}
}

int get activitiesLeftToComplete => messageAnalyticsEntry?.numActivities ?? 0;
bool get isPracticeComplete => activitiesLeftToComplete <= 0;

/// When an activity is completed, we need to update the state
/// and check if the toolbar should be unlocked
void onActivityFinish() {
if (!mounted) return;
activitiesLeftToComplete -= 1;
clearSelection();
setState(() {});
}

/// In some cases, we need to exit the practice flow and let the user
/// interact with the toolbar without completing activities
void exitPracticeFlow() {
messageAnalyticsEntry?.clearActivityQueue();
clearSelection();
activitiesLeftToComplete = 0;
setState(() {});
}

Future<void> _setInitialToolbarModeAndSelectedSpan() async {
Future<void> _setInitialToolbarMode() async {
if (widget._pangeaMessageEvent.isAudioMessage) {
toolbarMode = MessageMode.speechToText;
return setState(() => toolbarMode = MessageMode.practiceActivity);
}

// we're only going to do activities if we have tokens for the message
if (tokens != null) {
// if the user selects a span on initialization, then we want to give
// them a practice activity on that word
if (selectedTargetTokenForWordMeaning != null) {
_selectedSpan = selectedTargetTokenForWordMeaning?.text;
return setState(() => toolbarMode = MessageMode.practiceActivity);
}

if (activitiesLeftToComplete > 0) {
return setState(() => toolbarMode = MessageMode.practiceActivity);
}
// 1) we're only going to do activities if we have tokens for the message
// 2) if the user selects a span on initialization, then we want to give
// them a practice activity on that word
// 3) if the user has activities left to complete, then we want to give them
if (tokens != null &&
(selectedTargetTokenForWordMeaning != null ||
activitiesLeftToComplete > 0)) {
return setState(() => toolbarMode = MessageMode.practiceActivity);
}

// Note: this setting is now hidden so this will always be false
Expand Down
32 changes: 4 additions & 28 deletions lib/pangea/widgets/practice_activity/practice_activity_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@ import 'dart:async';
import 'dart:developer';

import 'package:collection/collection.dart';
import 'package:fluffychat/pangea/controllers/message_analytics_controller.dart';
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/controllers/practice_activity_generation_controller.dart';
import 'package:fluffychat/pangea/controllers/put_analytics_controller.dart';
import 'package:fluffychat/pangea/enum/activity_type_enum.dart';
import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart';
import 'package:fluffychat/pangea/matrix_event_wrappers/practice_activity_event.dart';
import 'package:fluffychat/pangea/models/analytics/constructs_model.dart';
import 'package:fluffychat/pangea/models/pangea_token_model.dart';
import 'package:fluffychat/pangea/models/practice_activities.dart/message_activity_request.dart';
import 'package:fluffychat/pangea/models/practice_activities.dart/practice_activity_model.dart';
import 'package:fluffychat/pangea/models/practice_activities.dart/practice_activity_record_model.dart';
Expand Down Expand Up @@ -55,9 +53,6 @@ class PracticeActivityCardState extends State<PracticeActivityCard> {
List<PracticeActivityEvent> get practiceActivities =>
widget.pangeaMessageEvent.practiceActivities;

// if the user has selected a token, we're going to give them an activity on that token first
late PangeaToken? startingToken;

// Used to show an animation when the user completes an activity
// while simultaneously fetching a new activity and not showing the loading spinner
// until the appropriate time has passed to 'savor the joy'
Expand Down Expand Up @@ -97,7 +92,6 @@ class PracticeActivityCardState extends State<PracticeActivityCard> {
/// Get an existing activity if there is one.
/// If not, get a new activity from the server.
Future<void> initialize() async {
startingToken = widget.overlayController.selectedTargetTokenForWordMeaning;
_setPracticeActivity(
await _fetchActivity(),
);
Expand All @@ -120,26 +114,8 @@ class PracticeActivityCardState extends State<PracticeActivityCard> {
return null;
}

// if the user selected a token which is not already in a hidden word activity,
// we're going to give them an activity on that token first
// otherwise, we're going to give them an activity on the next token in the queue
TargetTokensAndActivityType? nextActivitySpecs;
if (startingToken != null) {
// if the user selected a token, we're going to give them an activity on that token first
nextActivitySpecs = TargetTokensAndActivityType(
tokens: [startingToken!],
activityType: ActivityTypeEnum.wordMeaning,
);
// clear the starting token so that the next activity is not based on it
startingToken = null;
// we want to go down to 2 activities + the activity with the startingToken
// so we remove the last activity from the queue if there's more than 2
widget.overlayController.messageAnalyticsEntry?.goDownTo2Activities();
} else {
nextActivitySpecs =
widget.overlayController.messageAnalyticsEntry?.nextActivity;
}

final nextActivitySpecs =
widget.overlayController.messageAnalyticsEntry?.nextActivity;
// the client is going to be choosing the next activity now
// if nothing is set then it must be done with practice
if (nextActivitySpecs == null) {
Expand All @@ -151,7 +127,7 @@ class PracticeActivityCardState extends State<PracticeActivityCard> {
// check if we already have an activity matching the specs
final existingActivity = practiceActivities.firstWhereOrNull(
(activity) =>
nextActivitySpecs!.matchesActivity(activity.practiceActivity),
nextActivitySpecs.matchesActivity(activity.practiceActivity),
);
if (existingActivity != null) {
debugPrint('found existing activity');
Expand All @@ -160,7 +136,7 @@ class PracticeActivityCardState extends State<PracticeActivityCard> {
}

debugPrint(
"client requesting ${nextActivitySpecs.activityType.string} for ${nextActivitySpecs.tokens.map((t) => t.text).join(' ')}",
"client requesting ${nextActivitySpecs.activityType.string} for: ${nextActivitySpecs.tokens.map((t) => t.text.content).join(' ')}",
);

final PracticeActivityModelResponse? activityResponse =
Expand Down

0 comments on commit 981c635

Please sign in to comment.