diff --git a/CHANGELOG.md b/CHANGELOG.md index e1eff7db7..207258ba1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Added access to saved comments from account page - contribution from @CTalvio - Added Polish translation - contribution from @pazdikan - Show default avatar for users without an avatar - contribution from @coslu +- Added lock icon indicating a post is locked. Visible in feed and post view. Also blocks commenting functionality and instead shows a toast indicating the post is blocked - contribution from @ajsosa - Added the ability to combine the post FAB with the comment navigation buttons - contribution from @micahmo ### Changed diff --git a/lib/community/widgets/post_card_view_comfortable.dart b/lib/community/widgets/post_card_view_comfortable.dart index edc7fd506..6e671715a 100644 --- a/lib/community/widgets/post_card_view_comfortable.dart +++ b/lib/community/widgets/post_card_view_comfortable.dart @@ -106,6 +106,27 @@ class PostCardViewComfortable extends StatelessWidget { child: Text.rich( TextSpan( children: [ + if (postViewMedia.postView.post.locked) ...[ + WidgetSpan( + child: Icon( + Icons.lock, + color: indicateRead && postViewMedia.postView.read ? Colors.red.withOpacity(0.55) : Colors.red, + size: 17.0 * textScaleFactor, + )), + if (!postViewMedia.postView.post.featuredCommunity) + const WidgetSpan( + child: SizedBox( + width: 3, + )), + ], + if (postViewMedia.postView.post.featuredCommunity) + WidgetSpan( + child: Icon( + Icons.push_pin_rounded, + size: 17.0 * textScaleFactor, + color: indicateRead && postViewMedia.postView.read ? Colors.green.withOpacity(0.55) : Colors.green, + ), + ), TextSpan( text: postViewMedia.postView.post.name, style: theme.textTheme.bodyMedium?.copyWith( @@ -115,19 +136,6 @@ class PostCardViewComfortable extends StatelessWidget { : (indicateRead && postViewMedia.postView.read ? theme.textTheme.bodyMedium?.color?.withOpacity(0.55) : null), ), ), - if (postViewMedia.postView.post.featuredCommunity) - WidgetSpan( - child: Padding( - padding: const EdgeInsets.only( - left: 8.0, - ), - child: Icon( - Icons.push_pin_rounded, - size: 17.0 * textScaleFactor, - color: indicateRead && postViewMedia.postView.read ? Colors.green.withOpacity(0.55) : Colors.green, - ), - ), - ), if (!useSaveButton && postViewMedia.postView.saved) WidgetSpan( child: Padding( @@ -159,49 +167,58 @@ class PostCardViewComfortable extends StatelessWidget { ), if (!showTitleFirst) Padding( - padding: const EdgeInsets.only(top: 4.0, bottom: 6.0, left: 12.0, right: 12.0), - child: Text.rich( - TextSpan( - children: [ - TextSpan( - text: postViewMedia.postView.post.name, - style: theme.textTheme.bodyMedium?.copyWith( - fontWeight: FontWeight.w600, - color: indicateRead && postViewMedia.postView.read ? theme.textTheme.bodyMedium?.color?.withOpacity(0.65) : null, - ), - ), - if (postViewMedia.postView.post.featuredCommunity) - WidgetSpan( - child: Padding( - padding: const EdgeInsets.only( - left: 8.0, - ), + padding: const EdgeInsets.only(top: 4.0, bottom: 6.0, left: 12.0, right: 12.0), + child: Text.rich( + TextSpan( + children: [ + if (postViewMedia.postView.post.locked) ...[ + WidgetSpan( + child: Icon( + Icons.lock, + color: indicateRead && postViewMedia.postView.read ? Colors.red.withOpacity(0.55) : Colors.red, + size: 17.0 * textScaleFactor, + )), + if (!postViewMedia.postView.post.featuredCommunity) + const WidgetSpan( + child: SizedBox( + width: 3, + )), + ], + if (postViewMedia.postView.post.featuredCommunity) + WidgetSpan( child: Icon( Icons.push_pin_rounded, size: 17.0 * textScaleFactor, color: indicateRead && postViewMedia.postView.read ? Colors.green.withOpacity(0.55) : Colors.green, ), ), + TextSpan( + text: postViewMedia.postView.post.name, + style: theme.textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.w600, + color: postViewMedia.postView.post.featuredCommunity + ? (indicateRead && postViewMedia.postView.read ? Colors.green.withOpacity(0.55) : Colors.green) + : (indicateRead && postViewMedia.postView.read ? theme.textTheme.bodyMedium?.color?.withOpacity(0.55) : null), + ), ), - if (!useSaveButton && postViewMedia.postView.saved) - WidgetSpan( - child: Padding( - padding: const EdgeInsets.only( - left: 8.0, - ), - child: Icon( - Icons.star_rounded, - color: indicateRead && postViewMedia.postView.read ? Colors.purple.withOpacity(0.55) : Colors.purple, - size: 16.0 * textScaleFactor, - semanticLabel: 'Saved', + if (!useSaveButton && postViewMedia.postView.saved) + WidgetSpan( + child: Padding( + padding: const EdgeInsets.only( + left: 8.0, + ), + child: Icon( + Icons.star_rounded, + color: indicateRead && postViewMedia.postView.read ? Colors.purple.withOpacity(0.55) : Colors.purple, + size: 16.0 * textScaleFactor, + semanticLabel: 'Saved', + ), ), ), - ), - ], - ), - textScaleFactor: MediaQuery.of(context).textScaleFactor * textScaleFactor, - ), - ), + ], + ), + textScaleFactor: MediaQuery.of(context).textScaleFactor * textScaleFactor, + )), Visibility( visible: showTextContent && textContent.isNotEmpty, child: Padding( diff --git a/lib/community/widgets/post_card_view_compact.dart b/lib/community/widgets/post_card_view_compact.dart index 25a1ecf61..917807bb3 100644 --- a/lib/community/widgets/post_card_view_compact.dart +++ b/lib/community/widgets/post_card_view_compact.dart @@ -105,6 +105,27 @@ class PostCardViewCompact extends StatelessWidget { Text.rich( TextSpan( children: [ + if (postViewMedia.postView.post.locked) ...[ + WidgetSpan( + child: Icon( + Icons.lock, + color: indicateRead && postViewMedia.postView.read ? Colors.red.withOpacity(0.55) : Colors.red, + size: 17.0 * textScaleFactor, + )), + if (!postViewMedia.postView.post.featuredCommunity) + const WidgetSpan( + child: SizedBox( + width: 3, + )), + ], + if (postViewMedia.postView.post.featuredCommunity) + WidgetSpan( + child: Icon( + Icons.push_pin_rounded, + size: 17.0 * textScaleFactor, + color: indicateRead && postViewMedia.postView.read ? Colors.green.withOpacity(0.55) : Colors.green, + ), + ), TextSpan( text: postViewMedia.postView.post.name, style: theme.textTheme.bodyMedium?.copyWith( @@ -114,19 +135,6 @@ class PostCardViewCompact extends StatelessWidget { : (indicateRead && postViewMedia.postView.read ? theme.textTheme.bodyMedium?.color?.withOpacity(0.55) : null), ), ), - if (postViewMedia.postView.post.featuredCommunity) - WidgetSpan( - child: Padding( - padding: const EdgeInsets.only( - left: 8.0, - ), - child: Icon( - Icons.push_pin_rounded, - size: 17.0 * textScaleFactor, - color: indicateRead && postViewMedia.postView.read ? Colors.green.withOpacity(0.55) : Colors.green, - ), - ), - ), if (postViewMedia.postView.saved) WidgetSpan( child: Padding( diff --git a/lib/core/enums/fab_action.dart b/lib/core/enums/fab_action.dart index 4a648c2a5..1e9e913ce 100644 --- a/lib/core/enums/fab_action.dart +++ b/lib/core/enums/fab_action.dart @@ -142,7 +142,7 @@ enum PostFabAction { changeSort(), replyToPost(); - IconData getIcon({IconData? override}) { + IconData getIcon({IconData? override, bool postLocked = false}) { if (override != null) { return override; } @@ -155,11 +155,14 @@ enum PostFabAction { case PostFabAction.changeSort: return Icons.sort_rounded; case PostFabAction.replyToPost: + if (postLocked) { + return Icons.lock; + } return Icons.reply_rounded; } } - String getTitle(BuildContext context) { + String getTitle(BuildContext context, {bool postLocked = false}) { switch (this) { case PostFabAction.openFab: return AppLocalizations.of(context)!.open; @@ -168,6 +171,9 @@ enum PostFabAction { case PostFabAction.changeSort: return AppLocalizations.of(context)!.changeSort; case PostFabAction.replyToPost: + if (postLocked) { + return AppLocalizations.of(context)!.postLocked; + } return AppLocalizations.of(context)!.replyToPost; } } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 7f5cfbd8a..59d4afa49 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -48,6 +48,7 @@ "editComment": "Edit Comment", "reply": "Reply", "comment": "Comment", + "postLocked": "Post is locked, replies not allowed", "replyingTo": "Replying to {author}", "unexpectedError": "Unexpected Error", "fetchAccountError": "Could not determine account", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 0d7a261ae..51ebe2015 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -48,6 +48,7 @@ "editComment": "Editar comentario", "reply": "Responder", "comment": "Comentario", + "postLocked": "Post is locked, replies not allowed", "replyingTo": "Responder a {author}", "unexpectedError": "Error inesperado", "fetchAccountError": "No se pudo determinar la cuenta", diff --git a/lib/l10n/app_fi.arb b/lib/l10n/app_fi.arb index c6f532a86..c1ff88e92 100644 --- a/lib/l10n/app_fi.arb +++ b/lib/l10n/app_fi.arb @@ -48,6 +48,7 @@ "editComment": "Edit Comment", "reply": "Reply", "comment": "Comment", + "postLocked": "Post is locked, replies not allowed", "replyingTo": "Replying to {author}", "unexpectedError": "Unexpected Error", "fetchAccountError": "Could not determine account", diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index ab82212be..63baa0251 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -48,6 +48,7 @@ "editComment": "Edytuj komentarz", "reply": "Odpowiedz", "comment": "Comment", + "postLocked": "Post is locked, replies not allowed", "replyingTo": "Replying to {author}", "unexpectedError": "Wystąpił niespodziewany błąd", "fetchAccountError": "Nie można określić konta", diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb index c6f532a86..c1ff88e92 100644 --- a/lib/l10n/app_sv.arb +++ b/lib/l10n/app_sv.arb @@ -48,6 +48,7 @@ "editComment": "Edit Comment", "reply": "Reply", "comment": "Comment", + "postLocked": "Post is locked, replies not allowed", "replyingTo": "Replying to {author}", "unexpectedError": "Unexpected Error", "fetchAccountError": "Could not determine account", diff --git a/lib/post/pages/post_page.dart b/lib/post/pages/post_page.dart index f1f4ef62c..934147e48 100644 --- a/lib/post/pages/post_page.dart +++ b/lib/post/pages/post_page.dart @@ -92,6 +92,8 @@ class _PostPageState extends State { bool enableChangeSort = thunderState.postFabEnableChangeSort; bool enableReplyToPost = thunderState.postFabEnableReplyToPost; + bool postLocked = widget.postView?.postView.post.locked == true; + PostFabAction singlePressAction = thunderState.postFabSinglePressAction; PostFabAction longPressAction = thunderState.postFabLongPressAction; @@ -192,8 +194,8 @@ class _PostPageState extends State { centered: combineNavAndFab, distance: 60, icon: Icon( - singlePressAction.getIcon(override: singlePressAction == PostFabAction.changeSort ? sortTypeIcon : null), - semanticLabel: singlePressAction.getTitle(context), + singlePressAction.getIcon(override: singlePressAction == PostFabAction.changeSort ? sortTypeIcon : null, postLocked: postLocked), + semanticLabel: singlePressAction.getTitle(context, postLocked: postLocked), size: 35, ), onPressed: () => singlePressAction.execute( @@ -209,7 +211,7 @@ class _PostPageState extends State { : singlePressAction == PostFabAction.changeSort ? () => showSortBottomSheet(context, state) : singlePressAction == PostFabAction.replyToPost - ? () => replyToPost(context) + ? () => replyToPost(context, postLocked: postLocked) : null), onLongPress: () => longPressAction.execute( context: context, @@ -224,7 +226,7 @@ class _PostPageState extends State { : longPressAction == PostFabAction.changeSort ? () => showSortBottomSheet(context, state) : longPressAction == PostFabAction.replyToPost - ? () => replyToPost(context) + ? () => replyToPost(context, postLocked: postLocked) : null), children: [ if (enableReplyToPost) @@ -233,12 +235,12 @@ class _PostPageState extends State { onPressed: () { HapticFeedback.mediumImpact(); PostFabAction.replyToPost.execute( - override: () => replyToPost(context), + override: () => replyToPost(context, postLocked: postLocked), ); }, title: PostFabAction.replyToPost.getTitle(context), icon: Icon( - PostFabAction.replyToPost.getIcon(), + postLocked ? Icons.lock : PostFabAction.replyToPost.getIcon(), ), ), if (enableChangeSort) @@ -420,7 +422,11 @@ class _PostPageState extends State { ); } - void replyToPost(BuildContext context) { + void replyToPost(BuildContext context, {bool postLocked = false}) { + if (postLocked) { + showSnackbar(context, AppLocalizations.of(context)!.postLocked); + return; + } PostBloc postBloc = context.read(); ThunderBloc thunderBloc = context.read(); AuthBloc authBloc = context.read(); diff --git a/lib/post/widgets/post_view.dart b/lib/post/widgets/post_view.dart index 4d231de54..6a1084008 100644 --- a/lib/post/widgets/post_view.dart +++ b/lib/post/widgets/post_view.dart @@ -23,6 +23,8 @@ import 'package:thunder/user/utils/special_user_checks.dart'; import 'package:thunder/utils/instance.dart'; import 'package:thunder/utils/numbers.dart'; import 'package:thunder/utils/swipe.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:thunder/shared/snackbar.dart'; class PostSubview extends StatelessWidget { final PostViewMedia postViewMedia; @@ -272,6 +274,11 @@ class PostSubview extends StatelessWidget { child: IconButton( onPressed: isUserLoggedIn ? () { + if (postView.post.locked) { + showSnackbar(context, AppLocalizations.of(context)!.postLocked); + return; + } + PostBloc postBloc = context.read(); ThunderBloc thunderBloc = context.read(); account_bloc.AccountBloc accountBloc = context.read(); @@ -294,7 +301,9 @@ class PostSubview extends StatelessWidget { ); } : null, - icon: const Icon(Icons.reply_rounded, semanticLabel: 'Reply'), + icon: postView.post.locked + ? Icon(Icons.lock, semanticLabel: AppLocalizations.of(context)!.postLocked, color: Colors.red) + : Icon(Icons.reply_rounded, semanticLabel: AppLocalizations.of(context)!.reply), ), ), Expanded(