summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/main.dart34
-rw-r--r--lib/screens/chat_list_screen.dart152
-rw-r--r--lib/screens/chat_screen.dart176
-rw-r--r--lib/screens/login_screen.dart97
-rw-r--r--lib/screens/signup_screen.dart89
5 files changed, 548 insertions, 0 deletions
diff --git a/lib/main.dart b/lib/main.dart
new file mode 100644
index 0000000..2831b49
--- /dev/null
+++ b/lib/main.dart
@@ -0,0 +1,34 @@
+import 'package:flutter/material.dart';
+import 'screens/login_screen.dart';
+
+void main() {
+ runApp(const MessengerApp());
+}
+
+class MessengerApp extends StatelessWidget {
+ const MessengerApp({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp(
+ title: 'Messenger Clone',
+ debugShowCheckedModeBanner: false,
+ theme: ThemeData(
+ colorScheme: ColorScheme.fromSeed(
+ seedColor: const Color(0xFF2AABEE), // Messenger light blue
+ brightness: Brightness.light,
+ ),
+ useMaterial3: true,
+ ),
+ darkTheme: ThemeData(
+ colorScheme: ColorScheme.fromSeed(
+ seedColor: const Color(0xFF2AABEE),
+ brightness: Brightness.dark,
+ ),
+ useMaterial3: true,
+ ),
+ themeMode: ThemeMode.system,
+ home: const LoginScreen(),
+ );
+ }
+}
diff --git a/lib/screens/chat_list_screen.dart b/lib/screens/chat_list_screen.dart
new file mode 100644
index 0000000..f3e5d13
--- /dev/null
+++ b/lib/screens/chat_list_screen.dart
@@ -0,0 +1,152 @@
+import 'package:flutter/material.dart';
+import 'chat_screen.dart';
+import 'login_screen.dart';
+
+class ChatListScreen extends StatelessWidget {
+ const ChatListScreen({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ final chats = [
+ {'name': 'Alice Smith', 'msg': 'Hey, how are you?', 'time': '10:30 AM', 'unread': 2, 'color': Colors.red},
+ {'name': 'Bob Johnson', 'msg': 'Are we still on for tomorrow?', 'time': '9:45 AM', 'unread': 0, 'color': Colors.blue},
+ {'name': 'Charlie Brown', 'msg': 'I sent you the files.', 'time': 'Yesterday', 'unread': 0, 'color': Colors.green},
+ {'name': 'Design Team', 'msg': 'Dave: The new mocks look great.', 'time': 'Yesterday', 'unread': 5, 'color': Colors.purple},
+ {'name': 'Eve', 'msg': 'Ok.', 'time': 'Tuesday', 'unread': 0, 'color': Colors.orange},
+ ];
+
+ return Scaffold(
+ appBar: AppBar(
+ title: const Text('Messenger'),
+ backgroundColor: const Color(0xFF2AABEE),
+ foregroundColor: Colors.white,
+ actions: [
+ IconButton(icon: const Icon(Icons.search), onPressed: () {}),
+ ],
+ ),
+ drawer: Drawer(
+ child: ListView(
+ padding: EdgeInsets.zero,
+ children: [
+ const UserAccountsDrawerHeader(
+ accountName: Text('John Doe', style: TextStyle(fontWeight: FontWeight.bold)),
+ accountEmail: Text('johndoe@example.com'),
+ currentAccountPicture: CircleAvatar(
+ backgroundColor: Colors.white,
+ child: Text('J', style: TextStyle(fontSize: 24, color: Color(0xFF2AABEE))),
+ ),
+ decoration: BoxDecoration(color: Color(0xFF2AABEE)),
+ ),
+ ListTile(
+ leading: const Icon(Icons.group),
+ title: const Text('New Group'),
+ onTap: () {},
+ ),
+ ListTile(
+ leading: const Icon(Icons.person),
+ title: const Text('Contacts'),
+ onTap: () {},
+ ),
+ ListTile(
+ leading: const Icon(Icons.bookmark_border),
+ title: const Text('Saved Messages'),
+ onTap: () {},
+ ),
+ ListTile(
+ leading: const Icon(Icons.settings),
+ title: const Text('Settings'),
+ onTap: () {},
+ ),
+ const Divider(),
+ ListTile(
+ leading: const Icon(Icons.person_add),
+ title: const Text('Invite Friends'),
+ onTap: () {},
+ ),
+ ListTile(
+ leading: const Icon(Icons.help_outline),
+ title: const Text('Messenger Features'),
+ onTap: () {},
+ ),
+ const Divider(),
+ ListTile(
+ leading: const Icon(Icons.logout, color: Colors.red),
+ title: const Text('Log out', style: TextStyle(color: Colors.red)),
+ onTap: () {
+ Navigator.pushReplacement(
+ context,
+ MaterialPageRoute(builder: (context) => const LoginScreen()),
+ );
+ },
+ ),
+ ],
+ ),
+ ),
+ body: ListView.separated(
+ itemCount: chats.length,
+ separatorBuilder: (context, index) => const Divider(height: 1, indent: 72),
+ itemBuilder: (context, index) {
+ final chat = chats[index];
+ return ListTile(
+ leading: CircleAvatar(
+ backgroundColor: chat['color'] as Color,
+ radius: 26,
+ child: Text(
+ (chat['name'] as String)[0],
+ style: const TextStyle(color: Colors.white, fontSize: 20),
+ ),
+ ),
+ title: Text(
+ chat['name'] as String,
+ style: const TextStyle(fontWeight: FontWeight.bold),
+ ),
+ subtitle: Text(
+ chat['msg'] as String,
+ maxLines: 1,
+ overflow: TextOverflow.ellipsis,
+ ),
+ trailing: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ Text(
+ chat['time'] as String,
+ style: const TextStyle(color: Colors.grey, fontSize: 12),
+ ),
+ const SizedBox(height: 4),
+ if ((chat['unread'] as int) > 0)
+ Container(
+ padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
+ decoration: BoxDecoration(
+ color: const Color(0xFF2AABEE),
+ borderRadius: BorderRadius.circular(10),
+ ),
+ child: Text(
+ '${chat['unread']}',
+ style: const TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.bold),
+ ),
+ )
+ else
+ const SizedBox(height: 16),
+ ],
+ ),
+ onTap: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => ChatScreen(name: chat['name'] as String),
+ ),
+ );
+ },
+ );
+ },
+ ),
+ floatingActionButton: FloatingActionButton(
+ onPressed: () {},
+ backgroundColor: const Color(0xFF2AABEE),
+ foregroundColor: Colors.white,
+ child: const Icon(Icons.edit),
+ ),
+ );
+ }
+}
diff --git a/lib/screens/chat_screen.dart b/lib/screens/chat_screen.dart
new file mode 100644
index 0000000..35ea4a2
--- /dev/null
+++ b/lib/screens/chat_screen.dart
@@ -0,0 +1,176 @@
+import 'package:flutter/material.dart';
+
+class ChatScreen extends StatefulWidget {
+ final String name;
+
+ const ChatScreen({super.key, required this.name});
+
+ @override
+ State<ChatScreen> createState() => _ChatScreenState();
+}
+
+class _ChatScreenState extends State<ChatScreen> {
+ final _messageController = TextEditingController();
+ final List<Map<String, dynamic>> _messages = [
+ {'text': 'Hello!', 'isMe': false, 'time': '10:00 AM'},
+ {'text': 'Hi, how are you?', 'isMe': true, 'time': '10:05 AM'},
+ {'text': 'I am good, thanks! Are we meeting later?', 'isMe': false, 'time': '10:06 AM'},
+ ];
+
+ void _sendMessage() {
+ if (_messageController.text.trim().isEmpty) return;
+
+ setState(() {
+ _messages.add({
+ 'text': _messageController.text,
+ 'isMe': true,
+ 'time': 'Now',
+ });
+ _messageController.clear();
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final isDark = Theme.of(context).brightness == Brightness.dark;
+
+ return Scaffold(
+ appBar: AppBar(
+ backgroundColor: const Color(0xFF2AABEE),
+ foregroundColor: Colors.white,
+ titleSpacing: 0,
+ title: Row(
+ children: [
+ CircleAvatar(
+ radius: 18,
+ backgroundColor: Colors.white24,
+ child: Text(widget.name[0], style: const TextStyle(color: Colors.white, fontSize: 16)),
+ ),
+ const SizedBox(width: 12),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(widget.name, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
+ const Text('last seen recently', style: TextStyle(fontSize: 12, color: Colors.white70)),
+ ],
+ ),
+ ],
+ ),
+ actions: [
+ IconButton(icon: const Icon(Icons.call), onPressed: () {}),
+ IconButton(icon: const Icon(Icons.more_vert), onPressed: () {}),
+ ],
+ ),
+ body: Container(
+ color: isDark ? null : const Color(0xFFC8DCED), // Classic background color
+ child: Column(
+ children: [
+ Expanded(
+ child: ListView.builder(
+ padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
+ itemCount: _messages.length,
+ itemBuilder: (context, index) {
+ final msg = _messages[index];
+ final isMe = msg['isMe'] as bool;
+ return Align(
+ alignment: isMe ? Alignment.centerRight : Alignment.centerLeft,
+ child: ConstrainedBox(
+ constraints: BoxConstraints(
+ maxWidth: MediaQuery.of(context).size.width * 0.75,
+ ),
+ child: Container(
+ margin: const EdgeInsets.only(bottom: 8),
+ padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
+ decoration: BoxDecoration(
+ color: isMe
+ ? (isDark ? const Color(0xFF2AABEE) : const Color(0xFFEEFFDE))
+ : (isDark ? const Color(0xFF212D3B) : Colors.white),
+ borderRadius: BorderRadius.circular(16).copyWith(
+ bottomRight: isMe ? const Radius.circular(4) : const Radius.circular(16),
+ bottomLeft: !isMe ? const Radius.circular(4) : const Radius.circular(16),
+ ),
+ boxShadow: [
+ BoxShadow(
+ color: Colors.black.withOpacity(0.05),
+ blurRadius: 2,
+ offset: const Offset(0, 1),
+ ),
+ ],
+ ),
+ child: Wrap(
+ crossAxisAlignment: WrapCrossAlignment.end,
+ alignment: WrapAlignment.end,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(right: 8.0, bottom: 2.0),
+ child: Text(
+ msg['text'] as String,
+ style: TextStyle(
+ color: isDark
+ ? Colors.white
+ : (isMe ? Colors.black87 : Colors.black87),
+ fontSize: 16,
+ ),
+ ),
+ ),
+ Text(
+ msg['time'] as String,
+ style: TextStyle(
+ color: isDark
+ ? Colors.white54
+ : (isMe ? const Color(0xFF55A65A) : Colors.grey),
+ fontSize: 11,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ },
+ ),
+ ),
+ Container(
+ padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
+ color: Theme.of(context).scaffoldBackgroundColor,
+ child: SafeArea(
+ child: Row(
+ children: [
+ IconButton(
+ icon: const Icon(Icons.attach_file, color: Colors.grey),
+ onPressed: () {},
+ ),
+ Expanded(
+ child: TextField(
+ controller: _messageController,
+ decoration: InputDecoration(
+ hintText: 'Message',
+ border: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(24),
+ borderSide: BorderSide.none,
+ ),
+ filled: true,
+ fillColor: isDark ? const Color(0xFF212D3B) : Colors.grey[200],
+ contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
+ ),
+ onSubmitted: (_) => _sendMessage(),
+ ),
+ ),
+ const SizedBox(width: 8),
+ CircleAvatar(
+ backgroundColor: const Color(0xFF2AABEE),
+ child: IconButton(
+ icon: const Icon(Icons.send, color: Colors.white, size: 20),
+ onPressed: _sendMessage,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/screens/login_screen.dart b/lib/screens/login_screen.dart
new file mode 100644
index 0000000..9716df0
--- /dev/null
+++ b/lib/screens/login_screen.dart
@@ -0,0 +1,97 @@
+import 'package:flutter/material.dart';
+import 'chat_list_screen.dart';
+import 'signup_screen.dart';
+
+class LoginScreen extends StatefulWidget {
+ const LoginScreen({super.key});
+
+ @override
+ State<LoginScreen> createState() => _LoginScreenState();
+}
+
+class _LoginScreenState extends State<LoginScreen> {
+ final _emailController = TextEditingController();
+ final _passwordController = TextEditingController();
+
+ void _login() {
+ // Navigate to chat list on successful login
+ Navigator.pushReplacement(
+ context,
+ MaterialPageRoute(builder: (context) => const ChatListScreen()),
+ );
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: Center(
+ child: SingleChildScrollView(
+ padding: const EdgeInsets.all(24.0),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ const Icon(
+ Icons.chat_bubble_outline,
+ size: 100,
+ color: Color(0xFF2AABEE),
+ ),
+ const SizedBox(height: 32),
+ const Text(
+ 'Log in to Messenger',
+ style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
+ textAlign: TextAlign.center,
+ ),
+ const SizedBox(height: 8),
+ const Text(
+ 'Please enter your email and password.',
+ style: TextStyle(color: Colors.grey),
+ textAlign: TextAlign.center,
+ ),
+ const SizedBox(height: 32),
+ TextField(
+ controller: _emailController,
+ keyboardType: TextInputType.emailAddress,
+ decoration: const InputDecoration(
+ labelText: 'Email',
+ border: OutlineInputBorder(),
+ prefixIcon: Icon(Icons.email),
+ ),
+ ),
+ const SizedBox(height: 16),
+ TextField(
+ controller: _passwordController,
+ obscureText: true,
+ decoration: const InputDecoration(
+ labelText: 'Password',
+ border: OutlineInputBorder(),
+ prefixIcon: Icon(Icons.lock),
+ ),
+ ),
+ const SizedBox(height: 24),
+ ElevatedButton(
+ onPressed: _login,
+ style: ElevatedButton.styleFrom(
+ backgroundColor: const Color(0xFF2AABEE),
+ foregroundColor: Colors.white,
+ padding: const EdgeInsets.symmetric(vertical: 16),
+ ),
+ child: const Text('Log In', style: TextStyle(fontSize: 16)),
+ ),
+ const SizedBox(height: 16),
+ TextButton(
+ onPressed: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(builder: (context) => const SignupScreen()),
+ );
+ },
+ child: const Text('Don\'t have an account? Sign up'),
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/screens/signup_screen.dart b/lib/screens/signup_screen.dart
new file mode 100644
index 0000000..1a0511d
--- /dev/null
+++ b/lib/screens/signup_screen.dart
@@ -0,0 +1,89 @@
+import 'package:flutter/material.dart';
+import 'chat_list_screen.dart';
+
+class SignupScreen extends StatefulWidget {
+ const SignupScreen({super.key});
+
+ @override
+ State<SignupScreen> createState() => _SignupScreenState();
+}
+
+class _SignupScreenState extends State<SignupScreen> {
+ final _nameController = TextEditingController();
+ final _emailController = TextEditingController();
+ final _passwordController = TextEditingController();
+
+ void _signup() {
+ Navigator.pushAndRemoveUntil(
+ context,
+ MaterialPageRoute(builder: (context) => const ChatListScreen()),
+ (route) => false,
+ );
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: const Text('Sign Up'),
+ backgroundColor: Colors.transparent,
+ elevation: 0,
+ ),
+ body: Center(
+ child: SingleChildScrollView(
+ padding: const EdgeInsets.all(24.0),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ const Icon(
+ Icons.chat_bubble_outline,
+ size: 80,
+ color: Color(0xFF2AABEE),
+ ),
+ const SizedBox(height: 32),
+ TextField(
+ controller: _nameController,
+ decoration: const InputDecoration(
+ labelText: 'Full Name',
+ border: OutlineInputBorder(),
+ prefixIcon: Icon(Icons.person),
+ ),
+ ),
+ const SizedBox(height: 16),
+ TextField(
+ controller: _emailController,
+ keyboardType: TextInputType.emailAddress,
+ decoration: const InputDecoration(
+ labelText: 'Email',
+ border: OutlineInputBorder(),
+ prefixIcon: Icon(Icons.email),
+ ),
+ ),
+ const SizedBox(height: 16),
+ TextField(
+ controller: _passwordController,
+ obscureText: true,
+ decoration: const InputDecoration(
+ labelText: 'Password',
+ border: OutlineInputBorder(),
+ prefixIcon: Icon(Icons.lock),
+ ),
+ ),
+ const SizedBox(height: 24),
+ ElevatedButton(
+ onPressed: _signup,
+ style: ElevatedButton.styleFrom(
+ backgroundColor: const Color(0xFF2AABEE),
+ foregroundColor: Colors.white,
+ padding: const EdgeInsets.symmetric(vertical: 16),
+ ),
+ child: const Text('Sign Up', style: TextStyle(fontSize: 16)),
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}