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:
parent
9971ca50b9
commit
b333c45026
10 changed files with 154 additions and 83 deletions
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ class ActivityGeneratorView extends StatelessWidget {
|
|||
onEdit: (updatedActivity) =>
|
||||
controller.onEdit(index, updatedActivity),
|
||||
onChange: controller.update,
|
||||
avatarURL: controller.avatarURL,
|
||||
initialFilename: controller.filename,
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue