Merge pull request #881 from pangeachat/show-gained-points-in-one-place
decide whether to show points gain animation based on the origin of t…
This commit is contained in:
commit
4dfc080b03
13 changed files with 84 additions and 28 deletions
|
|
@ -691,6 +691,7 @@ class ChatController extends State<ChatPageWithRoom>
|
|||
metadata: metadata,
|
||||
)),
|
||||
],
|
||||
origin: AnalyticsUpdateOrigin.sendMessage,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ 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/models/pangea_token_model.dart';
|
||||
import 'package:fluffychat/pangea/utils/error_handler.dart';
|
||||
|
|
@ -315,6 +316,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(
|
||||
|
|
@ -372,6 +375,7 @@ class ITChoices extends StatelessWidget {
|
|||
continuance.level > 1
|
||||
? ConstructUseTypeEnum.incIt
|
||||
: ConstructUseTypeEnum.corIt,
|
||||
AnalyticsUpdateOrigin.it,
|
||||
);
|
||||
}
|
||||
controller.currentITStep!.continuances[index].wasClicked = true;
|
||||
|
|
|
|||
|
|
@ -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});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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: [
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ class MultipleChoiceActivityState extends State<MultipleChoiceActivity> {
|
|||
widget.practiceCardController.currentActivity!,
|
||||
widget.practiceCardController.metadata,
|
||||
),
|
||||
origin: AnalyticsUpdateOrigin.practiceActivity,
|
||||
),
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ class WordFocusListeningActivityState
|
|||
widget.practiceCardController.currentActivity!,
|
||||
widget.practiceCardController.metadata,
|
||||
),
|
||||
origin: AnalyticsUpdateOrigin.practiceActivity,
|
||||
),
|
||||
);
|
||||
setState(() {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue