From d520739915d99a1128f50941ea49e8f81b8cd993 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 17 Jul 2025 08:28:11 +0300 Subject: [PATCH] feat: implement basic feed page --- lib/screens/pages/feed_page.dart | 304 +++++++++++++++++++++++- lib/screens/pages/invitations_page.dart | 19 +- lib/screens/pages/profile_page.dart | 19 +- 3 files changed, 324 insertions(+), 18 deletions(-) diff --git a/lib/screens/pages/feed_page.dart b/lib/screens/pages/feed_page.dart index dd8029f..a72374c 100644 --- a/lib/screens/pages/feed_page.dart +++ b/lib/screens/pages/feed_page.dart @@ -1,23 +1,303 @@ import 'package:flutter/material.dart'; -class FeedPage extends StatelessWidget { +class FeedPage extends StatefulWidget { + @override + _FeedPageState createState() => _FeedPageState(); +} + +class _FeedPageState extends State { + final List> mockPosts = [ + { + 'id': '1', + 'user': { + 'displayName': 'Ahmed Al-Rashid', + 'avatar': 'A', + 'avatar_color': Color(0xFF32B0A5), + }, + 'content': + 'Just had an amazing coffee at the new café downtown! The atmosphere is perfect for catching up with friends.', + 'timestamp': '2 hours ago', + 'likes': 12, + 'comments': 3, + 'isLiked': false, + }, + { + 'id': '2', + 'user': { + 'displayName': 'Sarah Mohammed', + 'avatar': 'S', + 'avatar_color': Color(0xFF4600B9), + }, + 'content': + 'Excited to announce that I just got accepted into the university! Time to start this new chapter of my life 🎓', + 'timestamp': '4 hours ago', + 'likes': 28, + 'comments': 7, + 'isLiked': true, + }, + { + 'id': '3', + 'user': { + 'displayName': 'Omar Hassan', + 'avatar': 'O', + 'avatar_color': Color(0xFF6A4C93), + }, + 'content': + 'The sunset view from my balcony tonight is absolutely breathtaking. Sometimes you just need to pause and appreciate the beauty around us.', + 'timestamp': '1 day ago', + 'likes': 45, + 'comments': 12, + 'isLiked': false, + }, + { + 'id': '4', + 'user': { + 'displayName': 'Fatima Al-Zahra', + 'avatar': 'F', + 'avatar_color': Color(0xFF32B0A5), + }, + 'content': + 'Finished reading an incredible book today. "The Seven Habits of Highly Effective People" - highly recommend it to anyone looking for personal development!', + 'timestamp': '2 days ago', + 'likes': 19, + 'comments': 5, + 'isLiked': true, + }, + ]; + @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text('Feed'), - backgroundColor: Color(0xFF6A4C93), - foregroundColor: Colors.white, + title: Text('Feed', style: TextStyle(fontWeight: FontWeight.w600)), + backgroundColor: Colors.white, + foregroundColor: Color(0xFF6A4C93), + elevation: 0, + bottom: PreferredSize( + preferredSize: Size.fromHeight(1), + child: Container(height: 1, color: Colors.grey[200]), + ), ), - body: Center( - child: Text( - 'This is the Feed Page', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.w500, - ), + body: RefreshIndicator( + onRefresh: () async { + await Future.delayed(Duration(seconds: 1)); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('Feed refreshed!'))); + }, + child: ListView.builder( + padding: EdgeInsets.symmetric(vertical: 8), + itemCount: mockPosts.length, + itemBuilder: (context, index) { + return PostCard( + post: mockPosts[index], + onLikePressed: () { + setState(() { + if (mockPosts[index]['isLiked']) { + mockPosts[index]['likes']--; + mockPosts[index]['isLiked'] = false; + } else { + mockPosts[index]['likes']++; + mockPosts[index]['isLiked'] = true; + } + }); + }, + ); + }, ), ), ); } -} \ No newline at end of file +} + +class PostCard extends StatefulWidget { + final Map post; + final VoidCallback onLikePressed; + + const PostCard({Key? key, required this.post, required this.onLikePressed}) + : super(key: key); + + @override + _PostCardState createState() => _PostCardState(); +} + +class _PostCardState extends State + with SingleTickerProviderStateMixin { + late AnimationController _likeAnimationController; + late Animation _likeAnimation; + + @override + void initState() { + super.initState(); + _likeAnimationController = AnimationController( + duration: Duration(milliseconds: 300), + vsync: this, + ); + _likeAnimation = Tween(begin: 1.0, end: 1.3).animate( + CurvedAnimation( + parent: _likeAnimationController, + curve: Curves.elasticOut, + ), + ); + } + + @override + void dispose() { + _likeAnimationController.dispose(); + super.dispose(); + } + + void _handleLike() { + widget.onLikePressed(); + _likeAnimationController.forward().then((_) { + _likeAnimationController.reverse(); + }); + } + + @override + Widget build(BuildContext context) { + final user = widget.post['user']; + final isLiked = widget.post['isLiked']; + + return Container( + margin: EdgeInsets.symmetric(horizontal: 16, vertical: 8), + 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: 20, + backgroundColor: user['avatar_color'], + child: Text( + user['avatar'], + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + user['displayName'], + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 16, + color: Colors.black87, + ), + ), + SizedBox(height: 2), + Text( + widget.post['timestamp'], + style: TextStyle(color: Colors.grey[600], fontSize: 12), + ), + ], + ), + ), + IconButton( + onPressed: () { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('More options pressed')), + ); + }, + icon: Icon(Icons.more_horiz, color: Colors.grey[600]), + ), + ], + ), + SizedBox(height: 12), + Text( + widget.post['content'], + style: TextStyle( + fontSize: 15, + height: 1.4, + color: Colors.black87, + ), + ), + SizedBox(height: 16), + Row( + children: [ + AnimatedBuilder( + animation: _likeAnimation, + builder: (context, child) { + return Transform.scale( + scale: _likeAnimation.value, + child: GestureDetector( + onTap: _handleLike, + child: Container( + padding: EdgeInsets.all(12), + child: Icon( + isLiked ? Icons.favorite : Icons.favorite_border, + color: isLiked ? Colors.red : Colors.grey[600], + size: 24, + ), + ), + ), + ); + }, + ), + Text( + '${widget.post['likes']}', + style: TextStyle( + color: Colors.grey[700], + fontWeight: FontWeight.w500, + ), + ), + SizedBox(width: 16), + IconButton( + onPressed: () { + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('Comments pressed'))); + }, + icon: Icon( + Icons.chat_bubble_outline, + color: Colors.grey[600], + size: 24, + ), + ), + Text( + '${widget.post['comments']}', + style: TextStyle( + color: Colors.grey[700], + fontWeight: FontWeight.w500, + ), + ), + Spacer(), + IconButton( + onPressed: () { + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('Share pressed'))); + }, + icon: Icon( + Icons.share_outlined, + color: Colors.grey[600], + size: 24, + ), + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/lib/screens/pages/invitations_page.dart b/lib/screens/pages/invitations_page.dart index a1ffff8..64a109b 100644 --- a/lib/screens/pages/invitations_page.dart +++ b/lib/screens/pages/invitations_page.dart @@ -5,9 +5,22 @@ class InvitationsPage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text('Invitations'), - backgroundColor: Color(0xFF6A4C93), - foregroundColor: Colors.white, + title: Text( + 'Invitations', + style: TextStyle( + fontWeight: FontWeight.w600, + ), + ), + backgroundColor: Colors.white, + foregroundColor: Color(0xFF6A4C93), + elevation: 0, + bottom: PreferredSize( + preferredSize: Size.fromHeight(1), + child: Container( + height: 1, + color: Colors.grey[200], + ), + ), ), body: Center( child: Text( diff --git a/lib/screens/pages/profile_page.dart b/lib/screens/pages/profile_page.dart index 5f6b40d..a7a1e5e 100644 --- a/lib/screens/pages/profile_page.dart +++ b/lib/screens/pages/profile_page.dart @@ -5,9 +5,22 @@ class ProfilePage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text('Profile'), - backgroundColor: Color(0xFF6A4C93), - foregroundColor: Colors.white, + title: Text( + 'Profile', + style: TextStyle( + fontWeight: FontWeight.w600, + ), + ), + backgroundColor: Colors.white, + foregroundColor: Color(0xFF6A4C93), + elevation: 0, + bottom: PreferredSize( + preferredSize: Size.fromHeight(1), + child: Container( + height: 1, + color: Colors.grey[200], + ), + ), ), body: Center( child: Text(