Messaging App Initial Commit

Pages Already Implemented Login and Registeration Page
This commit is contained in:
2025-01-01 00:35:25 +00:00
commit 8ec33980c6
14 changed files with 970 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
//const endPoint = 'http://10.15.45.11/v1';
const endPoint = 'https://api.theonasanyas.com/v1';
const projectId = 'chatapp';
const selfSigned = false;
const databaseId = '676d7bc5000ffc9ca2a4';
const userCollectionId = '676d7d05000253c91d27';
const chatsCollectionId = '67734e8b002936f64abd';
const convCollectionId = '67734e7f00205b8f40a6';
const imageStorageBucket = '6771b9000011f84c14fa';
+158
View File
@@ -0,0 +1,158 @@
import 'dart:io';
import 'package:appwrite/appwrite.dart';
import 'package:appwrite/models.dart' as models;
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:messaging_app/components/constants.dart';
import 'package:messaging_app/service/navigation_service.dart';
import 'package:messaging_app/service/snackbar_service.dart';
enum AuthStatus {
notAuthenticated,
authenticated,
authenticating,
userNotFound,
error,
}
class MessagingProviders extends ChangeNotifier {
//
Client client = Client();
late final Account account;
late final Databases database;
late final Storage storage;
// Auth Status
AuthStatus? status;
//User Details
models.User? user;
models.Session? session;
// var _email;
// var _name;
// var _imageURL;
// var _timeStamp;
static MessagingProviders instance = MessagingProviders();
MessagingProviders() {
init();
loadUser();
}
init() {
client.setEndpoint(endPoint).setProject(projectId).setSelfSigned();
account = Account(client);
database = Databases(client);
storage = Storage(client);
}
loadUser() async {
try {
user = await account.get();
status = AuthStatus.authenticated;
} catch (e) {
status = AuthStatus.notAuthenticated;
} finally {
notifyListeners();
}
}
void loginWithEmailAndPassword(String _email, String _password) async {
//
status = AuthStatus.authenticating;
notifyListeners();
try {
session = await account.createEmailPasswordSession(
email: _email, password: _password);
// user = await account.get();
status = AuthStatus.authenticated;
SnackBarService.instance.showSnackBarSuccess("Welcome! ${user!.name}");
NavigationService.instance.navigateToReplacement("home");
// account.deleteSession(sessionId: 'current');
} on AppwriteException catch (e) {
SnackBarService.instance.showSnackBarError(e.message!);
status = AuthStatus.error;
user = null;
//
} on Exception catch (e) {
SnackBarService.instance.showSnackBarError(e.toString());
//
}
notifyListeners();
}
Future<void> createUser(String _email, String _password,
Future<void> onSuccess(String _uid)) async {
try {
models.User _user = await account.create(
userId: ID.unique(), email: _email, password: _password);
status = AuthStatus.authenticated;
await onSuccess(_user.$id);
SnackBarService.instance.showSnackBarSuccess("Welcome! ${_user.email}");
NavigationService.instance.goBack();
NavigationService.instance.navigateToReplacement("home");
} on AppwriteException catch (e) {
status = AuthStatus.error;
user = null;
SnackBarService.instance.showSnackBarError(e.message!);
} on Exception catch (e) {
SnackBarService.instance.showSnackBarError(e.toString());
//
}
notifyListeners();
}
Future<void> createUserInDB(
String _documentId, String _email, String _name, String _imageURL) async {
try {
await database.createDocument(
databaseId: databaseId,
collectionId: userCollectionId,
documentId: _documentId,
data: {
"name": _name,
"email": _email,
"timeStamp": DateTime.now().toUtc().toIso8601String(),
"image": _imageURL
});
status = AuthStatus.authenticated;
} on AppwriteException catch (e) {
SnackBarService.instance.showSnackBarError(e.message!);
//
} on Exception catch (e) {
SnackBarService.instance.showSnackBarError(e.toString());
//
}
notifyListeners();
}
uploadUserImage(XFile? file, String _uid) async {
try {
File _file = File(file!.path);
var _test = await storage.createFile(
bucketId: imageStorageBucket,
fileId: ID.unique(),
file: InputFile.fromPath(path: _file.path, filename: file.name),
permissions: [
Permission.read(Role.any()),
],
);
return "$endPoint/storage/buckets/${_test.bucketId}/files/${_test.$id}/view?project=$projectId";
} on AppwriteException catch (e) {
SnackBarService.instance.showSnackBarError(e.message!);
print(e.message);
//
} on Exception catch (e) {
SnackBarService.instance.showSnackBarError(e.toString());
//
}
notifyListeners();
}
}
+17
View File
@@ -0,0 +1,17 @@
import 'package:flutter/material.dart';
import 'package:messaging_app/pages/home_page.dart';
import 'package:messaging_app/pages/login_page.dart';
import 'package:messaging_app/pages/registeration_page.dart';
class MessagingRoutes {
//
static MessagingRoutes instance = MessagingRoutes();
Map<String, WidgetBuilder> get messagingRoutes {
return {
"login": (BuildContext _context) => LoginPage(),
"register": (BuildContext _context) => RegisterationPage(),
"home": (BuildContext _context) => HomePage(),
};
}
}
+35
View File
@@ -0,0 +1,35 @@
import 'package:flutter/material.dart';
import 'package:messaging_app/components/messaging_routes.dart';
import 'package:messaging_app/service/navigation_service.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MessagingApp());
}
class MessagingApp extends StatelessWidget {
const MessagingApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Messaging App',
navigatorKey: NavigationService.instance.navigatorKey,
theme: ThemeData(
brightness: Brightness.dark,
scaffoldBackgroundColor: Colors.black,
primaryColor: Color.fromRGBO(42, 117, 188, 1.0),
colorScheme: ColorScheme.dark(),
useMaterial3: true,
),
routes: MessagingRoutes.instance.messagingRoutes,
initialRoute: "login",
// home: RegisterationPage(),
);
}
}
+26
View File
@@ -0,0 +1,26 @@
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<StatefulWidget> createState() {
//
return _HomePageState();
}
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
//
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: AppBar(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
title: Text("Messaging App"),
titleTextStyle: TextStyle(fontSize: 15),
),
);
}
}
+209
View File
@@ -0,0 +1,209 @@
import 'package:flutter/material.dart';
import 'package:messaging_app/components/messaging_provider.dart';
import 'package:messaging_app/service/navigation_service.dart';
import 'package:messaging_app/service/snackbar_service.dart';
import 'package:provider/provider.dart';
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@override
State<StatefulWidget> createState() {
return _LoginPageState();
}
}
class _LoginPageState extends State<LoginPage> {
//
var _deviceHeight;
var _deviceWidth;
String? _email;
String? _password;
late GlobalKey<FormState> _formKey;
late MessagingProviders _auth;
_LoginPageState() {
_formKey = GlobalKey<FormState>();
}
@override
Widget build(BuildContext context) {
//
_deviceHeight = MediaQuery.of(context).size.height;
_deviceWidth = MediaQuery.of(context).size.width;
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
body: Align(
child: ChangeNotifierProvider<MessagingProviders>.value(
value: MessagingProviders.instance,
child: _loginPageUI(),
),
//_loginPageUI(),
),
);
}
Widget _loginPageUI() {
return Builder(builder: (BuildContext _context) {
SnackBarService.instance.buildContext = _context;
_auth = Provider.of<MessagingProviders>(_context);
return Container(
height: _deviceHeight * 0.60,
// color: Colors.red,
padding: EdgeInsets.symmetric(horizontal: _deviceWidth * 0.10),
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_headingWidget(),
_inputForm(),
_loginButton(),
_registerButton(),
],
),
);
});
}
Widget _headingWidget() {
return SizedBox(
height: _deviceHeight * 0.12,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Welcome Back!',
style: TextStyle(fontSize: 35, fontWeight: FontWeight.w700),
),
Text(
'Please Login to your Account',
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w200),
)
],
),
);
}
Widget _inputForm() {
return SizedBox(
height: _deviceHeight * 0.16,
child: Form(
key: _formKey,
onChanged: () {
_formKey.currentState?.save();
},
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_emailTextField(),
_passwordTextField(),
],
),
),
);
}
Widget _emailTextField() {
return TextFormField(
autocorrect: false,
style: TextStyle(
color: Colors.white,
),
validator: (_input) {
return _input!.isNotEmpty && _input.contains("@")
? null
: "Please enter a valid Email";
},
onSaved: (_input) {
setState(() {
_email = _input!;
});
},
cursorColor: Colors.white,
decoration: InputDecoration(
hintText: "Email Address",
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white))),
);
}
Widget _passwordTextField() {
return TextFormField(
autocorrect: false,
style: TextStyle(
color: Colors.white,
),
validator: (_input) {
return _input!.isNotEmpty ? null : "Please enter a Password";
},
onSaved: (_input) {
setState(() {
_password = _input!;
});
},
obscureText: true,
cursorColor: Colors.white,
decoration: InputDecoration(
hintText: "Password",
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white))),
);
}
Widget _loginButton() {
return _auth.status == AuthStatus.authenticating
? Align(
alignment: Alignment.center,
child: CircularProgressIndicator(),
)
: SizedBox(
height: _deviceHeight * 0.06,
width: _deviceWidth,
child: MaterialButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
//Login User
_auth.loginWithEmailAndPassword(_email!, _password!);
}
},
color: Colors.blue,
child: Text(
'Login',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w700,
),
),
),
);
}
Widget _registerButton() {
return GestureDetector(
onTap: () {
NavigationService.instance.navigateTo("register");
},
child: SizedBox(
height: _deviceHeight * 0.06,
width: _deviceWidth,
child: Text(
'REGISTER',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w700,
),
),
),
);
}
}
+269
View File
@@ -0,0 +1,269 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:messaging_app/components/messaging_provider.dart';
import 'package:messaging_app/service/media_service.dart';
import 'package:messaging_app/service/navigation_service.dart';
import 'package:messaging_app/service/snackbar_service.dart';
import 'package:provider/provider.dart';
class RegisterationPage extends StatefulWidget {
const RegisterationPage({super.key});
@override
State<StatefulWidget> createState() {
return _RegisterationPageState();
}
}
class _RegisterationPageState extends State<RegisterationPage> {
//
var _deviceHeight;
var _deviceWidth;
XFile? _image;
String? _name;
String? _email;
String? _password;
late GlobalKey<FormState> _formKey;
late MessagingProviders _auth;
_RegisterationPageState() {
_formKey = GlobalKey<FormState>();
}
@override
Widget build(BuildContext context) {
//
_deviceHeight = MediaQuery.of(context).size.height;
_deviceWidth = MediaQuery.of(context).size.width;
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
body: Container(
// color: Colors.blue,
alignment: Alignment.center,
child: ChangeNotifierProvider<MessagingProviders>.value(
value: MessagingProviders.instance,
child: _registerationPageUI(),
),
),
);
}
Widget _registerationPageUI() {
return Builder(builder: (BuildContext _context) {
SnackBarService.instance.buildContext = _context;
_auth = Provider.of<MessagingProviders>(_context);
return Container(
// color: Colors.deepOrange,
height: _deviceHeight * 0.75,
padding: EdgeInsets.symmetric(horizontal: _deviceWidth * 0.10),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_headingWidget(),
_inputForm(),
_registerButton(),
_backToLoginPage(),
],
),
);
});
}
Widget _headingWidget() {
return SizedBox(
height: _deviceHeight * 0.12,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'SignUp to Enjoy!',
style: TextStyle(fontSize: 35, fontWeight: FontWeight.w700),
),
Text(
'Please enter your details',
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w200),
)
],
),
);
}
Widget _inputForm() {
return Container(
height: _deviceHeight * 0.35,
child: Form(
key: _formKey,
onChanged: () {
_formKey.currentState?.save();
},
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_imageSelectorWidgeet(),
_nameTextField(),
_emailTextField(),
_passwordTextField(),
],
),
),
);
}
Widget _imageSelectorWidgeet() {
return Align(
child: GestureDetector(
onTap: () async {
XFile? _imageFile = await MediaService.instance.getImageFromLibrary();
_imageFile!.name;
setState(() {
_image = _imageFile;
});
},
child: Container(
height: _deviceHeight * 0.10,
width: _deviceHeight * 0.10,
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.circular(500),
image: DecorationImage(
fit: BoxFit.cover,
image: _image != null
? Image.file(File(_image!.path)).image
: NetworkImage('https://i.pravatar.cc/1000'),
// image: NetworkImage('https://cdn0.iconfinder.com/data/icons/occupation-002/64/programmer-programming-occupation-avatar-512.png'),
)),
),
),
);
}
Widget _nameTextField() {
return TextFormField(
autocorrect: false,
style: TextStyle(
color: Colors.white,
),
validator: (_input) {
return _input!.isNotEmpty ? null : "Please enter a valid Name";
},
onSaved: (_input) {
setState(() {
_name = _input!;
});
},
cursorColor: Colors.white,
decoration: InputDecoration(
hintText: "Name",
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white))),
);
}
Widget _emailTextField() {
return TextFormField(
autocorrect: false,
style: TextStyle(
color: Colors.white,
),
validator: (_input) {
return _input!.isNotEmpty && _input.contains("@")
? null
: "Please enter a valid Email";
},
onSaved: (_input) {
setState(() {
_email = _input!;
});
},
cursorColor: Colors.white,
decoration: InputDecoration(
hintText: "Email",
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white))),
);
}
Widget _passwordTextField() {
return TextFormField(
autocorrect: false,
style: TextStyle(
color: Colors.white,
),
validator: (_input) {
return _input!.isNotEmpty ? null : "Please enter a Password";
},
onSaved: (_input) {
setState(() {
_password = _input!;
});
},
obscureText: true,
cursorColor: Colors.white,
decoration: InputDecoration(
hintText: "Password",
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white))),
);
}
Widget _registerButton() {
return _auth.status == AuthStatus.authenticating
? Align(
child: CircularProgressIndicator(),
)
: SizedBox(
height: _deviceHeight * 0.06,
width: _deviceWidth,
child: MaterialButton(
onPressed: () {
if (_formKey.currentState!.validate() && _image != null) {
//
_auth.createUser(_email!, _password!, (String _uid) async {
var _url = await _auth.uploadUserImage(_image, _uid);
_auth.createUserInDB(_uid, _email!, _name!, _url);
if (_auth.status == AuthStatus.authenticated) {
_auth.loginWithEmailAndPassword(_email!, _password!);
}
//
});
//Login User
// _auth.loginWithEmailAndPassword(_email!, _password!);
}
},
color: Colors.blue,
child: Text(
'Register',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w700,
),
),
),
);
}
Widget _backToLoginPage() {
return GestureDetector(
onTap: () {
NavigationService.instance.goBack();
},
child: Container(
height: _deviceHeight * 0.06,
width: _deviceWidth,
child: Icon(
Icons.arrow_back,
size: 40,
),
),
);
}
}
+11
View File
@@ -0,0 +1,11 @@
import 'package:image_picker/image_picker.dart';
class MediaService {
//
static MediaService instance = MediaService();
Future<XFile?> getImageFromLibrary() async {
ImagePicker _picker = ImagePicker();
return await _picker.pickImage(source: ImageSource.gallery);
}
}
+29
View File
@@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
class NavigationService {
//
static NavigationService instance = NavigationService();
GlobalKey<NavigatorState>? navigatorKey;
NavigationService() {
navigatorKey = GlobalKey<NavigatorState>();
}
Future<dynamic>? navigateToReplacement(String _routeName) {
return navigatorKey!.currentState!.pushReplacementNamed(_routeName);
}
Future<dynamic>? navigateTo(String _routeName) {
return navigatorKey!.currentState!.pushNamed(_routeName);
}
Future<dynamic>? navigateToRoute(MaterialPageRoute _route) {
return navigatorKey!.currentState!.push(_route);
}
// Manually Call Function
goBack() {
return navigatorKey!.currentState!.pop();
}
}
+46
View File
@@ -0,0 +1,46 @@
import 'package:flutter/material.dart';
class SnackBarService {
//
BuildContext? _buildContext;
static SnackBarService instance = SnackBarService();
SnackBarService() {}
set buildContext(BuildContext _context) {
_buildContext = _context;
}
void showSnackBarError(String _message) {
ScaffoldMessenger.of(_buildContext!).showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
content: Text(
_message,
style: TextStyle(
color: Colors.white,
fontSize: 15,
),
),
backgroundColor: Colors.red,
),
);
}
void showSnackBarSuccess(String _message) {
ScaffoldMessenger.of(_buildContext!).showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
content: Text(
_message,
style: TextStyle(
color: Colors.white,
fontSize: 15,
),
),
backgroundColor: Colors.green,
),
);
}
}