chore: make activity bookmark ID final to prevent bookmarking the same activity twice (#2310)

This commit is contained in:
ggurdin 2025-04-01 16:12:33 -04:00 committed by GitHub
parent e3961db0d6
commit d4ce298866
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 73 additions and 71 deletions

View file

@ -100,9 +100,7 @@ class ActivityPlanCardState extends State<ActivityPlanCard> {
Future<ActivityPlanModel> _addBookmark(ActivityPlanModel activity) async {
try {
final uniqueID =
"${activity.title.replaceAll(RegExp(r'\s+'), '-')}-${DateTime.now().millisecondsSinceEpoch}";
return BookmarkedActivitiesRepo.save(activity, uniqueID);
return BookmarkedActivitiesRepo.save(activity);
} catch (e, stack) {
debugger(when: kDebugMode);
ErrorHandler.logError(e: e, s: stack, data: activity.toJson());
@ -116,9 +114,8 @@ class ActivityPlanCardState extends State<ActivityPlanCard> {
}
Future<void> _removeBookmark() async {
if (widget.activity.bookmarkId == null) return;
try {
BookmarkedActivitiesRepo.remove(widget.activity.bookmarkId!);
BookmarkedActivitiesRepo.remove(widget.activity.bookmarkId);
} catch (e, stack) {
debugger(when: kDebugMode);
ErrorHandler.logError(e: e, s: stack, data: widget.activity.toJson());

View file

@ -4,13 +4,13 @@ import 'package:fluffychat/pangea/activity_planner/activity_plan_request.dart';
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
class ActivityPlanModel {
final String bookmarkId;
final ActivityPlanRequest req;
String title;
String learningObjective;
String instructions;
List<Vocab> vocab;
String? imageURL;
String? bookmarkId;
ActivityPlanModel({
required this.req,
@ -18,9 +18,8 @@ class ActivityPlanModel {
required this.learningObjective,
required this.instructions,
required this.vocab,
this.bookmarkId,
this.imageURL,
});
}) : bookmarkId = req.hashCode.toString();
factory ActivityPlanModel.fromJson(Map<String, dynamic> json) {
return ActivityPlanModel(
@ -32,7 +31,6 @@ class ActivityPlanModel {
json[ModelKey.activityPlanVocab].map((vocab) => Vocab.fromJson(vocab)),
),
imageURL: json[ModelKey.activityPlanImageURL],
bookmarkId: json[ModelKey.activityPlanBookmarkId],
);
}
@ -77,8 +75,7 @@ class ActivityPlanModel {
other.learningObjective == learningObjective &&
other.instructions == instructions &&
listEquals(other.vocab, vocab) &&
other.imageURL == imageURL &&
other.bookmarkId == bookmarkId;
other.imageURL == imageURL;
}
@override
@ -88,8 +85,7 @@ class ActivityPlanModel {
learningObjective.hashCode ^
instructions.hashCode ^
Object.hashAll(vocab) ^
imageURL.hashCode ^
bookmarkId.hashCode;
imageURL.hashCode;
}
class Vocab {

View file

@ -11,11 +11,9 @@ class BookmarkedActivitiesRepo {
/// returns the activity with a bookmarkId
static Future<ActivityPlanModel> save(
ActivityPlanModel activity,
String bookmarkID,
) async {
activity.bookmarkId = bookmarkID;
await _bookStorage.write(
bookmarkID,
activity.bookmarkId,
activity.toJson(),
);
@ -27,8 +25,7 @@ class BookmarkedActivitiesRepo {
_bookStorage.remove(bookmarkId);
static bool isBookmarked(ActivityPlanModel activity) {
return activity.bookmarkId != null &&
_bookStorage.read(activity.bookmarkId!) != null;
return _bookStorage.read(activity.bookmarkId) != null;
}
static List<ActivityPlanModel> get() {

View file

@ -52,13 +52,8 @@ class BookmarkedActivitiesListState extends State<BookmarkedActivitiesList> {
activity.imageURL = url.toString();
}
final uniqueID =
"${activity.title.replaceAll(RegExp(r'\s+'), '-')}-${DateTime.now().millisecondsSinceEpoch}";
if (activity.bookmarkId != null) {
await BookmarkedActivitiesRepo.remove(activity.bookmarkId!);
}
await BookmarkedActivitiesRepo.save(activity, uniqueID);
await BookmarkedActivitiesRepo.remove(activity.bookmarkId);
await BookmarkedActivitiesRepo.save(activity);
if (mounted) setState(() {});
}

View file

@ -189,16 +189,11 @@ class ActivitySuggestionCard extends StatelessWidget {
),
onPressed: onPressed != null
? () async {
final uniqueID =
"${activity.title.replaceAll(RegExp(r'\s+'), '-')}-${DateTime.now().millisecondsSinceEpoch}";
await (isBookmarked
? BookmarkedActivitiesRepo.remove(
activity.bookmarkId!,
activity.bookmarkId,
)
: BookmarkedActivitiesRepo.save(
activity,
uniqueID,
));
: BookmarkedActivitiesRepo.save(activity));
onChange();
}
: null,

View file

@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:shimmer/shimmer.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart';
@ -48,6 +49,7 @@ class ActivitySuggestionsAreaState extends State<ActivitySuggestionsArea> {
super.dispose();
}
bool _loading = true;
bool get _isColumnMode => FluffyThemes.isColumnMode(context);
final List<ActivityPlanModel> _activityItems = [];
@ -57,52 +59,72 @@ class ActivitySuggestionsAreaState extends State<ActivitySuggestionsArea> {
double get cardWidth => _isColumnMode ? 225.0 : 150.0;
Future<void> _setActivityItems() async {
final ActivityPlanRequest request = ActivityPlanRequest(
topic: "",
mode: "",
objective: "",
media: MediaEnum.nan,
cefrLevel: LanguageLevelTypeEnum.a1,
languageOfInstructions: LanguageKeys.defaultLanguage,
targetLanguage:
MatrixState.pangeaController.languageController.userL2?.langCode ??
LanguageKeys.defaultLanguage,
numberOfParticipants: 3,
count: 5,
);
final resp = await ActivitySearchRepo.get(request);
_activityItems.addAll(resp.activityPlans);
if (mounted) setState(() {});
try {
final ActivityPlanRequest request = ActivityPlanRequest(
topic: "",
mode: "",
objective: "",
media: MediaEnum.nan,
cefrLevel: LanguageLevelTypeEnum.a1,
languageOfInstructions: LanguageKeys.defaultLanguage,
targetLanguage:
MatrixState.pangeaController.languageController.userL2?.langCode ??
LanguageKeys.defaultLanguage,
numberOfParticipants: 3,
count: 5,
);
final resp = await ActivitySearchRepo.get(request);
_activityItems.addAll(resp.activityPlans);
} finally {
if (mounted) setState(() => _loading = false);
}
}
@override
Widget build(BuildContext context) {
final List<Widget> cards = _activityItems
.map((activity) {
return ActivitySuggestionCard(
activity: activity,
onPressed: () {
showDialog(
context: context,
builder: (context) {
return ActivitySuggestionDialog(
activity: activity,
buttonText: L10n.of(context).inviteAndLaunch,
room: widget.room,
final theme = Theme.of(context);
final List<Widget> cards = _loading
? List.generate(5, (i) {
return Shimmer.fromColors(
baseColor: theme.colorScheme.primary.withAlpha(20),
highlightColor: theme.colorScheme.primary.withAlpha(50),
child: Container(
height: cardHeight,
width: cardWidth,
margin: EdgeInsets.all(cardPadding),
decoration: BoxDecoration(
color: theme.colorScheme.surfaceContainer,
borderRadius: BorderRadius.circular(24.0),
),
),
);
})
: _activityItems
.map((activity) {
return ActivitySuggestionCard(
activity: activity,
onPressed: () {
showDialog(
context: context,
builder: (context) {
return ActivitySuggestionDialog(
activity: activity,
buttonText: L10n.of(context).inviteAndLaunch,
room: widget.room,
);
},
);
},
width: cardWidth,
height: cardHeight,
padding: cardPadding,
onChange: () {
if (mounted) setState(() {});
},
);
},
width: cardWidth,
height: cardHeight,
padding: cardPadding,
onChange: () {
if (mounted) setState(() {});
},
);
})
.cast<Widget>()
.toList();
})
.cast<Widget>()
.toList();
final scrollDirection = widget.scrollDirection ??
(_isColumnMode ? Axis.horizontal : Axis.vertical);