Skip to content

Commit

Permalink
Fix issue marking multiple replies as read (#1305)
Browse files Browse the repository at this point in the history
  • Loading branch information
micahmo authored Apr 17, 2024
1 parent fde95c6 commit 37910e9
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 63 deletions.
7 changes: 3 additions & 4 deletions lib/inbox/bloc/inbox_bloc.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'package:bloc/bloc.dart';
import 'package:collection/collection.dart';
import 'package:equatable/equatable.dart';
import 'package:bloc_concurrency/bloc_concurrency.dart';
import 'package:lemmy_api_client/v3.dart';
Expand All @@ -8,7 +7,6 @@ import 'package:stream_transform/stream_transform.dart';
import 'package:thunder/account/models/account.dart';
import 'package:thunder/core/auth/helpers/fetch_account.dart';
import 'package:thunder/core/singletons/lemmy_client.dart';
import 'package:thunder/comment/utils/comment.dart';

part 'inbox_event.dart';
part 'inbox_state.dart';
Expand Down Expand Up @@ -40,7 +38,7 @@ class InboxBloc extends Bloc<InboxEvent, InboxState> {
_markReplyAsReadEvent,
// Do not throttle mark as read because it's something
// a user might try to do in quick succession to multiple messages
transformer: throttleDroppable(Duration.zero),
// Do not use any transformer, because a throttleDroppable will only process the first request and restartable will only process the last.
);
on<MarkMentionAsReadEvent>(
_markMentionAsReadEvent,
Expand Down Expand Up @@ -249,13 +247,14 @@ class InboxBloc extends Bloc<InboxEvent, InboxState> {

int totalUnreadCount = getUnreadCountResponse.privateMessages + getUnreadCountResponse.mentions + getUnreadCountResponse.replies;

emit(state.copyWith(
return emit(state.copyWith(
status: InboxStatus.success,
replies: replies,
totalUnreadCount: totalUnreadCount,
repliesUnreadCount: getUnreadCountResponse.replies,
mentionsUnreadCount: getUnreadCountResponse.mentions,
messagesUnreadCount: getUnreadCountResponse.privateMessages,
inboxReplyMarkedAsRead: event.commentReplyId,
));
} catch (e) {
return emit(state.copyWith(status: InboxStatus.failure, errorMessage: e.toString()));
Expand Down
6 changes: 6 additions & 0 deletions lib/inbox/bloc/inbox_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class InboxState extends Equatable {
this.hasReachedInboxReplyEnd = false,
this.hasReachedInboxMentionEnd = false,
this.hasReachedInboxPrivateMessageEnd = false,
this.inboxReplyMarkedAsRead,
});

final InboxStatus status;
Expand All @@ -44,6 +45,8 @@ class InboxState extends Equatable {
final bool hasReachedInboxMentionEnd;
final bool hasReachedInboxPrivateMessageEnd;

final int? inboxReplyMarkedAsRead;

InboxState copyWith({
required InboxStatus status,
String? errorMessage,
Expand All @@ -61,6 +64,7 @@ class InboxState extends Equatable {
bool? hasReachedInboxReplyEnd,
bool? hasReachedInboxMentionEnd,
bool? hasReachedInboxPrivateMessageEnd,
int? inboxReplyMarkedAsRead,
}) {
return InboxState(
status: status,
Expand All @@ -79,6 +83,7 @@ class InboxState extends Equatable {
hasReachedInboxReplyEnd: hasReachedInboxReplyEnd ?? this.hasReachedInboxReplyEnd,
hasReachedInboxMentionEnd: hasReachedInboxMentionEnd ?? this.hasReachedInboxMentionEnd,
hasReachedInboxPrivateMessageEnd: hasReachedInboxPrivateMessageEnd ?? this.hasReachedInboxPrivateMessageEnd,
inboxReplyMarkedAsRead: inboxReplyMarkedAsRead ?? this.inboxReplyMarkedAsRead,
);
}

Expand All @@ -100,5 +105,6 @@ class InboxState extends Equatable {
hasReachedInboxReplyEnd,
hasReachedInboxMentionEnd,
hasReachedInboxPrivateMessageEnd,
inboxReplyMarkedAsRead,
];
}
118 changes: 59 additions & 59 deletions lib/inbox/widgets/inbox_replies_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class InboxRepliesView extends StatefulWidget {
}

class _InboxRepliesViewState extends State<InboxRepliesView> {
int? inboxReplyMarkedAsRead;
List<int> inboxRepliesBeingMarkedAsRead = [];
List<int> inboxRepliesMarkedAsRead = [];

@override
Expand All @@ -54,19 +54,16 @@ class _InboxRepliesViewState extends State<InboxRepliesView> {
Widget build(BuildContext context) {
final DateTime now = DateTime.now().toUtc();

if (widget.replies.isEmpty) {
if (widget.replies.isEmpty || widget.replies.map((reply) => reply.commentReply.id).every((id) => inboxRepliesMarkedAsRead.contains(id))) {
return Align(alignment: Alignment.topCenter, heightFactor: (MediaQuery.of(context).size.height / 27), child: const Text('No replies'));
}

return BlocListener<InboxBloc, InboxState>(
listener: (context, state) {
if (state.status == InboxStatus.success) {
if (inboxReplyMarkedAsRead == null) return;

setState(() {
inboxRepliesMarkedAsRead.add(inboxReplyMarkedAsRead!);
inboxReplyMarkedAsRead = null;
});
if (state.status == InboxStatus.success && inboxRepliesBeingMarkedAsRead.isNotEmpty && state.inboxReplyMarkedAsRead != null) {
inboxRepliesBeingMarkedAsRead.remove(state.inboxReplyMarkedAsRead);
inboxRepliesMarkedAsRead.add(state.inboxReplyMarkedAsRead!);
setState(() {});
}
},
child: ListView.builder(
Expand All @@ -75,59 +72,62 @@ class _InboxRepliesViewState extends State<InboxRepliesView> {
physics: const NeverScrollableScrollPhysics(),
itemCount: widget.replies.length,
itemBuilder: (context, index) {
return Column(
children: [
Divider(
height: 1.0,
thickness: 1.0,
color: ElevationOverlay.applySurfaceTint(
Theme.of(context).colorScheme.surface,
Theme.of(context).colorScheme.surfaceTint,
10,
if (widget.showAll || !inboxRepliesMarkedAsRead.contains(widget.replies[index].commentReply.id)) {
return Column(
children: [
Divider(
height: 1.0,
thickness: 1.0,
color: ElevationOverlay.applySurfaceTint(
Theme.of(context).colorScheme.surface,
Theme.of(context).colorScheme.surfaceTint,
10,
),
),
),
CommentReference(
comment: widget.replies[index].toCommentView(),
now: now,
onVoteAction: (int commentId, int voteType) => context.read<PostBloc>().add(VoteCommentEvent(commentId: commentId, score: voteType)),
onSaveAction: (int commentId, bool save) => context.read<PostBloc>().add(SaveCommentEvent(commentId: commentId, save: save)),
onDeleteAction: (int commentId, bool deleted) => context.read<PostBloc>().add(DeleteCommentEvent(deleted: deleted, commentId: commentId)),
onReportAction: (int commentId) {
showReportCommentActionBottomSheet(
context,
commentId: commentId,
);
},
onReplyEditAction: (CommentView commentView, bool isEdit) async => navigateToCreateCommentPage(
context,
commentView: isEdit ? commentView : null,
parentCommentView: isEdit ? null : commentView,
onCommentSuccess: (commentView) {
context.read<PostBloc>().add(UpdateCommentEvent(commentView: commentView, isEdit: isEdit));
CommentReference(
comment: widget.replies[index].toCommentView(),
now: now,
onVoteAction: (int commentId, int voteType) => context.read<PostBloc>().add(VoteCommentEvent(commentId: commentId, score: voteType)),
onSaveAction: (int commentId, bool save) => context.read<PostBloc>().add(SaveCommentEvent(commentId: commentId, save: save)),
onDeleteAction: (int commentId, bool deleted) => context.read<PostBloc>().add(DeleteCommentEvent(deleted: deleted, commentId: commentId)),
onReportAction: (int commentId) {
showReportCommentActionBottomSheet(
context,
commentId: commentId,
);
},
onReplyEditAction: (CommentView commentView, bool isEdit) async => navigateToCreateCommentPage(
context,
commentView: isEdit ? commentView : null,
parentCommentView: isEdit ? null : commentView,
onCommentSuccess: (commentView) {
context.read<PostBloc>().add(UpdateCommentEvent(commentView: commentView, isEdit: isEdit));
},
),
isOwnComment: widget.replies[index].creator.id == context.read<AuthBloc>().state.account?.userId,
child: widget.replies[index].commentReply.read == false && !inboxRepliesMarkedAsRead.contains(widget.replies[index].commentReply.id)
? !inboxRepliesBeingMarkedAsRead.contains(widget.replies[index].commentReply.id)
? IconButton(
onPressed: () {
setState(() => inboxRepliesBeingMarkedAsRead.add(widget.replies[index].commentReply.id));
context.read<InboxBloc>().add(MarkReplyAsReadEvent(commentReplyId: widget.replies[index].commentReply.id, read: true, showAll: widget.showAll));
},
icon: const Icon(
Icons.check,
semanticLabel: 'Mark as read',
),
visualDensity: VisualDensity.compact,
)
: const Padding(
padding: EdgeInsets.symmetric(horizontal: 8.0),
child: SizedBox(width: 20, height: 20, child: CircularProgressIndicator()),
)
: null,
),
isOwnComment: widget.replies[index].creator.id == context.read<AuthBloc>().state.account?.userId,
child: widget.replies[index].commentReply.read == false && !inboxRepliesMarkedAsRead.contains(widget.replies[index].commentReply.id)
? inboxReplyMarkedAsRead != widget.replies[index].commentReply.id
? IconButton(
onPressed: () {
setState(() => inboxReplyMarkedAsRead = widget.replies[index].commentReply.id);
context.read<InboxBloc>().add(MarkReplyAsReadEvent(commentReplyId: widget.replies[index].commentReply.id, read: true, showAll: widget.showAll));
},
icon: const Icon(
Icons.check,
semanticLabel: 'Mark as read',
),
visualDensity: VisualDensity.compact,
)
: const Padding(
padding: EdgeInsets.symmetric(horizontal: 8.0),
child: SizedBox(width: 20, height: 20, child: CircularProgressIndicator()),
)
: null,
),
],
);
],
);
}
return Container();
},
),
);
Expand Down

0 comments on commit 37910e9

Please sign in to comment.