···
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../constants/app_colors.dart';
···
/// - Periodic updates of time strings
/// - Deterministic testing without DateTime.now()
class PostCard extends StatelessWidget {
-
const PostCard({required this.post, this.currentTime, super.key});
final DateTime? currentTime;
Widget build(BuildContext context) {
···
const SizedBox(height: 8),
-
if (post.post.title != null) ...[
-
style: const TextStyle(
-
color: AppColors.textPrimary,
-
fontWeight: FontWeight.w400,
-
// Spacing after title (only if we have content below)
-
if (post.post.title != null &&
-
(post.post.embed?.external != null ||
-
post.post.text.isNotEmpty))
-
const SizedBox(height: 8),
-
// Embed (link preview)
-
if (post.post.embed?.external != null) ...[
-
embed: post.post.embed!.external!,
-
streamableService: context.read<StreamableService>(),
-
const SizedBox(height: 8),
-
// Post text body preview
-
if (post.post.text.isNotEmpty) ...[
-
padding: const EdgeInsets.all(10),
-
decoration: BoxDecoration(
-
color: AppColors.backgroundSecondary,
-
borderRadius: BorderRadius.circular(8),
-
color: AppColors.textPrimary.withValues(alpha: 0.7),
-
overflow: TextOverflow.ellipsis,
// External link (if present)
if (post.post.embed?.external != null) ...[
···
const SizedBox(height: 4),
-
PostCardActions(post: post),
···
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
+
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import '../constants/app_colors.dart';
···
/// - Periodic updates of time strings
/// - Deterministic testing without DateTime.now()
class PostCard extends StatelessWidget {
+
this.showCommentButton = true,
+
this.disableNavigation = false,
final DateTime? currentTime;
+
final bool showCommentButton;
+
final bool disableNavigation;
+
/// Check if this post should be clickable
+
/// Only text posts (no embeds or non-video/link embeds) are clickable
+
bool get _isClickable {
+
// If navigation is explicitly disabled (e.g., on detail screen), not clickable
+
if (disableNavigation) {
+
final embed = post.post.embed;
+
// If no embed, it's a text-only post - clickable
+
// If embed exists, check if it's a video or link type
+
final external = embed.external;
+
if (external == null) {
+
return true; // No external embed, clickable
+
final embedType = external.embedType;
+
// Video and video-stream posts should NOT be clickable (they have their own tap handling)
+
if (embedType == 'video' || embedType == 'video-stream') {
+
// Link embeds should NOT be clickable (they have their own link handling)
+
if (embedType == 'link') {
+
// All other types are clickable
+
void _navigateToDetail(BuildContext context) {
+
// Navigate to post detail screen
+
// Use URI-encoded version of the post URI for the URL path
+
// Pass the full post object via extras
+
final encodedUri = Uri.encodeComponent(post.post.uri);
+
context.push('/post/$encodedUri', extra: post);
Widget build(BuildContext context) {
···
const SizedBox(height: 8),
+
// Wrap content in InkWell if clickable (text-only posts)
+
onTap: () => _navigateToDetail(context),
+
crossAxisAlignment: CrossAxisAlignment.start,
+
if (post.post.title != null) ...[
+
style: const TextStyle(
+
color: AppColors.textPrimary,
+
fontWeight: FontWeight.w400,
+
// Spacing after title (only if we have text)
+
if (post.post.title != null && post.post.text.isNotEmpty)
+
const SizedBox(height: 8),
+
// Post text body preview
+
if (post.post.text.isNotEmpty) ...[
+
padding: const EdgeInsets.all(10),
+
decoration: BoxDecoration(
+
color: AppColors.backgroundSecondary,
+
borderRadius: BorderRadius.circular(8),
+
color: AppColors.textPrimary.withValues(alpha: 0.7),
+
overflow: TextOverflow.ellipsis,
+
// Non-clickable content (video/link posts)
+
crossAxisAlignment: CrossAxisAlignment.start,
+
if (post.post.title != null) ...[
+
style: const TextStyle(
+
color: AppColors.textPrimary,
+
fontWeight: FontWeight.w400,
+
// Spacing after title (only if we have content below)
+
if (post.post.title != null &&
+
(post.post.embed?.external != null ||
+
post.post.text.isNotEmpty))
+
const SizedBox(height: 8),
+
// Embed (link preview)
+
if (post.post.embed?.external != null) ...[
+
embed: post.post.embed!.external!,
+
streamableService: context.read<StreamableService>(),
+
const SizedBox(height: 8),
+
// Post text body preview
+
if (post.post.text.isNotEmpty) ...[
+
padding: const EdgeInsets.all(10),
+
decoration: BoxDecoration(
+
color: AppColors.backgroundSecondary,
+
borderRadius: BorderRadius.circular(8),
+
color: AppColors.textPrimary.withValues(alpha: 0.7),
+
overflow: TextOverflow.ellipsis,
// External link (if present)
if (post.post.embed?.external != null) ...[
···
const SizedBox(height: 4),
+
showCommentButton: showCommentButton,