feat: send activity plan state event
This commit is contained in:
parent
379e4a8db9
commit
e3e81fbd68
12 changed files with 164 additions and 95 deletions
|
|
@ -1,12 +1,9 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
|
|
@ -19,7 +16,6 @@ import 'package:fluffychat/pangea/activity_planner/activity_planner_page.dart';
|
|||
import 'package:fluffychat/pangea/activity_planner/bookmarked_activities_repo.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/list_request_schema.dart';
|
||||
import 'package:fluffychat/pangea/activity_suggestions/activity_suggestions_constants.dart';
|
||||
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
|
||||
import 'package:fluffychat/utils/file_selector.dart';
|
||||
|
|
@ -112,44 +108,13 @@ class ActivityListViewState extends State<ActivityListView> {
|
|||
future: () async {
|
||||
final activity = _activities![index];
|
||||
|
||||
final eventId = await widget.room?.pangeaSendTextEvent(
|
||||
activity.markdown,
|
||||
messageTag: ModelKey.messageTagActivityPlan,
|
||||
//include full model or should we move to a state event for this?
|
||||
await widget.room?.sendActivityPlan(
|
||||
activity,
|
||||
avatar: _avatar,
|
||||
avatarURL: _avatarURL,
|
||||
filename: _filename,
|
||||
);
|
||||
|
||||
if (eventId == null) {
|
||||
debugger(when: kDebugMode);
|
||||
return;
|
||||
}
|
||||
|
||||
Uint8List? bytes = _avatar;
|
||||
if (_avatarURL != null && bytes == null) {
|
||||
final resp = await http
|
||||
.get(Uri.parse(_avatarURL!))
|
||||
.timeout(const Duration(seconds: 5));
|
||||
bytes = resp.bodyBytes;
|
||||
}
|
||||
|
||||
if (bytes != null && _filename != null) {
|
||||
final file = MatrixFile(
|
||||
bytes: bytes,
|
||||
name: _filename!,
|
||||
);
|
||||
|
||||
await widget.room?.sendFileEvent(
|
||||
file,
|
||||
shrinkImageMaxDimension: 1600,
|
||||
extraContent: {
|
||||
ModelKey.messageTags: ModelKey.messageTagActivityPlan,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (widget.room != null && widget.room!.canSendDefaultStates) {
|
||||
await widget.room?.setPinnedEvents([eventId]);
|
||||
}
|
||||
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_plan_request.dart';
|
||||
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
|
||||
|
||||
class ActivityPlanModel {
|
||||
final ActivityPlanRequest req;
|
||||
|
|
@ -23,27 +24,27 @@ class ActivityPlanModel {
|
|||
|
||||
factory ActivityPlanModel.fromJson(Map<String, dynamic> json) {
|
||||
return ActivityPlanModel(
|
||||
req: ActivityPlanRequest.fromJson(json['req']),
|
||||
title: json['title'],
|
||||
learningObjective: json['learning_objective'],
|
||||
instructions: json['instructions'],
|
||||
req: ActivityPlanRequest.fromJson(json[ModelKey.activityPlanRequest]),
|
||||
title: json[ModelKey.activityPlanTitle],
|
||||
learningObjective: json[ModelKey.activityPlanLearningObjective],
|
||||
instructions: json[ModelKey.activityPlanInstructions],
|
||||
vocab: List<Vocab>.from(
|
||||
json['vocab'].map((vocab) => Vocab.fromJson(vocab)),
|
||||
json[ModelKey.activityPlanVocab].map((vocab) => Vocab.fromJson(vocab)),
|
||||
),
|
||||
bookmarkId: json['bookmark_id'],
|
||||
imageURL: json['image_url'],
|
||||
bookmarkId: json[ModelKey.activityPlanBookmarkId],
|
||||
imageURL: json[ModelKey.activityPlanImageURL],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'req': req.toJson(),
|
||||
'title': title,
|
||||
'learning_objective': learningObjective,
|
||||
'instructions': instructions,
|
||||
'vocab': vocab.map((vocab) => vocab.toJson()).toList(),
|
||||
'bookmark_id': bookmarkId,
|
||||
'image_url': imageURL,
|
||||
ModelKey.activityPlanRequest: req.toJson(),
|
||||
ModelKey.activityPlanTitle: title,
|
||||
ModelKey.activityPlanLearningObjective: learningObjective,
|
||||
ModelKey.activityPlanInstructions: instructions,
|
||||
ModelKey.activityPlanVocab: vocab.map((vocab) => vocab.toJson()).toList(),
|
||||
ModelKey.activityPlanBookmarkId: bookmarkId,
|
||||
ModelKey.activityPlanImageURL: imageURL,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:fluffychat/pangea/activity_planner/media_enum.dart';
|
||||
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/enums/language_level_type_enum.dart';
|
||||
|
||||
class ActivityPlanRequest {
|
||||
|
|
@ -26,33 +27,35 @@ class ActivityPlanRequest {
|
|||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'topic': topic,
|
||||
'mode': mode,
|
||||
'objective': objective,
|
||||
'media': media.string,
|
||||
'activity_cefr_level': cefrLevel.string,
|
||||
'language_of_instructions': languageOfInstructions,
|
||||
'target_language': targetLanguage,
|
||||
'count': count,
|
||||
'number_of_participants': numberOfParticipants,
|
||||
ModelKey.activityRequestTopic: topic,
|
||||
ModelKey.activityRequestMode: mode,
|
||||
ModelKey.activityRequestObjective: objective,
|
||||
ModelKey.activityRequestMedia: media.string,
|
||||
ModelKey.activityRequestCefrLevel: cefrLevel.string,
|
||||
ModelKey.activityRequestLanguageOfInstructions: languageOfInstructions,
|
||||
ModelKey.activityRequestTargetLanguage: targetLanguage,
|
||||
ModelKey.activityRequestCount: count,
|
||||
ModelKey.activityRequestNumberOfParticipants: numberOfParticipants,
|
||||
};
|
||||
}
|
||||
|
||||
factory ActivityPlanRequest.fromJson(Map<String, dynamic> json) =>
|
||||
ActivityPlanRequest(
|
||||
topic: json['topic'],
|
||||
mode: json['mode'],
|
||||
objective: json['objective'],
|
||||
media: MediaEnum.nan.fromString(json['media']),
|
||||
cefrLevel: json['activity_cefr_level'] != null
|
||||
topic: json[ModelKey.activityRequestTopic],
|
||||
mode: json[ModelKey.activityRequestMode],
|
||||
objective: json[ModelKey.activityRequestObjective],
|
||||
media: MediaEnum.nan.fromString(json[ModelKey.activityRequestMedia]),
|
||||
cefrLevel: json[ModelKey.activityRequestCefrLevel] != null
|
||||
? LanguageLevelTypeEnumExtension.fromString(
|
||||
json['activity_cefr_level'],
|
||||
json[ModelKey.activityRequestCefrLevel],
|
||||
)
|
||||
: LanguageLevelTypeEnum.a1,
|
||||
languageOfInstructions: json['language_of_instructions'],
|
||||
targetLanguage: json['target_language'],
|
||||
count: json['count'],
|
||||
numberOfParticipants: json['number_of_participants'],
|
||||
languageOfInstructions:
|
||||
json[ModelKey.activityRequestLanguageOfInstructions],
|
||||
targetLanguage: json[ModelKey.activityRequestTargetLanguage],
|
||||
count: json[ModelKey.activityRequestCount],
|
||||
numberOfParticipants:
|
||||
json[ModelKey.activityRequestNumberOfParticipants],
|
||||
);
|
||||
|
||||
String get storageKey =>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import 'package:matrix/matrix.dart';
|
|||
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_list_view.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_mode_list_repo.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_plan_request.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/learning_objective_list_repo.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/list_request_schema.dart';
|
||||
|
|
@ -16,6 +17,7 @@ import 'package:fluffychat/pangea/activity_planner/suggestion_form_field.dart';
|
|||
import 'package:fluffychat/pangea/activity_planner/topic_list_repo.dart';
|
||||
import 'package:fluffychat/pangea/chat_settings/widgets/language_level_dropdown.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/dropdown_text_button.dart';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
|
||||
import 'package:fluffychat/pangea/instructions/instructions_enum.dart';
|
||||
import 'package:fluffychat/pangea/instructions/instructions_inline_tooltip.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart';
|
||||
|
|
@ -54,6 +56,8 @@ class ActivityPlannerPageState extends State<ActivityPlannerPage> {
|
|||
|
||||
Room? get room => Matrix.of(context).client.getRoomById(widget.roomID);
|
||||
|
||||
ActivityPlanModel? get _initialActivity => room?.activityPlan;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
|
@ -62,12 +66,26 @@ class ActivityPlannerPageState extends State<ActivityPlannerPage> {
|
|||
return;
|
||||
}
|
||||
|
||||
_selectedLanguageOfInstructions =
|
||||
MatrixState.pangeaController.languageController.userL1?.langCode;
|
||||
_selectedTargetLanguage =
|
||||
MatrixState.pangeaController.languageController.userL2?.langCode;
|
||||
_selectedCefrLevel = LanguageLevelTypeEnum.a1;
|
||||
_selectedNumberOfParticipants = max(room?.getParticipants().length ?? 1, 1);
|
||||
if (_initialActivity == null) {
|
||||
_selectedLanguageOfInstructions =
|
||||
MatrixState.pangeaController.languageController.userL1?.langCode;
|
||||
_selectedTargetLanguage =
|
||||
MatrixState.pangeaController.languageController.userL2?.langCode;
|
||||
_selectedCefrLevel = LanguageLevelTypeEnum.a1;
|
||||
_selectedNumberOfParticipants =
|
||||
max(room?.getParticipants().length ?? 1, 1);
|
||||
} else {
|
||||
_selectedMedia = _initialActivity!.req.media;
|
||||
_selectedLanguageOfInstructions =
|
||||
_initialActivity!.req.languageOfInstructions;
|
||||
_selectedTargetLanguage = _initialActivity!.req.targetLanguage;
|
||||
_selectedCefrLevel = _initialActivity!.req.cefrLevel;
|
||||
_selectedNumberOfParticipants =
|
||||
_initialActivity!.req.numberOfParticipants;
|
||||
_topicController.text = _initialActivity!.req.topic;
|
||||
_objectiveController.text = _initialActivity!.req.objective;
|
||||
_modeController.text = _initialActivity!.req.mode;
|
||||
}
|
||||
}
|
||||
|
||||
final _topicController = TextEditingController();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import 'dart:developer';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
|
@ -17,7 +16,6 @@ import 'package:fluffychat/config/themes.dart';
|
|||
import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart';
|
||||
import 'package:fluffychat/pangea/activity_suggestions/activity_suggestion_card_row.dart';
|
||||
import 'package:fluffychat/pangea/chat/constants/default_power_level.dart';
|
||||
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
|
||||
import 'package:fluffychat/utils/file_selector.dart';
|
||||
|
|
@ -180,17 +178,7 @@ class ActivitySuggestionDialogState extends State<ActivitySuggestionDialog> {
|
|||
if (room == null) return;
|
||||
}
|
||||
|
||||
final eventId = await room.pangeaSendTextEvent(
|
||||
widget.activity.markdown,
|
||||
messageTag: ModelKey.messageTagActivityPlan,
|
||||
);
|
||||
|
||||
if (eventId == null) {
|
||||
debugger(when: kDebugMode);
|
||||
return;
|
||||
}
|
||||
|
||||
await room.setPinnedEvents([eventId]);
|
||||
await room.sendActivityPlan(widget.activity);
|
||||
context.go("/rooms/$roomId/invite");
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -156,4 +156,25 @@ class ModelKey {
|
|||
static const String analytics = "analytics";
|
||||
static const String level = "level";
|
||||
static const String xpOffset = "xp_offset";
|
||||
|
||||
// activity plan
|
||||
static const String activityPlanRequest = "req";
|
||||
static const String activityPlanTitle = "title";
|
||||
static const String activityPlanLearningObjective = "learning_objective";
|
||||
static const String activityPlanInstructions = "instructions";
|
||||
static const String activityPlanVocab = "vocab";
|
||||
static const String activityPlanImageURL = "image_url";
|
||||
static const String activityPlanBookmarkId = "bookmark_id";
|
||||
|
||||
static const String activityRequestTopic = "topic";
|
||||
static const String activityRequestMode = "mode";
|
||||
static const String activityRequestObjective = "objective";
|
||||
static const String activityRequestMedia = "media";
|
||||
static const String activityRequestCefrLevel = "activity_cefr_level";
|
||||
static const String activityRequestLanguageOfInstructions =
|
||||
"language_of_instructions";
|
||||
static const String activityRequestTargetLanguage = "target_language";
|
||||
static const String activityRequestCount = "count";
|
||||
static const String activityRequestNumberOfParticipants =
|
||||
"number_of_participants";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ class PangeaEventTypes {
|
|||
static const botOptions = "pangea.bot_options";
|
||||
static const capacity = "pangea.capacity";
|
||||
|
||||
static const activityPlan = "pangea.activity_plan";
|
||||
|
||||
static const userAge = "pangea.user_age";
|
||||
|
||||
static const String report = 'm.report';
|
||||
|
|
|
|||
|
|
@ -10,11 +10,13 @@ import 'package:flutter/material.dart';
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:html_unescape/html_unescape.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:matrix/matrix.dart' as matrix;
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:matrix/src/utils/markdown.dart';
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/constructs_event.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/bot/utils/bot_name.dart';
|
||||
|
|
|
|||
|
|
@ -266,6 +266,56 @@ extension EventsRoomExtension on Room {
|
|||
);
|
||||
}
|
||||
|
||||
Future<void> sendActivityPlan(
|
||||
ActivityPlanModel activity, {
|
||||
Uint8List? avatar,
|
||||
String? avatarURL,
|
||||
String? filename,
|
||||
}) async {
|
||||
Uint8List? bytes = avatar;
|
||||
if (avatarURL != null && bytes == null) {
|
||||
final resp = await http
|
||||
.get(Uri.parse(avatarURL))
|
||||
.timeout(const Duration(seconds: 5));
|
||||
bytes = resp.bodyBytes;
|
||||
}
|
||||
|
||||
MatrixFile? file;
|
||||
if (filename != null && bytes != null) {
|
||||
file = MatrixFile(
|
||||
bytes: bytes,
|
||||
name: filename,
|
||||
);
|
||||
}
|
||||
final eventId = await pangeaSendTextEvent(
|
||||
activity.markdown,
|
||||
messageTag: ModelKey.messageTagActivityPlan,
|
||||
);
|
||||
|
||||
if (file != null) {
|
||||
await sendFileEvent(
|
||||
file,
|
||||
shrinkImageMaxDimension: 1600,
|
||||
extraContent: {
|
||||
ModelKey.messageTags: ModelKey.messageTagActivityPlan,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (canSendDefaultStates) {
|
||||
await client.setRoomStateWithKey(
|
||||
id,
|
||||
PangeaEventTypes.activityPlan,
|
||||
"",
|
||||
activity.toJson(),
|
||||
);
|
||||
|
||||
if (eventId != null) {
|
||||
await setPinnedEvents([eventId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a list of events in the room that are of type [PangeaEventTypes.construct]
|
||||
/// and have the sender as [userID]. If [count] is provided, the function will
|
||||
/// return at most [count] events.
|
||||
|
|
|
|||
|
|
@ -70,4 +70,23 @@ extension RoomSettingsRoomExtension on Room {
|
|||
if (stateEvent == null) return null;
|
||||
return BotOptionsModel.fromJson(stateEvent.content);
|
||||
}
|
||||
|
||||
ActivityPlanModel? get activityPlan {
|
||||
final stateEvent = getState(PangeaEventTypes.activityPlan);
|
||||
if (stateEvent == null) return null;
|
||||
|
||||
try {
|
||||
return ActivityPlanModel.fromJson(stateEvent.content);
|
||||
} catch (e, s) {
|
||||
ErrorHandler.logError(
|
||||
e: e,
|
||||
s: s,
|
||||
data: {
|
||||
"roomID": id,
|
||||
"stateEvent": stateEvent.content,
|
||||
},
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import 'package:matrix/matrix.dart';
|
|||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pages/chat/chat.dart';
|
||||
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
|
||||
import 'package:fluffychat/pangea/events/extensions/pangea_event_extension.dart';
|
||||
|
||||
class OverlayHeader extends StatelessWidget {
|
||||
final ChatController controller;
|
||||
|
|
@ -62,8 +62,7 @@ class OverlayHeader extends StatelessWidget {
|
|||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
if (controller.canEditSelectedEvents &&
|
||||
controller.selectedEvents.first.content[ModelKey.messageTags] !=
|
||||
ModelKey.messageTagActivityPlan)
|
||||
!controller.selectedEvents.first.isActivityMessage)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit_outlined),
|
||||
tooltip: L10n.of(context).edit,
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ abstract class ClientManager {
|
|||
EventTypes.RoomPowerLevels,
|
||||
PangeaEventTypes.userSetLemmaInfo,
|
||||
EventTypes.RoomJoinRules,
|
||||
PangeaEventTypes.activityPlan,
|
||||
// Pangea#
|
||||
},
|
||||
logLevel: kReleaseMode ? Level.warning : Level.verbose,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue