Toolbar practice (#707)
* remove print statement * ending animation, savoring joy, properly adding xp in session * forgot to switch env again... * increment version number * about to move toolbar buttons up to level of overlay controller * added ability to give feedback and get new activitypull/1398/head
parent
371d4f06d4
commit
b8edf595ca
@ -0,0 +1,122 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pangea/enum/message_mode_enum.dart';
|
||||
import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart';
|
||||
import 'package:fluffychat/pangea/widgets/chat/message_selection_overlay.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ToolbarButtons extends StatefulWidget {
|
||||
final MessageOverlayController overlayController;
|
||||
final double width;
|
||||
|
||||
const ToolbarButtons({
|
||||
required this.overlayController,
|
||||
required this.width,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
ToolbarButtonsState createState() => ToolbarButtonsState();
|
||||
}
|
||||
|
||||
class ToolbarButtonsState extends State<ToolbarButtons> {
|
||||
PangeaMessageEvent get pangeaMessageEvent =>
|
||||
widget.overlayController.pangeaMessageEvent;
|
||||
|
||||
List<MessageMode> get modes => MessageMode.values
|
||||
.where((mode) => mode.isValidMode(pangeaMessageEvent.event))
|
||||
.toList();
|
||||
|
||||
static const double iconWidth = 36.0;
|
||||
|
||||
MessageOverlayController get overlayController => widget.overlayController;
|
||||
|
||||
// @ggurdin - maybe this can be stateless now?
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final double barWidth = widget.width - iconWidth;
|
||||
|
||||
if (widget.overlayController.pangeaMessageEvent.isAudioMessage) {
|
||||
return const SizedBox();
|
||||
}
|
||||
|
||||
return SizedBox(
|
||||
width: widget.width,
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Stack(
|
||||
children: [
|
||||
Container(
|
||||
width: widget.width,
|
||||
height: 12,
|
||||
decoration: BoxDecoration(
|
||||
color: MessageModeExtension.barAndLockedButtonColor(context),
|
||||
),
|
||||
margin: const EdgeInsets.symmetric(horizontal: iconWidth / 2),
|
||||
),
|
||||
AnimatedContainer(
|
||||
duration: FluffyThemes.animationDuration,
|
||||
height: 12,
|
||||
width: overlayController.isPracticeComplete
|
||||
? barWidth
|
||||
: min(
|
||||
barWidth,
|
||||
(barWidth / 3) *
|
||||
pangeaMessageEvent.numberOfActivitiesCompleted,
|
||||
),
|
||||
color: AppConfig.success,
|
||||
margin: const EdgeInsets.symmetric(horizontal: iconWidth / 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: modes
|
||||
.mapIndexed(
|
||||
(index, mode) => Tooltip(
|
||||
message: mode.tooltip(context),
|
||||
child: IconButton(
|
||||
iconSize: 20,
|
||||
icon: Icon(mode.icon),
|
||||
color: mode == widget.overlayController.toolbarMode
|
||||
? Colors.white
|
||||
: null,
|
||||
isSelected: mode == widget.overlayController.toolbarMode,
|
||||
style: ButtonStyle(
|
||||
backgroundColor: WidgetStateProperty.all(
|
||||
mode.iconButtonColor(
|
||||
context,
|
||||
index,
|
||||
widget.overlayController.toolbarMode,
|
||||
pangeaMessageEvent.numberOfActivitiesCompleted,
|
||||
widget.overlayController.isPracticeComplete,
|
||||
),
|
||||
),
|
||||
),
|
||||
onPressed: mode.isUnlocked(
|
||||
index,
|
||||
pangeaMessageEvent.numberOfActivitiesCompleted,
|
||||
overlayController.isPracticeComplete,
|
||||
)
|
||||
? () =>
|
||||
widget.overlayController.updateToolbarMode(mode)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
import 'package:fluffychat/pages/chat/chat.dart';
|
||||
import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
class ToolbarSelectionArea extends StatelessWidget {
|
||||
final ChatController controller;
|
||||
final PangeaMessageEvent? pangeaMessageEvent;
|
||||
final bool isOverlay;
|
||||
final Widget child;
|
||||
final Event? nextEvent;
|
||||
final Event? prevEvent;
|
||||
|
||||
const ToolbarSelectionArea({
|
||||
required this.controller,
|
||||
this.pangeaMessageEvent,
|
||||
this.isOverlay = false,
|
||||
required this.child,
|
||||
this.nextEvent,
|
||||
this.prevEvent,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
if (pangeaMessageEvent != null && !isOverlay) {
|
||||
controller.showToolbar(
|
||||
pangeaMessageEvent!,
|
||||
nextEvent: nextEvent,
|
||||
prevEvent: prevEvent,
|
||||
);
|
||||
}
|
||||
},
|
||||
onLongPress: () {
|
||||
if (pangeaMessageEvent != null && !isOverlay) {
|
||||
controller.showToolbar(
|
||||
pangeaMessageEvent!,
|
||||
nextEvent: nextEvent,
|
||||
prevEvent: prevEvent,
|
||||
);
|
||||
}
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,99 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart';
|
||||
import 'package:fluffychat/pangea/models/analytics/construct_list_model.dart';
|
||||
import 'package:fluffychat/pangea/models/analytics/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/models/practice_activities.dart/message_activity_request.dart';
|
||||
import 'package:fluffychat/pangea/utils/error_handler.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Seperated out the target tokens from the practice activity card
|
||||
/// in order to control the state of the target tokens
|
||||
class TargetTokensController {
|
||||
List<TokenWithXP>? _targetTokens;
|
||||
|
||||
TargetTokensController();
|
||||
|
||||
/// From the tokens in the message, do a preliminary filtering of which to target
|
||||
/// Then get the construct uses for those tokens
|
||||
Future<List<TokenWithXP>> targetTokens(
|
||||
BuildContext context,
|
||||
PangeaMessageEvent pangeaMessageEvent,
|
||||
) async {
|
||||
if (_targetTokens != null) {
|
||||
return _targetTokens!;
|
||||
}
|
||||
|
||||
_targetTokens = await _initialize(context, pangeaMessageEvent);
|
||||
|
||||
await updateTokensWithConstructs(
|
||||
MatrixState.pangeaController.analytics.analyticsStream.value ?? [],
|
||||
context,
|
||||
pangeaMessageEvent,
|
||||
);
|
||||
|
||||
return _targetTokens!;
|
||||
}
|
||||
|
||||
Future<List<TokenWithXP>> _initialize(
|
||||
BuildContext context,
|
||||
PangeaMessageEvent pangeaMessageEvent,
|
||||
) async {
|
||||
if (!context.mounted) {
|
||||
ErrorHandler.logError(
|
||||
m: 'getTargetTokens called when not mounted',
|
||||
s: StackTrace.current,
|
||||
);
|
||||
return _targetTokens = [];
|
||||
}
|
||||
|
||||
final tokens = await pangeaMessageEvent
|
||||
.representationByLanguage(pangeaMessageEvent.messageDisplayLangCode)
|
||||
?.tokensGlobal(context);
|
||||
|
||||
if (tokens == null || tokens.isEmpty) {
|
||||
debugger(when: kDebugMode);
|
||||
return _targetTokens = [];
|
||||
}
|
||||
|
||||
_targetTokens = [];
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
//don't bother with tokens that we don't save to vocab
|
||||
if (!tokens[i].lemma.saveVocab) {
|
||||
continue;
|
||||
}
|
||||
|
||||
_targetTokens!.add(tokens[i].emptyTokenWithXP);
|
||||
}
|
||||
|
||||
return _targetTokens!;
|
||||
}
|
||||
|
||||
Future<void> updateTokensWithConstructs(
|
||||
List<OneConstructUse> constructUses,
|
||||
context,
|
||||
pangeaMessageEvent,
|
||||
) async {
|
||||
final ConstructListModel constructList = ConstructListModel(
|
||||
uses: constructUses,
|
||||
type: null,
|
||||
);
|
||||
|
||||
_targetTokens ??= await _initialize(context, pangeaMessageEvent);
|
||||
|
||||
for (final token in _targetTokens!) {
|
||||
for (final construct in token.constructs) {
|
||||
final constructUseModel = constructList.getConstructUses(
|
||||
construct.id.lemma,
|
||||
construct.id.type,
|
||||
);
|
||||
if (constructUseModel != null) {
|
||||
construct.xp += constructUseModel.points;
|
||||
construct.lastUsed = constructUseModel.lastUsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue