2364 on chat creation with activity if no room image set activity image (#2371)

* chore: formatting

* chore: on chat creation without activity, set avatar to activity image if no image set
This commit is contained in:
ggurdin 2025-04-07 10:58:38 -04:00 committed by GitHub
parent 9971ca50b9
commit b333c45026
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 154 additions and 83 deletions

View file

@ -49,7 +49,6 @@ class ActivityGeneratorState extends State<ActivityGenerator> {
LanguageLevelTypeEnum? selectedCefrLevel;
int? selectedNumberOfParticipants;
String? avatarURL;
String? filename;
@override
@ -186,11 +185,15 @@ class ActivityGeneratorState extends State<ActivityGenerator> {
final modeName =
mode.defaultName.toLowerCase().replaceAll(RegExp(r'\s+'), '');
if (!mounted) return;
if (!mounted || activities == null) return;
final imageUrl =
"${AppConfig.assetsBaseURL}/${ActivitySuggestionsConstants.modeImageFileStart}$modeName.jpg";
setState(() {
filename =
"${ActivitySuggestionsConstants.modeImageFileStart}$modeName.jpg";
avatarURL = "${AppConfig.assetsBaseURL}/$filename";
for (final activity in activities!) {
activity.imageURL = imageUrl;
}
});
}
@ -217,12 +220,9 @@ class ActivityGeneratorState extends State<ActivityGenerator> {
});
try {
await _setModeImageURL();
final resp = await ActivityPlanGenerationRepo.get(planRequest);
for (final activity in resp.activityPlans) {
activity.imageURL = avatarURL;
}
activities = resp.activityPlans;
await _setModeImageURL();
} catch (e, s) {
error = e.toString();
ErrorHandler.logError(

View file

@ -59,7 +59,6 @@ class ActivityGeneratorView extends StatelessWidget {
onEdit: (updatedActivity) =>
controller.onEdit(index, updatedActivity),
onChange: controller.update,
avatarURL: controller.avatarURL,
initialFilename: controller.filename,
);
},

View file

@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:go_router/go_router.dart';
import 'package:http/http.dart' as http;
import 'package:material_symbols_icons/symbols.dart';
import 'package:matrix/matrix.dart' as sdk;
import 'package:matrix/matrix.dart';
@ -26,7 +27,6 @@ class ActivityPlanCard extends StatefulWidget {
final VoidCallback onChange;
final ValueChanged<ActivityPlanModel> onEdit;
final double maxWidth;
final String? avatarURL;
final String? initialFilename;
const ActivityPlanCard({
@ -36,7 +36,6 @@ class ActivityPlanCard extends StatefulWidget {
required this.onChange,
required this.onEdit,
this.maxWidth = 400,
this.avatarURL,
this.initialFilename,
});
@ -53,7 +52,6 @@ class ActivityPlanCardState extends State<ActivityPlanCard> {
final TextEditingController _newVocabController = TextEditingController();
final FocusNode _vocabFocusNode = FocusNode();
String? _avatarURL;
Uint8List? _avatar;
String? _filename;
@ -67,7 +65,6 @@ class ActivityPlanCardState extends State<ActivityPlanCard> {
_instructionsController =
TextEditingController(text: _tempActivity.instructions);
_filename = widget.initialFilename;
_avatarURL = widget.avatarURL ?? widget.activity.imageURL;
}
static const double itemPadding = 12;
@ -89,7 +86,7 @@ class ActivityPlanCardState extends State<ActivityPlanCard> {
learningObjective: _learningObjectiveController.text,
instructions: _instructionsController.text,
vocab: _tempActivity.vocab,
imageURL: _avatarURL,
imageURL: widget.activity.imageURL,
);
widget.onEdit(updatedActivity);
@ -162,11 +159,27 @@ class ActivityPlanCardState extends State<ActivityPlanCard> {
await showFutureLoadingDialog(
context: context,
future: () async {
if (_avatar == null && widget.activity.imageURL != null) {
final resp = await http
.get(Uri.parse(widget.activity.imageURL!))
.timeout(const Duration(seconds: 5));
_avatar = resp.bodyBytes;
}
String? avatarUrl;
if (_avatar != null) {
final client = Matrix.of(context).client;
final url = await client.uploadContent(
_avatar!,
filename: _filename,
);
avatarUrl = url.toString();
}
if (widget.room != null) {
await widget.room?.sendActivityPlan(
widget.activity,
avatar: _avatar,
avatarURL: _avatarURL,
filename: _filename,
);
@ -181,6 +194,15 @@ class ActivityPlanCardState extends State<ActivityPlanCard> {
groupName:
widget.activity.title.isNotEmpty ? widget.activity.title : null,
initialState: [
if (_avatar != null) ...[
StateEvent(
type: EventTypes.RoomAvatar,
stateKey: '',
content: {
"url": avatarUrl,
},
),
],
StateEvent(
type: EventTypes.RoomPowerLevels,
stateKey: '',
@ -200,7 +222,6 @@ class ActivityPlanCardState extends State<ActivityPlanCard> {
await room.sendActivityPlan(
widget.activity,
avatar: _avatar,
avatarURL: _avatarURL,
filename: _filename,
);
@ -232,12 +253,12 @@ class ActivityPlanCardState extends State<ActivityPlanCard> {
),
clipBehavior: Clip.hardEdge,
alignment: Alignment.center,
child: _avatarURL != null || _avatar != null
child: widget.activity.imageURL != null || _avatar != null
? ClipRRect(
child: _avatar == null
? CachedNetworkImage(
fit: BoxFit.cover,
imageUrl: _avatarURL!,
imageUrl: widget.activity.imageURL!,
placeholder: (context, url) {
return const Center(
child: CircularProgressIndicator(),

View file

@ -19,6 +19,7 @@ import 'package:fluffychat/pangea/activity_suggestions/activity_suggestion_card_
import 'package:fluffychat/pangea/chat/constants/default_power_level.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:fluffychat/utils/client_download_content_extension.dart';
import 'package:fluffychat/utils/file_selector.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
import 'package:fluffychat/widgets/matrix.dart';
@ -119,12 +120,22 @@ class ActivitySuggestionDialogState extends State<ActivitySuggestionDialog> {
if (widget.activity.imageURL == null) return;
try {
if (_avatar == null) {
final Response response =
await http.get(Uri.parse(widget.activity.imageURL!));
_avatar = response.bodyBytes;
_filename = Uri.encodeComponent(
Uri.parse(widget.activity.imageURL!).pathSegments.last,
);
if (widget.activity.imageURL!.startsWith("mxc")) {
final client = Matrix.of(context).client;
final mxcUri = Uri.parse(widget.activity.imageURL!);
final data = await client.downloadMxcCached(mxcUri);
_avatar = data;
_filename = Uri.encodeComponent(
mxcUri.pathSegments.last,
);
} else {
final Response response =
await http.get(Uri.parse(widget.activity.imageURL!));
_avatar = response.bodyBytes;
_filename = Uri.encodeComponent(
Uri.parse(widget.activity.imageURL!).pathSegments.last,
);
}
}
} catch (err, s) {
ErrorHandler.logError(
@ -183,12 +194,29 @@ class ActivitySuggestionDialogState extends State<ActivitySuggestionDialog> {
return;
}
String? avatarUrl;
if (_avatar != null) {
final url = await Matrix.of(context).client.uploadContent(
_avatar!,
filename: _filename,
);
avatarUrl = url.toString();
}
final client = Matrix.of(context).client;
final roomId = await client.createGroupChat(
preset: CreateRoomPreset.publicChat,
visibility: sdk.Visibility.private,
groupName: widget.activity.title,
initialState: [
if (avatarUrl != null)
StateEvent(
type: EventTypes.RoomAvatar,
stateKey: '',
content: {
"url": avatarUrl,
},
),
StateEvent(
type: EventTypes.RoomPowerLevels,
stateKey: '',
@ -246,34 +274,55 @@ class ActivitySuggestionDialogState extends State<ActivitySuggestionDialog> {
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24.0),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(24.0),
child: _avatar != null
? Image.memory(_avatar!, fit: BoxFit.cover)
: widget.activity.imageURL != null
? widget.activity.imageURL!.startsWith("mxc")
? MxcImage(
uri: Uri.parse(widget.activity.imageURL!),
width: width,
height: 200,
cacheKey: widget.activity.bookmarkId,
fit: BoxFit.cover,
)
: CachedNetworkImage(
imageUrl: widget.activity.imageURL!,
fit: BoxFit.cover,
placeholder: (context, url) => const Center(
child: CircularProgressIndicator(),
),
errorWidget: (context, url, error) =>
const SizedBox(),
)
: null,
),
Stack(
alignment: Alignment.center,
children: [
DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24.0),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(24.0),
child: _avatar != null
? Image.memory(_avatar!, fit: BoxFit.cover)
: widget.activity.imageURL != null
? widget.activity.imageURL!.startsWith("mxc")
? MxcImage(
uri: Uri.parse(widget.activity.imageURL!),
width: width,
height: 200,
cacheKey: widget.activity.bookmarkId,
fit: BoxFit.cover,
)
: CachedNetworkImage(
imageUrl: widget.activity.imageURL!,
fit: BoxFit.cover,
placeholder: (context, url) =>
const Center(
child: CircularProgressIndicator(),
),
errorWidget: (context, url, error) =>
const SizedBox(),
)
: null,
),
),
if (_isEditing)
Positioned(
bottom: 8.0,
child: InkWell(
borderRadius: BorderRadius.circular(90),
onTap: _setAvatar,
child: const CircleAvatar(
radius: 24.0,
child: Icon(
Icons.add_a_photo_outlined,
size: 24.0,
),
),
),
),
],
),
Flexible(
child: SingleChildScrollView(
@ -601,21 +650,6 @@ class ActivitySuggestionDialogState extends State<ActivitySuggestionDialog> {
tooltip: L10n.of(context).close,
),
),
if (_isEditing)
Positioned(
top: 160.0,
child: InkWell(
borderRadius: BorderRadius.circular(90),
onTap: _setAvatar,
child: const CircleAvatar(
radius: 24.0,
child: Icon(
Icons.add_a_photo_outlined,
size: 24.0,
),
),
),
),
],
);

View file

@ -1,8 +1,10 @@
import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/constructs/construct_form.dart';
import 'package:fluffychat/pangea/practice_activities/practice_choice.dart';
import 'package:flutter/material.dart';
class PracticeMatchActivity {
/// The constructIdenfifiers involved in the activity

View file

@ -1,6 +1,9 @@
import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:collection/collection.dart';
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart';
import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart';
@ -9,7 +12,6 @@ import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart';
import 'package:fluffychat/pangea/practice_activities/practice_selection_repo.dart';
import 'package:fluffychat/pangea/practice_activities/practice_target.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/foundation.dart';
class PracticeSelection {
late String _userL2;
@ -166,11 +168,15 @@ class PracticeSelection {
).sorted(
(a, b) {
final bScore = b.tokens.first.activityPriorityScore(
ActivityTypeEnum.morphId, b.morphFeature!) *
ActivityTypeEnum.morphId,
b.morphFeature!,
) *
(tokenIsIncludedInActivityOfAnyType(b.tokens.first) ? 1.1 : 1);
final aScore = a.tokens.first.activityPriorityScore(
ActivityTypeEnum.morphId, a.morphFeature!) *
ActivityTypeEnum.morphId,
a.morphFeature!,
) *
(tokenIsIncludedInActivityOfAnyType(a.tokens.first) ? 1.1 : 1);
return bScore.compareTo(aScore);

View file

@ -1,8 +1,10 @@
import 'package:flutter/material.dart';
import 'package:get_storage/get_storage.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
import 'package:fluffychat/pangea/practice_activities/practice_selection.dart';
import 'package:flutter/material.dart';
import 'package:get_storage/get_storage.dart';
class PracticeSelectionRepo {
static final GetStorage _storage = GetStorage('practice_selection_cache');
@ -21,7 +23,8 @@ class PracticeSelectionRepo {
}
static MapEntry<String, PracticeSelection>? _parsePracticeSelection(
String key) {
String key,
) {
if (!_storage.hasData(key)) {
return null;
}

View file

@ -1,3 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pages/chat/chat.dart';
import 'package:fluffychat/pangea/toolbar/enums/message_mode_enum.dart';
@ -7,8 +11,6 @@ import 'package:fluffychat/pangea/toolbar/widgets/message_speech_to_text_card.da
import 'package:fluffychat/pangea/toolbar/widgets/message_translation_card.dart';
import 'package:fluffychat/pangea/toolbar/widgets/practice_activity/practice_activity_card.dart';
import 'package:fluffychat/pangea/toolbar/widgets/word_zoom/morph_focus_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
const double minContentHeight = 120;

View file

@ -1,7 +1,13 @@
import 'dart:async';
import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:collection/collection.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pages/chat/chat.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
@ -25,10 +31,6 @@ import 'package:fluffychat/pangea/toolbar/reading_assistance_input_row/morph_sel
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_positioner.dart';
import 'package:fluffychat/pangea/toolbar/widgets/reading_assistance_content.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:matrix/matrix.dart';
/// Controls data at the top level of the toolbar (mainly token / toolbar mode selection)
class MessageSelectionOverlay extends StatefulWidget {

View file

@ -1,5 +1,11 @@
import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_use_model.dart';
import 'package:fluffychat/pangea/analytics_misc/text_loading_shimmer.dart';
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
@ -12,10 +18,6 @@ import 'package:fluffychat/pangea/toolbar/enums/message_mode_enum.dart';
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart';
import 'package:fluffychat/pangea/toolbar/widgets/practice_activity/word_zoom_activity_button.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:material_symbols_icons/symbols.dart';
class LemmaMeaningWidget extends StatefulWidget {
final ConstructUses constructUse;