Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 0 additions & 1 deletion lib/community/widgets/post_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,6 @@ class _PostCardState extends State<PostCard> {
: PostCardViewComfortable(
postViewMedia: widget.postViewMedia,
hideThumbnails: state.hideThumbnails,
showThumbnailPreviewOnRight: state.showThumbnailPreviewOnRight,
hideNsfwPreviews: state.hideNsfwPreviews,
markPostReadOnMediaView: state.markPostReadOnMediaView,
feedType: widget.feedType,
Expand Down
135 changes: 89 additions & 46 deletions lib/community/widgets/post_card_actions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,27 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

import 'package:thunder/core/auth/bloc/auth_bloc.dart';
import 'package:thunder/thunder/bloc/thunder_bloc.dart';

/// Represents the actions that can be performed on a post when using the card view.
class PostCardActions extends StatelessWidget {
// Callback functions
final Function(int) onVoteAction;
final Function(bool) onSaveAction;
/// The current vote for the post. This can be 1 for upvote, -1 for downvote, or 0 for no vote.
final int voteType;

final int postId;
/// Whether the post is saved or not.
final bool saved;
final int voteType;

/// The callback function to execute when a vote action is performed.
final Function(int voteType) onVoteAction;

/// The callback function to execute when a save action is performed.
final Function(bool saved) onSaveAction;

const PostCardActions({
super.key,
required this.postId,
required this.voteType,
required this.saved,
required this.onVoteAction,
Expand All @@ -26,58 +31,96 @@ class PostCardActions extends StatelessWidget {

@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;

return BlocBuilder<ThunderBloc, ThunderState>(
buildWhen: (previous, current) {
return previous.upvoteColor != current.upvoteColor ||
previous.downvoteColor != current.downvoteColor ||
previous.saveColor != current.saveColor ||
previous.showVoteActions != current.showVoteActions ||
previous.showSaveAction != current.showSaveAction;
},
builder: (context, state) {
final bool showVoteActions = state.showVoteActions;
final bool showSaveAction = state.showSaveAction;
Color upvoteColor = state.upvoteColor.color;
Color downvoteColor = state.downvoteColor.color;
Color saveColor = state.saveColor.color;

final bool downvotesEnabled = context.read<AuthBloc>().state.downvotesEnabled;
bool showVoteActions = state.showVoteActions;
bool showSaveAction = state.showSaveAction;

return Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
bool upvoted = voteType == 1;
bool downvoted = voteType == -1;

return Wrap(
children: [
if (showVoteActions)
IconButton(
icon: Icon(
Icons.arrow_upward,
semanticLabel: voteType == 1 ? 'Upvoted' : 'Upvote',
),
color: voteType == 1 ? context.read<ThunderBloc>().state.upvoteColor.color : null,
visualDensity: VisualDensity.compact,
onPressed: () {
HapticFeedback.mediumImpact();
onVoteAction(voteType == 1 ? 0 : 1);
}),
if (showVoteActions && downvotesEnabled)
IconButton(
icon: Icon(
Icons.arrow_downward,
semanticLabel: voteType == -1 ? 'Downvoted' : 'Downvote',
),
color: voteType == -1 ? context.read<ThunderBloc>().state.downvoteColor.color : null,
visualDensity: VisualDensity.compact,
onPressed: () {
HapticFeedback.mediumImpact();
onVoteAction(voteType == -1 ? 0 : -1);
if (showVoteActions) ...[
PostCardAction(
icon: Icons.arrow_upward,
color: upvoted ? upvoteColor : null,
label: upvoted ? l10n.upvoted : l10n.upvote,
onPressed: () => onVoteAction(upvoted ? 0 : 1),
),
BlocSelector<AuthBloc, AuthState, bool>(
selector: (state) => state.downvotesEnabled,
builder: (context, downvotesEnabled) {
if (!downvotesEnabled) return const SizedBox.shrink();

return PostCardAction(
icon: Icons.arrow_downward,
color: downvoted ? downvoteColor : null,
label: downvoted ? l10n.downvoted : l10n.downvote,
onPressed: () => onVoteAction(downvoted ? 0 : -1),
);
},
),
],
if (showSaveAction)
IconButton(
icon: Icon(
saved ? Icons.star_rounded : Icons.star_border_rounded,
semanticLabel: saved ? 'Saved' : 'Save',
),
color: saved ? context.read<ThunderBloc>().state.saveColor.color : null,
visualDensity: VisualDensity.compact,
onPressed: () {
HapticFeedback.mediumImpact();
onSaveAction(saved ? false : true);
},
PostCardAction(
icon: saved ? Icons.star_rounded : Icons.star_border_rounded,
label: saved ? l10n.saved : l10n.save,
color: saved ? saveColor : null,
onPressed: () => onSaveAction(!saved),
),
],
);
},
);
}
}

/// Represents a single action that can be performed on a post when using the card view.
class PostCardAction extends StatelessWidget {
/// The icon to display for the action. The icon will generally change depending on the active state of the action.
final IconData icon;

/// The color of the icon. This color will change depending on the active state of the action.
final Color? color;

/// The semantic label for the icon. This is used for accessibility purposes.
final String label;

/// The callback function to execute when the action is pressed.
final Function() onPressed;

const PostCardAction({
super.key,
required this.icon,
required this.color,
required this.label,
required this.onPressed,
});

@override
Widget build(BuildContext context) {
return IconButton(
icon: Icon(icon, semanticLabel: label),
color: color,
visualDensity: VisualDensity.compact,
onPressed: () {
HapticFeedback.mediumImpact();
onPressed();
},
);
}
}
Loading