diff --git a/sojorn_app/lib/screens/post/threaded_conversation_screen.dart b/sojorn_app/lib/screens/post/threaded_conversation_screen.dart index 47e6745..c05c926 100644 --- a/sojorn_app/lib/screens/post/threaded_conversation_screen.dart +++ b/sojorn_app/lib/screens/post/threaded_conversation_screen.dart @@ -315,7 +315,7 @@ class _ThreadedConversationScreenState extends ConsumerState _navigateToPost(parentPost.id), child: Container( @@ -546,54 +546,69 @@ class _ThreadedConversationScreenState extends ConsumerState _toggleReaction(post.id, emoji), + onAdd: () => _openReactionPicker(post.id), ), - ), - const SizedBox(width: 12), - IconButton( - onPressed: () => _toggleLike(post), - icon: Icon( - isLiked ? Icons.favorite : Icons.favorite_border, - color: isLiked ? Colors.red : AppTheme.textSecondary, - ), - style: IconButton.styleFrom( - backgroundColor: AppTheme.navyBlue.withValues(alpha: 0.08), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), + const SizedBox(height: 16), + // Actions row - left aligned + Row( + children: [ + Expanded( + child: ElevatedButton.icon( + onPressed: post.allowChain + ? () { + _openReplyComposer(post); + } + : null, + icon: const Icon(Icons.reply, size: 18), + label: const Text('Reply'), + style: ElevatedButton.styleFrom( + backgroundColor: AppTheme.brightNavy, + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 14), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + ), ), - ), - ), - const SizedBox(width: 8), - IconButton( - onPressed: () => _toggleSave(post), - icon: Icon( - isSaved ? Icons.bookmark : Icons.bookmark_border, - color: isSaved ? AppTheme.brightNavy : AppTheme.textSecondary, - ), - style: IconButton.styleFrom( - backgroundColor: AppTheme.navyBlue.withValues(alpha: 0.08), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), + const SizedBox(width: 12), + IconButton( + onPressed: () => _toggleLike(post), + icon: Icon( + isLiked ? Icons.favorite : Icons.favorite_border, + color: isLiked ? Colors.red : AppTheme.textSecondary, + ), + style: IconButton.styleFrom( + backgroundColor: AppTheme.navyBlue.withValues(alpha: 0.08), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), ), - ), + const SizedBox(width: 8), + IconButton( + onPressed: () => _toggleSave(post), + icon: Icon( + isSaved ? Icons.bookmark : Icons.bookmark_border, + color: isSaved ? AppTheme.brightNavy : AppTheme.textSecondary, + ), + style: IconButton.styleFrom( + backgroundColor: AppTheme.navyBlue.withValues(alpha: 0.08), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + ), + ], ), ], ); @@ -657,99 +672,217 @@ class _ThreadedConversationScreenState extends ConsumerState - _toggleReaction(_focusContext!.targetPost.id, emoji), - onAdd: () => - _openReactionPicker(_focusContext!.targetPost.id), + margin: const EdgeInsets.fromLTRB(16, 16, 16, 0), + padding: const EdgeInsets.all(24), + decoration: BoxDecoration( + color: AppTheme.cardSurface, + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: AppTheme.navyBlue.withValues(alpha: 0.1), + width: 1, + ), + ), + child: Center( + child: Text( + 'No replies yet', + style: GoogleFonts.inter( + color: AppTheme.textSecondary, + fontSize: 14, ), - const SizedBox(height: 12), - Container( - width: double.infinity, - padding: const EdgeInsets.all(32), - decoration: BoxDecoration( - color: AppTheme.cardSurface, - borderRadius: BorderRadius.circular(22), - border: Border.all( - color: AppTheme.navyBlue.withValues(alpha: 0.12), - width: 2, - ), - ), - child: Center( - child: Column( - children: [ - Icon( - Icons.chat_bubble_outline, - size: 48, - color: AppTheme.textSecondary, - ), - const SizedBox(height: 16), - Text( - _focusContext!.targetPost.allowChain - ? 'Be the first to reply' - : 'Replies are disabled', - style: GoogleFonts.inter( - color: AppTheme.textSecondary, - fontSize: 16, - fontWeight: FontWeight.w500, - ), - ), - ], - ), - ), - ), - ], + ), ), ), ), ); } - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ReactionStrip( - reactions: _reactionCountsFor(_focusContext!.targetPost), - myReactions: _myReactionsFor(_focusContext!.targetPost), - reactionUsers: _reactionUsersFor(_focusContext!.targetPost), - onToggle: (emoji) => - _toggleReaction(_focusContext!.targetPost.id, emoji), - onAdd: () => - _openReactionPicker(_focusContext!.targetPost.id), + return SlideTransition( + position: _slideAnimation, + child: FadeTransition( + opacity: _fadeAnimation, + child: Container( + margin: const EdgeInsets.fromLTRB(16, 16, 16, 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Dashboard header + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: AppTheme.navyBlue.withValues(alpha: 0.05), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: AppTheme.navyBlue.withValues(alpha: 0.1), + ), + ), + child: Row( + children: [ + Icon( + Icons.chat_bubble_outline, + color: AppTheme.brightNavy, + size: 20, + ), + const SizedBox(width: 8), + Text( + '${children.length} ${children.length == 1 ? 'Reply' : 'Replies'}', + style: GoogleFonts.inter( + color: AppTheme.navyBlue, + fontSize: 16, + fontWeight: FontWeight.w600, + ), + ), + const Spacer(), + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + decoration: BoxDecoration( + color: AppTheme.brightNavy.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(20), + ), + child: Text( + 'Dashboard View', + style: GoogleFonts.inter( + color: AppTheme.brightNavy, + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ), + ], + ), + ), + const SizedBox(height: 16), + // Reply chains as dashboard items + ...children.asMap().entries.map((entry) { + final index = entry.key; + final post = entry.value; + return _buildDashboardReplyItem(post, index); + }).toList(), + ], ), - const SizedBox(height: 12), - Wrap( - spacing: 10, - runSpacing: 10, - children: children.asMap().entries.map((entry) { - final index = entry.key; - final post = entry.value; - return InteractiveReplyBlock( - key: ValueKey('reply_${post.id}'), - post: post, - compactPreview: true, - isLikedOverride: - _likedByPost[post.id] ?? (post.isLiked ?? false), - onToggleLike: () => _toggleLike(post), - onTap: () => _navigateToPost(post.id), - ) - .animate(delay: (index * 90).ms) - .fadeIn(duration: 300.ms, curve: Curves.easeOutCubic) - .slideY(begin: 0.06, end: 0, curve: Curves.easeOutBack); - }).toList(), + ), + ), + ); + } + + Widget _buildDashboardReplyItem(Post post, int index) { + return Container( + margin: const EdgeInsets.only(bottom: 12), + decoration: BoxDecoration( + color: AppTheme.cardSurface, + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: AppTheme.navyBlue.withValues(alpha: 0.08), + width: 1, + ), + boxShadow: [ + BoxShadow( + color: AppTheme.navyBlue.withValues(alpha: 0.04), + blurRadius: 8, + offset: const Offset(0, 2), ), ], ), - ); + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () => _navigateToPost(post.id), + borderRadius: BorderRadius.circular(16), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Reply header with menu button + Row( + children: [ + _buildCompactAvatar(post), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + post.author?.displayName ?? 'Anonymous', + style: GoogleFonts.inter( + color: AppTheme.navyBlue, + fontSize: 14, + fontWeight: FontWeight.w600, + ), + ), + Text( + timeago.format(post.createdAt), + style: GoogleFonts.inter( + color: AppTheme.textSecondary, + fontSize: 11, + ), + ), + ], + ), + ), + // Menu button + Container( + padding: const EdgeInsets.all(6), + decoration: BoxDecoration( + color: AppTheme.navyBlue.withValues(alpha: 0.05), + borderRadius: BorderRadius.circular(8), + ), + child: Icon( + Icons.more_horiz, + size: 16, + color: AppTheme.textSecondary, + ), + ), + ], + ), + const SizedBox(height: 12), + // Reply content + Text( + post.body, + style: GoogleFonts.inter( + color: AppTheme.navyText, + fontSize: 14, + height: 1.4, + ), + maxLines: 3, + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 12), + // Reply actions + Row( + children: [ + ReactionStrip( + reactions: _reactionCountsFor(post), + myReactions: _myReactionsFor(post), + reactionUsers: _reactionUsersFor(post), + onToggle: (emoji) => _toggleReaction(post.id, emoji), + onAdd: () => _openReactionPicker(post.id), + ), + const Spacer(), + Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), + decoration: BoxDecoration( + color: AppTheme.brightNavy.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(12), + ), + child: Text( + 'View Thread', + style: GoogleFonts.inter( + color: AppTheme.brightNavy, + fontSize: 11, + fontWeight: FontWeight.w600, + ), + ), + ), + ], + ), + ], + ), + ), + ), + ), + ).animate(delay: (index * 100).ms) + .fadeIn(duration: 300.ms, curve: Curves.easeOutCubic) + .slideY(begin: 0.04, end: 0, curve: Curves.easeOutBack); } void _toggleReaction(String postId, String emoji) {