Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A few post sheet improvements #1391

Merged
merged 6 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion lib/community/bloc/community_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import 'package:stream_transform/stream_transform.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

import 'package:thunder/community/enums/community_action.dart';
import 'package:thunder/core/models/post_view_media.dart';
micahmo marked this conversation as resolved.
Show resolved Hide resolved
import 'package:thunder/core/singletons/lemmy_client.dart';
import 'package:thunder/feed/utils/community.dart';
import 'package:thunder/shared/snackbar.dart';
import 'package:thunder/utils/global_context.dart';

part 'community_event.dart';
Expand Down Expand Up @@ -73,9 +75,17 @@ class CommunityBloc extends Bloc<CommunityEvent, CommunityState> {
emit(state.copyWith(status: CommunityStatus.fetching));

// Wait for one second before fetching the community information to get any updated information
Future.delayed(const Duration(seconds: 1)).then((value) async {
await Future.delayed(const Duration(seconds: 1)).then((value) async {
GetCommunityResponse? getCommunityResponse = await fetchCommunityInformation(id: event.communityId);
emit(state.copyWith(status: CommunityStatus.success, communityView: getCommunityResponse.communityView));

if (GlobalContext.context.mounted) {
if (event.value) {
showSnackbar(AppLocalizations.of(GlobalContext.context)!.subscribed);
} else {
showSnackbar(AppLocalizations.of(GlobalContext.context)!.unsubscribed);
}
}
});
} catch (e) {
return emit(state.copyWith(status: CommunityStatus.failure));
Expand Down
5 changes: 4 additions & 1 deletion lib/community/bloc/community_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ final class CommunityActionEvent extends CommunityEvent {
/// TODO: Change the dynamic type to the correct type(s) if possible
final dynamic value;

const CommunityActionEvent({required this.communityId, required this.communityAction, this.value});
/// An optional post associated with this action
final PostViewMedia? postViewMedia;
micahmo marked this conversation as resolved.
Show resolved Hide resolved

const CommunityActionEvent({required this.communityId, required this.communityAction, this.value, this.postViewMedia});
}

final class CommunityClearMessageEvent extends CommunityEvent {}
43 changes: 34 additions & 9 deletions lib/community/utils/post_card_action_helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -287,11 +287,13 @@ void showPostActionBottomModalSheet(
BuildContext context,
PostViewMedia postViewMedia, {
PostActionBottomSheetPage page = PostActionBottomSheetPage.general,
void Function(int userId)? onBlockedUser,
void Function(int userId)? onBlockedCommunity,
}) {
final bool isOwnPost = postViewMedia.postView.creator.id == context.read<AuthBloc>().state.account?.userId;

final bool isModerator =
context.read<AccountBloc>().state.moderates.any((CommunityModeratorView communityModeratorView) => communityModeratorView.community.id == postViewMedia.postView.community.id);
final int? currentUserId = context.read<AuthBloc>().state.account?.userId;

// Generate the list of default actions for the general page
final List<ExtendedPostCardActions> defaultPostCardActions = postCardActionItems
Expand Down Expand Up @@ -365,7 +367,7 @@ void showPostActionBottomModalSheet(
final List<ExtendedPostCardActions> userActions = postCardActionItems
.where((extendedAction) => [
PostCardAction.visitProfile,
PostCardAction.blockUser,
if (postViewMedia.postView.creator.id != currentUserId) PostCardAction.blockUser,
].contains(extendedAction.postCardAction))
.toList();

Expand Down Expand Up @@ -421,6 +423,8 @@ void showPostActionBottomModalSheet(
PostActionBottomSheetPage.instance: l10n.instanceActions,
},
outerContext: context,
onBlockedUser: onBlockedUser,
onBlockedCommunity: onBlockedCommunity,
),
);
}
Expand All @@ -444,6 +448,12 @@ class PostCardActionPicker extends StatefulWidget {
/// The context from whoever invoked this sheet (useful for blocs that would otherwise be missing)
final BuildContext outerContext;

/// Callback used to notify that we blocked a user
final void Function(int userId)? onBlockedUser;

/// Callback used to notify that we blocked a community
final Function(int userId)? onBlockedCommunity;

const PostCardActionPicker({
super.key,
required this.postViewMedia,
Expand All @@ -452,6 +462,8 @@ class PostCardActionPicker extends StatefulWidget {
required this.multiPostCardActions,
required this.titles,
required this.outerContext,
required this.onBlockedUser,
required this.onBlockedCommunity,
});

@override
Expand Down Expand Up @@ -644,8 +656,10 @@ class _PostCardActionPickerState extends State<PostCardActionPicker> {
pop = false;
break;
case PostCardAction.blockCommunity:
action =
() => widget.outerContext.read<CommunityBloc>().add(CommunityActionEvent(communityAction: CommunityAction.block, communityId: widget.postViewMedia.postView.community.id, value: true));
action = () {
widget.outerContext.read<CommunityBloc>().add(CommunityActionEvent(communityAction: CommunityAction.block, communityId: widget.postViewMedia.postView.community.id, value: true));
widget.onBlockedCommunity?.call(widget.postViewMedia.postView.community.id);
};
break;
case PostCardAction.upvote:
action = () => widget.outerContext
Expand All @@ -670,15 +684,26 @@ class _PostCardActionPickerState extends State<PostCardActionPicker> {
action = () => setState(() => page = PostActionBottomSheetPage.share);
break;
case PostCardAction.blockUser:
action = () => widget.outerContext.read<UserBloc>().add(UserActionEvent(userAction: UserAction.block, userId: widget.postViewMedia.postView.creator.id, value: true));
action = () {
widget.outerContext.read<UserBloc>().add(UserActionEvent(userAction: UserAction.block, userId: widget.postViewMedia.postView.creator.id, value: true));
widget.onBlockedCommunity?.call(widget.postViewMedia.postView.creator.id);
};
break;
case PostCardAction.subscribeToCommunity:
action =
() => widget.outerContext.read<CommunityBloc>().add(CommunityActionEvent(communityAction: CommunityAction.follow, communityId: widget.postViewMedia.postView.community.id, value: true));
action = () => widget.outerContext.read<CommunityBloc>().add(CommunityActionEvent(
communityAction: CommunityAction.follow,
communityId: widget.postViewMedia.postView.community.id,
value: true,
postViewMedia: widget.postViewMedia,
));
break;
case PostCardAction.unsubscribeFromCommunity:
action =
() => widget.outerContext.read<CommunityBloc>().add(CommunityActionEvent(communityAction: CommunityAction.follow, communityId: widget.postViewMedia.postView.community.id, value: false));
action = () => widget.outerContext.read<CommunityBloc>().add(CommunityActionEvent(
communityAction: CommunityAction.follow,
communityId: widget.postViewMedia.postView.community.id,
value: false,
postViewMedia: widget.postViewMedia,
));
break;
case PostCardAction.delete:
action = () => widget.outerContext
Expand Down
2 changes: 2 additions & 0 deletions lib/community/widgets/post_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ class _PostCardState extends State<PostCard> {
onLongPress: () => showPostActionBottomModalSheet(
context,
widget.postViewMedia,
onBlockedUser: (userId) => context.read<FeedBloc>().add(FeedDismissBlockedEvent(userId: userId)),
onBlockedCommunity: (communityId) => context.read<FeedBloc>().add(FeedDismissBlockedEvent(communityId: communityId)),
),
onTap: () async {
PostView postView = widget.postViewMedia.postView;
Expand Down
3 changes: 3 additions & 0 deletions lib/community/widgets/post_card_view_comfortable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import 'package:thunder/core/enums/media_type.dart';
import 'package:thunder/core/enums/view_mode.dart';
import 'package:thunder/core/models/post_view_media.dart';
import 'package:thunder/core/theme/bloc/theme_bloc.dart';
import 'package:thunder/feed/bloc/feed_bloc.dart';
import 'package:thunder/feed/view/feed_page.dart';
import 'package:thunder/shared/media_view.dart';
import 'package:thunder/shared/text/scalable_text.dart';
Expand Down Expand Up @@ -324,6 +325,8 @@ class PostCardViewComfortable extends StatelessWidget {
showPostActionBottomModalSheet(
context,
postViewMedia,
onBlockedUser: (userId) => context.read<FeedBloc>().add(FeedDismissBlockedEvent(userId: userId)),
onBlockedCommunity: (communityId) => context.read<FeedBloc>().add(FeedDismissBlockedEvent(communityId: communityId)),
);
HapticFeedback.mediumImpact();
}),
Expand Down
11 changes: 11 additions & 0 deletions lib/feed/bloc/feed_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ class FeedBloc extends Bloc<FeedEvent, FeedState> {
transformer: throttleDroppable(Duration.zero),
);

/// Handles dismissing posts from blocked users/communities
on<FeedDismissBlockedEvent>(
_onFeedDismissBlocked,
transformer: throttleDroppable(Duration.zero),
);

/// Handles hiding posts from the feed
on<FeedHidePostsFromViewEvent>(
_onFeedHidePostsFromView,
Expand Down Expand Up @@ -117,6 +123,11 @@ class FeedBloc extends Bloc<FeedEvent, FeedState> {
emit(state.copyWith(status: FeedStatus.success, dismissReadId: state.dismissReadId + 1));
}

/// Handles dismissing read posts from the feed
Future<void> _onFeedDismissBlocked(FeedDismissBlockedEvent event, Emitter<FeedState> emit) async {
emit(state.copyWith(status: FeedStatus.success, dismissBlockedUserId: event.userId, dismissBlockedCommunityId: event.communityId));
}

/// Handles scrolling to top of the feed
Future<void> _onFeedScrollToTop(ScrollToTopEvent event, Emitter<FeedState> emit) async {
emit(state.copyWith(status: FeedStatus.success, scrollId: state.scrollId + 1));
Expand Down
7 changes: 7 additions & 0 deletions lib/feed/bloc/feed_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ final class ScrollToTopEvent extends FeedEvent {}

final class FeedDismissReadEvent extends FeedEvent {}

final class FeedDismissBlockedEvent extends FeedEvent {
final int? communityId;
final int? userId;

const FeedDismissBlockedEvent({this.communityId, this.userId});
}

final class FeedHidePostsFromViewEvent extends FeedEvent {
final List<int> postIds;

Expand Down
14 changes: 14 additions & 0 deletions lib/feed/bloc/feed_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ final class FeedState extends Equatable {
this.message,
this.scrollId = 0,
this.dismissReadId = 0,
this.dismissBlockedUserId,
this.dismissBlockedCommunityId,
this.insertedPostIds = const [],
});

Expand Down Expand Up @@ -79,6 +81,12 @@ final class FeedState extends Equatable {
/// This id is used for dismissing already read posts in the feed
final int dismissReadId;

/// This id is used for dismissing posts from blocked users
final int? dismissBlockedUserId;

/// This id is used for dismissing posts from blocked communities
final int? dismissBlockedCommunityId;

/// The inserted post ids. This is used to prevent duplicate posts
final List<int> insertedPostIds;

Expand All @@ -101,6 +109,8 @@ final class FeedState extends Equatable {
String? message,
int? scrollId,
int? dismissReadId,
int? dismissBlockedUserId,
int? dismissBlockedCommunityId,
List<int>? insertedPostIds,
}) {
return FeedState(
Expand All @@ -122,6 +132,8 @@ final class FeedState extends Equatable {
message: message,
scrollId: scrollId ?? this.scrollId,
dismissReadId: dismissReadId ?? this.dismissReadId,
dismissBlockedUserId: dismissBlockedUserId,
dismissBlockedCommunityId: dismissBlockedCommunityId,
insertedPostIds: insertedPostIds ?? this.insertedPostIds,
);
}
Expand Down Expand Up @@ -151,6 +163,8 @@ final class FeedState extends Equatable {
message,
scrollId,
dismissReadId,
dismissBlockedUserId,
dismissBlockedCommunityId,
insertedPostIds
];
}
22 changes: 22 additions & 0 deletions lib/feed/view/feed_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,27 @@ class _FeedViewState extends State<FeedView> {
}
}

Future<void> dismissBlockedUsersAndCommunities(int? userId, int? communityId) async {
ThunderState state = context.read<ThunderBloc>().state;

FeedBloc feedBloc = context.read<FeedBloc>();
List<PostViewMedia> postViewMedias = feedBloc.state.postViewMedias;

if (postViewMedias.isNotEmpty) {
for (PostViewMedia postViewMedia in postViewMedias) {
if (postViewMedia.postView.creator.id == userId || postViewMedia.postView.community.id == communityId) {
setState(() => queuedForRemoval.add(postViewMedia.postView.post.id));
await Future.delayed(Duration(milliseconds: state.useCompactView ? 60 : 100));
}
}

await Future.delayed(const Duration(milliseconds: 500));

feedBloc.add(FeedHidePostsFromViewEvent(postIds: List.from(queuedForRemoval)));
setState(() => queuedForRemoval.clear());
}
}

@override
Widget build(BuildContext context) {
ThunderBloc thunderBloc = context.watch<ThunderBloc>();
Expand Down Expand Up @@ -280,6 +301,7 @@ class _FeedViewState extends State<FeedView> {
if (current.status == FeedStatus.initial) setState(() => showAppBarTitle = false);
if (previous.scrollId != current.scrollId) _scrollController.animateTo(0, duration: const Duration(milliseconds: 300), curve: Curves.easeInOut);
if (previous.dismissReadId != current.dismissReadId) dismissRead();
if (current.dismissBlockedUserId != null || current.dismissBlockedCommunityId != null) dismissBlockedUsersAndCommunities(current.dismissBlockedUserId, current.dismissBlockedCommunityId);
return true;
},
listener: (context, state) {
Expand Down
Loading