import 'package:flutter/material.dart'; import 'package:share_plus/share_plus.dart'; import '../../models/post_models.dart'; import '../../services/post_service.dart'; import '../../utils/invitation_utils.dart'; class PostViewPage extends StatefulWidget { final String postId; const PostViewPage({Key? key, required this.postId}) : super(key: key); @override _PostViewPageState createState() => _PostViewPageState(); } class _PostViewPageState extends State { bool _isLoading = true; DetailedPost? _post; String _errorMessage = ''; bool _isLiking = false; @override void initState() { super.initState(); _loadPost(); } Future _loadPost() async { setState(() { _isLoading = true; _errorMessage = ''; }); try { final result = await PostService.getPost(widget.postId); setState(() { if (result['success']) { _post = result['post']; } else { _errorMessage = result['message'] ?? 'Failed to load post'; } _isLoading = false; }); } catch (e) { setState(() { _errorMessage = 'Network error: $e'; _isLoading = false; }); } } Color _getAvatarColor(String displayName) { final colors = [ Color(0xFF32B0A5), Color(0xFF4600B9), Color(0xFF6A4C93), Color(0xFFFF6347), Color(0xFF32CD32), Color(0xFF9932CC), ]; int hash = displayName.hashCode; return colors[hash.abs() % colors.length]; } String _getAvatarLetter(String displayName) { return displayName.isNotEmpty ? displayName[0].toUpperCase() : '?'; } void _sharePost(DetailedPost post) { final shareText = '${post.creator.displayName} posted on Wesal.online:\n\n${post.body}'; Share.share(shareText); } Future _toggleLike() async { if (_isLiking || _post == null) return; setState(() { _isLiking = true; }); try { Map result; if (_post!.liked) { result = await PostService.unlikePost(_post!.id); } else { result = await PostService.likePost(_post!.id); } if (result['success']) { await _loadPost(); // Reload to get updated data } else { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(result['message'] ?? 'Failed to update like'), backgroundColor: Colors.red, ), ); } } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Network error occurred'), backgroundColor: Colors.red, ), ); } } finally { setState(() { _isLiking = false; }); } } Widget _buildLikedBySection() { if (_post == null || _post!.likes == 0) return SizedBox.shrink(); final displayUsers = _post!.likedUsers.take(3).toList(); return Container( margin: EdgeInsets.symmetric(horizontal: 16), child: GestureDetector( onTap: _showLikedUsers, child: Container( padding: EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: Offset(0, 2), ), ], ), child: Row( children: [ // Show up to 3 avatars ...displayUsers.asMap().entries.map((entry) { final index = entry.key; final user = entry.value; final avatarColor = _getAvatarColor(user.displayName); final avatarLetter = _getAvatarLetter(user.displayName); return Container( margin: EdgeInsets.only( right: index < displayUsers.length - 1 ? -8 : 0, ), child: CircleAvatar( radius: 16, backgroundColor: Colors.white, child: CircleAvatar( radius: 14, backgroundColor: avatarColor, child: Text( avatarLetter, style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 12, ), ), ), ), ); }).toList(), SizedBox(width: 12), Expanded( child: Text( _post!.likes == 1 ? 'Liked by ${_post!.likedUsers.first.displayName}' : _post!.likes == 2 ? 'Liked by ${_post!.likedUsers[0].displayName} and ${_post!.likedUsers[1].displayName}' : 'Liked by ${_post!.likedUsers[0].displayName}, ${_post!.likedUsers[1].displayName} and ${_post!.likes - 2} others', style: TextStyle(color: Colors.grey[700], fontSize: 14), ), ), Text( 'See all', style: TextStyle( color: Color(0xFF6A4C93), fontSize: 14, fontWeight: FontWeight.w500, ), ), SizedBox(width: 4), Icon(Icons.arrow_forward_ios, size: 12, color: Color(0xFF6A4C93)), ], ), ), ), ); } void _showLikedUsers() { if (_post == null || _post!.likedUsers.isEmpty) return; showModalBottomSheet( context: context, shape: RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), builder: (context) => Container( padding: EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( width: 50, height: 4, decoration: BoxDecoration( color: Colors.grey[300], borderRadius: BorderRadius.circular(2), ), ), SizedBox(height: 16), Text( 'Liked by', style: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, color: Colors.black87, ), ), SizedBox(height: 16), Flexible( child: ListView.builder( shrinkWrap: true, itemCount: _post!.likedUsers.length, itemBuilder: (context, index) { final user = _post!.likedUsers[index]; final avatarColor = _getAvatarColor(user.displayName); final avatarLetter = _getAvatarLetter(user.displayName); final relativeTime = InvitationUtils.getRelativeTime( user.likeTime, ); return ListTile( leading: CircleAvatar( radius: 20, backgroundColor: avatarColor, child: Text( avatarLetter, style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, ), ), ), title: Text( user.displayName, style: TextStyle( fontWeight: FontWeight.w500, fontSize: 16, ), ), subtitle: Text( relativeTime, style: TextStyle(color: Colors.grey[600], fontSize: 12), ), ); }, ), ), SizedBox(height: 16), ], ), ), ); } Widget _buildMockComments() { return Container( margin: EdgeInsets.symmetric(horizontal: 16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Comments', style: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, color: Colors.black87, ), ), SizedBox(height: 16), _buildComment( 'Ahmed Ali', 'Great post! This is exactly what I was thinking about.', '2h', false, ), _buildComment( 'Sara Ahmed', 'Thanks for sharing this. Very insightful!', '1h', false, ), _buildComment( 'Mohamed Hassan', 'I completely agree with your point here.', '45m', true, replyTo: 'Sara Ahmed', ), ], ), ); } Widget _buildComment( String name, String comment, String time, bool isReply, { String? replyTo, }) { final avatarColor = _getAvatarColor(name); final avatarLetter = _getAvatarLetter(name); return Container( margin: EdgeInsets.only(bottom: 16, left: isReply ? 40 : 0), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ CircleAvatar( radius: isReply ? 16 : 20, backgroundColor: avatarColor, child: Text( avatarLetter, style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: isReply ? 12 : 14, ), ), ), SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text( name, style: TextStyle( fontWeight: FontWeight.w600, fontSize: 14, color: Colors.black87, ), ), SizedBox(width: 8), Text( time, style: TextStyle(color: Colors.grey[600], fontSize: 12), ), ], ), if (replyTo != null) ...[ SizedBox(height: 4), Text.rich( TextSpan( children: [ TextSpan( text: 'Replying to ', style: TextStyle( color: Colors.grey[600], fontSize: 12, ), ), TextSpan( text: '@$replyTo', style: TextStyle( color: Color(0xFF6A4C93), fontSize: 12, fontWeight: FontWeight.w500, ), ), ], ), ), ], SizedBox(height: 4), Text( comment, style: TextStyle( fontSize: 14, height: 1.4, color: Colors.black87, ), ), SizedBox(height: 8), Row( children: [ TextButton( onPressed: () {}, style: TextButton.styleFrom( padding: EdgeInsets.zero, minimumSize: Size.zero, tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), child: Text( 'Like', style: TextStyle(color: Colors.grey[600], fontSize: 12), ), ), SizedBox(width: 16), TextButton( onPressed: () {}, style: TextButton.styleFrom( padding: EdgeInsets.zero, minimumSize: Size.zero, tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), child: Text( 'Reply', style: TextStyle(color: Colors.grey[600], fontSize: 12), ), ), ], ), ], ), ), ], ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Colors.white, elevation: 0, leading: IconButton( onPressed: () => Navigator.pop(context), icon: Icon(Icons.arrow_back, color: Colors.black87), ), title: Text( 'Post', style: TextStyle( color: Colors.black87, fontSize: 18, fontWeight: FontWeight.w600, ), ), ), backgroundColor: Color(0xFFF5F5F5), body: _buildBody(), ); } Widget _buildBody() { if (_isLoading) { return Center( child: CircularProgressIndicator( valueColor: AlwaysStoppedAnimation(Color(0xFF6A4C93)), ), ); } if (_errorMessage.isNotEmpty) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.error_outline, size: 64, color: Colors.grey[400]), SizedBox(height: 16), Text( _errorMessage, style: TextStyle(fontSize: 16, color: Colors.grey[600]), textAlign: TextAlign.center, ), SizedBox(height: 16), ElevatedButton( onPressed: _loadPost, style: ElevatedButton.styleFrom( backgroundColor: Color(0xFF6A4C93), foregroundColor: Colors.white, ), child: Text('Try Again'), ), ], ), ); } if (_post == null) { return Center(child: Text('Post not found')); } final creator = _post!.creator; final avatarColor = _getAvatarColor(creator.displayName); final avatarLetter = _getAvatarLetter(creator.displayName); final relativeTime = InvitationUtils.getRelativeTime(_post!.creationDate); return SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( margin: EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: Offset(0, 2), ), ], ), child: Padding( padding: EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ CircleAvatar( radius: 24, backgroundColor: avatarColor, child: Text( avatarLetter, style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 18, ), ), ), SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( creator.displayName, style: TextStyle( fontWeight: FontWeight.w600, fontSize: 18, color: Colors.black87, ), ), SizedBox(height: 2), Text( relativeTime, style: TextStyle( color: Colors.grey[600], fontSize: 14, ), ), ], ), ), IconButton( onPressed: () => _sharePost(_post!), icon: Icon( Icons.share_outlined, color: Colors.grey[600], ), ), ], ), SizedBox(height: 16), Text( _post!.body, style: TextStyle( fontSize: 16, height: 1.5, color: Colors.black87, ), ), SizedBox(height: 20), Row( children: [ IconButton( onPressed: _isLiking ? null : _toggleLike, icon: _isLiking ? SizedBox( width: 24, height: 24, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation( _post!.liked ? Colors.red : Colors.grey[600]!, ), ), ) : Icon( _post!.liked ? Icons.favorite : Icons.favorite_border, color: _post!.liked ? Colors.red : Colors.grey[600], size: 28, ), ), Text( '${_post!.likes}', style: TextStyle( color: Colors.grey[700], fontWeight: FontWeight.w500, fontSize: 16, ), ), SizedBox(width: 20), Icon( Icons.chat_bubble_outline, color: Colors.grey[600], size: 28, ), SizedBox(width: 8), Text( '${_post!.comments}', style: TextStyle( color: Colors.grey[700], fontWeight: FontWeight.w500, fontSize: 16, ), ), ], ), ], ), ), ), SizedBox(height: 8), _buildLikedBySection(), SizedBox(height: 16), _buildMockComments(), SizedBox(height: 24), ], ), ); } }