diff --git a/undomain/assets/Frame 15.png b/undomain/assets/Frame 15.png new file mode 100644 index 0000000..32c45b2 Binary files /dev/null and b/undomain/assets/Frame 15.png differ diff --git a/undomain/assets/box1.jpeg b/undomain/assets/box1.jpeg new file mode 100644 index 0000000..80786b2 Binary files /dev/null and b/undomain/assets/box1.jpeg differ diff --git a/undomain/assets/box2.jpeg b/undomain/assets/box2.jpeg new file mode 100644 index 0000000..f2638c8 Binary files /dev/null and b/undomain/assets/box2.jpeg differ diff --git a/undomain/assets/mess.jpeg b/undomain/assets/mess.jpeg new file mode 100644 index 0000000..fe7535d Binary files /dev/null and b/undomain/assets/mess.jpeg differ diff --git a/undomain/assets/pic.jpg b/undomain/assets/pic.jpg new file mode 100644 index 0000000..e9892c4 Binary files /dev/null and b/undomain/assets/pic.jpg differ diff --git a/undomain/lib/main.dart b/undomain/lib/main.dart index 1c68576..f7e275a 100644 --- a/undomain/lib/main.dart +++ b/undomain/lib/main.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:undomain/router/go_router.dart'; void main() { + WidgetsFlutterBinding.ensureInitialized(); runApp(const MyApp()); } diff --git a/undomain/lib/pages/authentication/email_verification/email_verification.dart b/undomain/lib/pages/authentication/email_verification/email_verification.dart index 6299109..f7404ea 100644 --- a/undomain/lib/pages/authentication/email_verification/email_verification.dart +++ b/undomain/lib/pages/authentication/email_verification/email_verification.dart @@ -1,15 +1,28 @@ import 'dart:async'; +import 'dart:convert'; +import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:pinput/pinput.dart'; import 'package:undomain/router/router_names.dart'; +import 'package:undomain/services/auth_services/authservices.dart'; +import 'package:undomain/util/colors/colors.dart'; +import 'package:undomain/util/global/global_function.dart'; import 'package:undomain/util/global/global_varibles.dart'; import 'package:undomain/util/textstyles/text_styles.dart'; import 'package:undomain/widgets/buttons/authpage_button.dart'; class EmailVerification extends StatefulWidget { - const EmailVerification({super.key}); + final String userid; + final bool isForRegister; + final String? email; + const EmailVerification({ + super.key, + required this.userid, + required this.isForRegister, + this.email, + }); @override State createState() => _EmailVerificationState(); @@ -18,7 +31,10 @@ class EmailVerification extends StatefulWidget { class _EmailVerificationState extends State { late Timer _timer; int _start = 60; - + bool _isLoading = false; + TextEditingController _pincontroller = TextEditingController(); + final GlobalFunction _globalFunction = GlobalFunction(); + final Authservices _authservices = Authservices(); @override void initState() { startTimer(); @@ -44,9 +60,55 @@ class _EmailVerificationState extends State { }); } - void _onSubmit(String pin) { - // Validate or verify PIN here - print("Entered Code: $pin"); + //request when complete the pinput + void _onSubmit(String pin) async { + setState(() { + _isLoading = true; + }); + if (pin.isEmpty || widget.userid.isEmpty) { + _globalFunction.snackBarMassage(context, "Empty User Data", 3); + return; + // GoRouter.of(context).goNamed(RouterNames.homePage); + } + + //for user registration + if (widget.isForRegister) { + final response = await _authservices.verifyNewUser( + userId: widget.userid, + verifyCode: pin, + ); + if (response["success"]) { + String base64String = response["user"]["profileUrl"]; + Uint8List imagesBytes = base64Decode(base64String); + GoRouter.of(context).goNamed( + RouterNames.homePage, + extra: { + "userId": response["user"]["id"], + "username": response["user"]["username"], + "email": response["user"]["email"], + "profileUrl": imagesBytes, + }, + ); + } else { + _globalFunction.snackBarMassage(context, response["massage"], 3); + } + //for password reset + } else { + final response = await _authservices.verifyResetPassword( + email: widget.email!, + otp: pin, + password: widget.userid, + ); + if (response["success"]) { + GoRouter.of(context).goNamed(RouterNames.loginPage); + } else { + _globalFunction.snackBarMassage(context, response["massage"], 3); + } + } + setState(() { + _isLoading = false; + _pincontroller.clear(); + }); } @override @@ -55,13 +117,22 @@ class _EmailVerificationState extends State { final defaultPinTheme = PinTheme( width: (pinputSize - 0.08) / 5, height: (pinputSize - 0.08) / 5, - textStyle: TextStyle(fontSize: 20, color: Colors.black), + textStyle: TextStyle(fontSize: 20, color: utilPrimaryBlack), decoration: BoxDecoration( - border: Border.all(color: Colors.grey), + // border: Border.all(color: utilPrimaryGrey), borderRadius: BorderRadius.circular(10), + color: utilPrimaryWhite, + boxShadow: [ + BoxShadow( + offset: Offset(1, 2), + blurRadius: 2, + color: utilPrimaryGrey.withOpacity(0.5), + ), + ], ), ); return Scaffold( + resizeToAvoidBottomInset: false, body: Padding( padding: EdgeInsets.symmetric( horizontal: authScreenPaddingH, @@ -80,6 +151,7 @@ class _EmailVerificationState extends State { SizedBox(height: MediaQuery.of(context).size.height * 0.02), //pinputs Pinput( + controller: _pincontroller, length: 5, keyboardType: TextInputType.number, onCompleted: _onSubmit, @@ -96,14 +168,20 @@ class _EmailVerificationState extends State { ], ), ) - : Text("Resend", style: textLabel), + : TextButton( + onPressed: () {}, + child: Text("Resend", style: textLabelRed), + ), ], ), SizedBox(height: MediaQuery.of(context).size.height * 0.08), Column( children: [ //verify button:to home page - AuthpageButton(path: RouterNames.homePage, text: "Verify"), + GestureDetector( + onTap: () => _onSubmit(_pincontroller.text), + child: AuthpageButton(text: "Verify", isLoading: _isLoading), + ), //to login page TextButton( onPressed: () { diff --git a/undomain/lib/pages/authentication/fogotpassword/fogot_password.dart b/undomain/lib/pages/authentication/fogotpassword/fogot_password.dart new file mode 100644 index 0000000..e5db645 --- /dev/null +++ b/undomain/lib/pages/authentication/fogotpassword/fogot_password.dart @@ -0,0 +1,185 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:undomain/router/router_names.dart'; +import 'package:undomain/services/auth_services/authservices.dart'; +import 'package:undomain/util/global/global_function.dart'; +import 'package:undomain/util/global/global_varibles.dart'; +import 'package:undomain/util/textstyles/text_styles.dart'; +import 'package:undomain/widgets/buttons/authpage_button.dart'; +import 'package:undomain/widgets/textboxes/authtext_box.dart'; + +class FogotPassword extends StatefulWidget { + const FogotPassword({super.key}); + + @override + State createState() => _FogotPasswordState(); +} + +class _FogotPasswordState extends State { + final TextEditingController _confirmpasswordcontroller = + TextEditingController(); + final TextEditingController _passwordcontroller = TextEditingController(); + final TextEditingController _emailcontroller = TextEditingController(); + final _formKey = GlobalKey(); + bool _isLoading = false; + final Authservices _authservices = Authservices(); + final GlobalFunction _globalFunction = GlobalFunction(); + //regexp for password + final RegExp passwordRegExp = RegExp( + r'^(?=.*[A-Za-z])(?=.*\d)(?=.*[!@#$%^&*(),.?":{}|<>]).{6,}$', + ); + String confirmpasswordHint = "@confirm password"; + bool isconfirmpasswordValid = true; + String passwordHint = "@password"; + String emailHint = "@email"; + bool isPasswordValid = true; + + Future _getCodeForResetPassword() async { + setState(() { + _isLoading = true; + }); + + final response = await _authservices.sendPasswordResetRequest( + email: _emailcontroller.text, + ); + if (response["success"]) { + GoRouter.of(context).goNamed( + RouterNames.verificationPage, + extra: { + "userId": _passwordcontroller.text, + "isFromRegister": false, + "email": response["user"]["id"], + }, + ); + } else { + _globalFunction.snackBarMassage(context, response["massage"], 3); + } + setState(() { + _isLoading = false; + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + resizeToAvoidBottomInset: false, + body: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: authScreenPaddingH, + vertical: authScreenPaddingV, + ), + child: Column( + children: [ + SizedBox(height: MediaQuery.of(context).size.height * 0.08), + //title + Column(children: [Text("Date NET.", style: textDisplay)]), + SizedBox(height: MediaQuery.of(context).size.height * 0.15), + //auth details + Form( + key: _formKey, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + //password + AuthtextBox( + isValid: isPasswordValid, + controller: _emailcontroller, + hint: emailHint, + isShow: false, + onSubmit: (p0) {}, + textInputAction: TextInputAction.next, + textInputType: TextInputType.emailAddress, + + validChecker: (value) => null, + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.02), + AuthtextBox( + isValid: isPasswordValid, + controller: _passwordcontroller, + hint: passwordHint, + isShow: false, + onSubmit: (p0) {}, + textInputAction: TextInputAction.next, + textInputType: TextInputType.name, + + validChecker: (value) => null, + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.02), + //confirm password + AuthtextBox( + controller: _confirmpasswordcontroller, + isValid: isconfirmpasswordValid, + hint: confirmpasswordHint, + isShow: false, + onSubmit: (p0) {}, + textInputAction: TextInputAction.done, + textInputType: TextInputType.visiblePassword, + validChecker: (value) => null, + ), + + SizedBox(height: MediaQuery.of(context).size.height * 0.25), + Column( + children: [ + //if valid form state + GestureDetector( + onTap: () async { + if (_confirmpasswordcontroller.text.isEmpty && + _passwordcontroller.text.isEmpty) { + setState(() { + isPasswordValid = false; + passwordHint = "please enter your @password"; + isconfirmpasswordValid = false; + confirmpasswordHint = + "please confirm your password"; + }); + } else if (!passwordRegExp.hasMatch( + _passwordcontroller.text, + )) { + setState(() { + passwordHint = "weak password"; + _passwordcontroller.clear(); + }); + } else if (_passwordcontroller.text != + _confirmpasswordcontroller.text) { + setState(() { + confirmpasswordHint = + "password mismatching please check your password"; + _confirmpasswordcontroller.clear(); + }); + } else { + await _getCodeForResetPassword(); + } + }, + + child: AuthpageButton( + text: "Submit", + isLoading: false, + ), + ), + //to register page + TextButton( + onPressed: () { + GoRouter.of( + context, + ).goNamed(RouterNames.registerPage); + }, + child: Text( + "Create new account", + style: textLabelRed, + ), + ), + ], + ), + + //to home page + ], + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/undomain/lib/pages/authentication/login/login_screen.dart b/undomain/lib/pages/authentication/login/login_screen.dart index 5910e57..d563323 100644 --- a/undomain/lib/pages/authentication/login/login_screen.dart +++ b/undomain/lib/pages/authentication/login/login_screen.dart @@ -1,6 +1,11 @@ +import 'dart:convert'; +import 'dart:typed_data'; + import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:undomain/router/router_names.dart'; +import 'package:undomain/services/auth_services/authservices.dart'; +import 'package:undomain/util/global/global_function.dart'; import 'package:undomain/util/global/global_varibles.dart'; import 'package:undomain/util/textstyles/text_styles.dart'; import 'package:undomain/widgets/buttons/authpage_button.dart'; @@ -16,7 +21,10 @@ class LoginScreen extends StatefulWidget { class _LoginScreenState extends State { final TextEditingController _usernamecontroller = TextEditingController(); final TextEditingController _passwordcontroller = TextEditingController(); - + final _formKey = GlobalKey(); + bool _isLoading = false; + final GlobalFunction _globalFunction = GlobalFunction(); + final Authservices _authservices = Authservices(); @override void dispose() { _passwordcontroller.dispose(); @@ -24,9 +32,45 @@ class _LoginScreenState extends State { super.dispose(); } + Future _userLogin() async { + setState(() { + _isLoading = true; + }); + + final response = await _authservices.login( + username: _usernamecontroller.text, + password: _passwordcontroller.text, + ); + if (response["success"]) { + String base64String = response["user"]["profileUrl"]; + Uint8List imagesBytes = base64Decode(base64String); + //MemoryImage(bytes) + GoRouter.of(context).goNamed( + RouterNames.homePage, + extra: { + "userId": response["user"]["id"], + "username": response["user"]["username"], + "email": response["user"]["email"], + "profileUrl": imagesBytes, + }, + ); + } else { + _globalFunction.snackBarMassage(context, response["massage"], 3); + } + setState(() { + _isLoading = false; + }); + } + + //login validation frontend properties + String usernameHint = "@username"; + bool isUsernameValid = true; + String passwordHint = "@password"; + bool isPasswordValid = true; @override Widget build(BuildContext context) { return Scaffold( + resizeToAvoidBottomInset: false, body: SingleChildScrollView( child: Padding( padding: EdgeInsets.symmetric( @@ -41,33 +85,65 @@ class _LoginScreenState extends State { SizedBox(height: MediaQuery.of(context).size.height * 0.15), //auth details Form( + key: _formKey, child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ AuthtextBox( + isValid: isUsernameValid, controller: _usernamecontroller, - hint: "@username", + hint: usernameHint, isShow: false, onSubmit: (p0) {}, textInputAction: TextInputAction.next, textInputType: TextInputType.name, + + validChecker: (value) => null, ), SizedBox(height: MediaQuery.of(context).size.height * 0.02), //password AuthtextBox( controller: _passwordcontroller, - hint: "@password", + isValid: isPasswordValid, + hint: passwordHint, isShow: false, onSubmit: (p0) {}, textInputAction: TextInputAction.done, textInputType: TextInputType.visiblePassword, + validChecker: (value) => null, ), - SizedBox(height: MediaQuery.of(context).size.height * 0.3), + SizedBox(height: MediaQuery.of(context).size.height * 0.01), + TextButton( + onPressed: () { + GoRouter.of( + context, + ).goNamed(RouterNames.fogotpasswordScreen); + }, + child: Text("Fogot Password ?", style: textLabelRed), + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.25), Column( children: [ - AuthpageButton( - text: "Login", - path: RouterNames.homePage, + //if valid form state + GestureDetector( + onTap: () async { + if (_formKey.currentState!.validate() && + _usernamecontroller.text.isNotEmpty && + _passwordcontroller.text.isNotEmpty) { + await _userLogin(); + } else { + setState(() { + isPasswordValid = false; + passwordHint = "please enter your @password"; + isUsernameValid = false; + usernameHint = "please enter your @username"; + }); + } + }, + child: AuthpageButton( + text: "Login", + isLoading: _isLoading, + ), ), //to register page TextButton( diff --git a/undomain/lib/pages/authentication/register/register_screen.dart b/undomain/lib/pages/authentication/register/register_screen.dart index 23d6a7b..527fd2d 100644 --- a/undomain/lib/pages/authentication/register/register_screen.dart +++ b/undomain/lib/pages/authentication/register/register_screen.dart @@ -1,7 +1,13 @@ +import 'dart:io'; + +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:image_picker/image_picker.dart'; import 'package:undomain/router/router_names.dart'; +import 'package:undomain/services/auth_services/authservices.dart'; import 'package:undomain/util/colors/colors.dart'; +import 'package:undomain/util/global/global_function.dart'; import 'package:undomain/util/global/global_varibles.dart'; import 'package:undomain/util/textstyles/text_styles.dart'; import 'package:undomain/widgets/buttons/authpage_button.dart'; @@ -20,6 +26,11 @@ class _RegisterScreenState extends State { final TextEditingController _confirmpasswordcontroller = TextEditingController(); final TextEditingController _emailcontroller = TextEditingController(); + final _formKey = GlobalKey(); + final Authservices _authservices = Authservices(); + final GlobalFunction _globalFunction = GlobalFunction(); + File? _file; + bool _isLoading = false; @override void dispose() { _passwordcontroller.dispose(); @@ -29,82 +40,239 @@ class _RegisterScreenState extends State { super.dispose(); } + //regexp for password + final RegExp passwordRegExp = RegExp( + r'^(?=.*[A-Za-z])(?=.*\d)(?=.*[!@#$%^&*(),.?":{}|<>]).{6,}$', + ); + + //reg exp for username + final RegExp usernameRegExp = RegExp(r'[!@#$%^&*(),.?":{}|<>]'); + + ///regexp for email + final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$'); + + //login validation frontend properties + String usernameHint = "@username"; + bool isUsernameValid = true; + String passwordHint = "@password"; + bool isPasswordValid = true; + String emailHint = "@email"; + bool isEmailValid = true; + String confirmPasswordHint = "@confirm password"; + bool isConfirmPasswordValid = true; + + //set profile image + Future _setProfileImage(ImageSource source) async { + ImagePicker _imgPicker = ImagePicker(); + final image = await _imgPicker.pickImage(source: source); + if (image != null) { + setState(() { + _file = File(image.path); + }); + } + } + + //save valid user data and get verifcation code + Future userRegister() async { + setState(() { + _isLoading = true; + }); + + final response = await _authservices.register( + _file!, + username: _usernamecontroller.text, + email: _emailcontroller.text, + password: _passwordcontroller.text, + ); + if (response["succss"]) { + GoRouter.of(context).goNamed( + RouterNames.verificationPage, + extra: { + "userId": response["user"]["id"], + "isFromRegister": true, + "email": "", + }, + ); + } else { + _globalFunction.snackBarMassage(context, response["massage"], 3); + } + setState(() { + _isLoading = false; + }); + } + @override Widget build(BuildContext context) { return Scaffold( - body: Padding( - padding: EdgeInsets.symmetric( - horizontal: authScreenPaddingH, - vertical: authScreenPaddingV, - ), - child: Column( - children: [ - SizedBox(height: MediaQuery.of(context).size.height * 0.08), - //title - Text("Date NET.", style: textDisplay), - //auth details - Form( - child: Column( - children: [ - SizedBox(height: MediaQuery.of(context).size.height * 0.02), - CircleAvatar(backgroundColor: utilPrimaryGrey, radius: 64), - SizedBox(height: MediaQuery.of(context).size.height * 0.02), - //username - AuthtextBox( - controller: _usernamecontroller, - hint: "@username", - isShow: false, - onSubmit: (p0) {}, - textInputAction: TextInputAction.next, - textInputType: TextInputType.name, - ), - SizedBox(height: MediaQuery.of(context).size.height * 0.02), - //email - AuthtextBox( - controller: _passwordcontroller, - hint: "@email", - isShow: false, - onSubmit: (p0) {}, - textInputAction: TextInputAction.next, - textInputType: TextInputType.emailAddress, - ), - SizedBox(height: MediaQuery.of(context).size.height * 0.02), - //password - AuthtextBox( - controller: _confirmpasswordcontroller, - hint: "@password", - isShow: false, - onSubmit: (p0) {}, - textInputAction: TextInputAction.next, - textInputType: TextInputType.visiblePassword, - ), - SizedBox(height: MediaQuery.of(context).size.height * 0.02), - //password - AuthtextBox( - controller: _emailcontroller, - hint: "@password", - isShow: false, - onSubmit: (p0) {}, - textInputAction: TextInputAction.done, - textInputType: TextInputType.visiblePassword, - ), - SizedBox(height: MediaQuery.of(context).size.height * 0.08), - //to verification page - AuthpageButton( - text: "Register", - path: RouterNames.verificationPage, - ), - //to login page - TextButton( - onPressed: () { - GoRouter.of(context).goNamed(RouterNames.loginPage); - }, - child: Text("Login", style: textLabelRed), - ), - ], + // resizeToAvoidBottomInset: false, + body: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: authScreenPaddingH, + vertical: authScreenPaddingV, + ), + child: Column( + children: [ + SizedBox(height: MediaQuery.of(context).size.height * 0.08), + //title + Text("Date NET.", style: textDisplay), + //auth details + Form( + key: _formKey, + child: Column( + children: [ + SizedBox(height: MediaQuery.of(context).size.height * 0.02), + Stack( + children: [ + //profile picture + _file != null + ? CircleAvatar( + backgroundImage: FileImage(_file!), + backgroundColor: utilPrimaryWhite.withOpacity( + 0.8, + ), + radius: 64, + ) + : CircleAvatar( + backgroundColor: utilPrimaryWhite.withOpacity( + 0.8, + ), + radius: 64, + ), + Positioned( + bottom: 0, + right: -6, + child: IconButton( + onPressed: () { + _setProfileImage(ImageSource.gallery); + }, + icon: Icon( + CupertinoIcons.camera_circle, + color: utilPrimaryWhite, + size: 40, + ), + ), + ), + ], + ), + + SizedBox(height: MediaQuery.of(context).size.height * 0.02), + //username + AuthtextBox( + isValid: isUsernameValid, + controller: _usernamecontroller, + hint: usernameHint, + isShow: false, + onSubmit: (p0) {}, + textInputAction: TextInputAction.next, + textInputType: TextInputType.name, + validChecker: (value) => null, + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.02), + //email + AuthtextBox( + isValid: isEmailValid, + controller: _emailcontroller, + hint: emailHint, + isShow: false, + onSubmit: (p0) {}, + textInputAction: TextInputAction.next, + textInputType: TextInputType.emailAddress, + validChecker: (value) => null, + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.02), + //password + AuthtextBox( + isValid: isPasswordValid, + controller: _passwordcontroller, + hint: passwordHint, + isShow: false, + onSubmit: (p0) {}, + textInputAction: TextInputAction.next, + textInputType: TextInputType.visiblePassword, + validChecker: (value) => null, + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.02), + //password + AuthtextBox( + isValid: isConfirmPasswordValid, + controller: _confirmpasswordcontroller, + hint: confirmPasswordHint, + isShow: false, + onSubmit: (p0) {}, + textInputAction: TextInputAction.done, + textInputType: TextInputType.visiblePassword, + validChecker: (value) => null, + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.08), + //to verification page + GestureDetector( + onTap: () async { + if (_usernamecontroller.text.isEmpty || + _emailcontroller.text.isEmpty || + _passwordcontroller.text.isEmpty || + _confirmpasswordcontroller.text.isEmpty) { + setState(() { + isUsernameValid = false; + isEmailValid = false; + isPasswordValid = false; + isConfirmPasswordValid = false; + usernameHint = "please enter your @username"; + emailHint = "please enter your @email"; + passwordHint = "please enter your @password"; + confirmPasswordHint = + "please enter your @confirm password"; + }); + } else if (usernameRegExp.hasMatch( + _usernamecontroller.text, + )) { + setState(() { + usernameHint = "@username cannot cantain symbols"; + _usernamecontroller.clear(); + }); + } else if (!emailRegex.hasMatch( + _emailcontroller.text, + )) { + setState(() { + emailHint = "Invalid @email format"; + _emailcontroller.clear(); + }); + } else if (!passwordRegExp.hasMatch( + _passwordcontroller.text, + )) { + setState(() { + passwordHint = "weak password"; + _passwordcontroller.clear(); + }); + } else if (_passwordcontroller.text != + _confirmpasswordcontroller.text) { + setState(() { + confirmPasswordHint = + "password mismatching please check your password"; + _confirmpasswordcontroller.clear(); + }); + } else { + //execute register function + await userRegister(); + } + }, + child: AuthpageButton( + text: "Register", + isLoading: _isLoading, + ), + ), + //to login page + TextButton( + onPressed: () { + GoRouter.of(context).goNamed(RouterNames.loginPage); + }, + child: Text("Login", style: textLabelRed), + ), + ], + ), ), - ), - ], + ], + ), ), ), ); diff --git a/undomain/lib/pages/authentication/spalshscreen/spalsh.dart b/undomain/lib/pages/authentication/spalshscreen/spalsh.dart index 23e1e5b..d3cf435 100644 --- a/undomain/lib/pages/authentication/spalshscreen/spalsh.dart +++ b/undomain/lib/pages/authentication/spalshscreen/spalsh.dart @@ -1,8 +1,15 @@ import 'dart:async'; +import 'package:animated_splash_screen/animated_splash_screen.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:page_transition/page_transition.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:undomain/pages/authentication/login/login_screen.dart'; +import 'package:undomain/pages/authentication/terms&conditions/terms_and_conditions.dart'; +import 'package:undomain/pages/home/main_screen.dart'; import 'package:undomain/router/router_names.dart'; +import 'package:undomain/util/colors/colors.dart'; import 'package:undomain/util/textstyles/text_styles.dart'; class SpalshScreen extends StatefulWidget { @@ -17,28 +24,61 @@ class _SpalshScreenState extends State { void initState() { super.initState(); Timer(Duration(seconds: 3), () { - GoRouter.of(context).goNamed(RouterNames.termsAndConditions); + GoRouter.of(context).goNamed(RouterNames.wrapperScreen); }); } + dynamic get splash => null; @override Widget build(BuildContext context) { - - return Scaffold( - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text("Date NET.", style: textDisplay), - SizedBox(height: 20), - - SizedBox(height: 10), - CircularProgressIndicator( - color: Colors.blue, - ), // optional loading spinner - ], - ), - ), + return AnimatedSplashScreen( + splash: Text("Date NET.", style: textDisplay), + nextScreen: WrapperScreen(), + // animationDuration: Duration(seconds: 3000), + backgroundColor: utilPrimaryWhite, + centered: true, + splashTransition: SplashTransition.fadeTransition, + pageTransitionType: PageTransitionType.fade, + + duration: 3000, ); } } + +//chack auth states +class WrapperScreen extends StatefulWidget { + const WrapperScreen({super.key}); + + @override + State createState() => _WrapperScreenState(); +} + +class _WrapperScreenState extends State { + bool isLoged = false; + bool isInitUser = false; + String? userId; + @override + void initState() { + _checkLoginState(); + super.initState(); + } + + void _checkLoginState() async { + SharedPreferences _pref = await SharedPreferences.getInstance(); + String? token = _pref.getString("token"); + userId = _pref.getString("user"); + setState(() { + isLoged = token != null; + isInitUser = userId == null; + }); + } + + @override + Widget build(BuildContext context) { + return isInitUser + ? TermsAndConditions() + : isLoged + ? Homepage() + : LoginScreen(); + } +} diff --git a/undomain/lib/pages/authentication/terms&conditions/terms_and_conditions.dart b/undomain/lib/pages/authentication/terms&conditions/terms_and_conditions.dart index f589af5..763cc65 100644 --- a/undomain/lib/pages/authentication/terms&conditions/terms_and_conditions.dart +++ b/undomain/lib/pages/authentication/terms&conditions/terms_and_conditions.dart @@ -1,14 +1,21 @@ import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; import 'package:undomain/router/router_names.dart'; import 'package:undomain/util/colors/colors.dart'; import 'package:undomain/util/global/global_varibles.dart'; import 'package:undomain/util/textstyles/text_styles.dart'; import 'package:undomain/widgets/buttons/authpage_button.dart'; -class TermsAndConditions extends StatelessWidget { +class TermsAndConditions extends StatefulWidget { const TermsAndConditions({super.key}); @override + State createState() => _TermsAndConditionsState(); +} + +class _TermsAndConditionsState extends State { + @override + bool isChecked = false; Widget build(BuildContext context) { final deviceWidth = MediaQuery.of(context).size.width; final deviceHeight = MediaQuery.of(context).size.height; @@ -39,20 +46,47 @@ class TermsAndConditions extends StatelessWidget { children: [ Row( children: [ + //acceptent check box Checkbox( - value: false, - onChanged: (value) {}, - checkColor: utilPrimaryRed, + value: isChecked, + activeColor: utilPrimaryRed, + onChanged: (value) { + setState(() { + isInitialUser = true; + isChecked = !isChecked; + }); + }, + checkColor: utilPrimaryWhite, autofocus: true, focusColor: utilPrimaryRed, side: BorderSide(color: utilPrimaryBlack, width: 1), ), Text("I agree terms & conditions", style: textLabel), - - //go to login page ], ), - AuthpageButton(path: RouterNames.loginPage, text: "Continue"), + //route to login page + GestureDetector( + onTap: () { + isChecked + ? GoRouter.of(context).goNamed(RouterNames.loginPage) + : ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: utilPrimaryRed, + closeIconColor: utilPrimaryWhite, + elevation: 1, + showCloseIcon: true, + padding: EdgeInsets.symmetric( + horizontal: authScreenPaddingH, + ), + content: Text( + "Please accept terms & conditions", + style: textSnackbar, + ), + ), + ); + }, + child: AuthpageButton(text: "Continue", isLoading: false), + ), ], ), ], diff --git a/undomain/lib/pages/home/home_screen.dart b/undomain/lib/pages/home/home_screen.dart new file mode 100644 index 0000000..26e2a1a --- /dev/null +++ b/undomain/lib/pages/home/home_screen.dart @@ -0,0 +1,161 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:material_floating_search_bar_2/material_floating_search_bar_2.dart'; +import 'package:undomain/services/userservices/userservices.dart'; +import 'package:undomain/util/colors/colors.dart'; +import 'package:undomain/util/global/global_function.dart'; +import 'package:undomain/util/textstyles/text_styles.dart'; + +class HomeScreen extends StatefulWidget { + // final String userId; + const HomeScreen({super.key}); + + @override + State createState() => _HomeScreenState(); +} + +class _HomeScreenState extends State { + String _serchItem = ""; + final FloatingSearchBarController _floatingSearchBarController = + FloatingSearchBarController(); + final Userservices _userservices = Userservices(); + final GlobalFunction _globalFunction = GlobalFunction(); + late Map user; + Uint8List? imagebytes; + String username = ""; + //get device user + Future _getDeviceUser() async { + user = await _userservices.getCurrentUser(); + if (!user["succss"]) { + _globalFunction.snackBarMassage(context, user["massage"], 3); + } else { + setState(() { + username = user["user"]["username"]; + + String base64String = user["user"]["profileUrl"]; + imagebytes = base64Decode(base64String); + }); + } + } + + @override + void initState() { + _getDeviceUser(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + double deviceW = MediaQuery.of(context).size.width; + double deviceH = MediaQuery.of(context).size.height; + double space = (deviceW - 72) / 2; + return SafeArea( + child: Scaffold( + body: Stack( + //fit: StackFit.expand, + children: [ + //background image + Image.asset( + "assets/mess.jpeg", + fit: BoxFit.fill, + height: deviceH * 0.4, + width: double.infinity, + ), + //user name + Positioned( + top: deviceH * 0.03, + left: deviceW * 0.03, + child: Chip( + label: RichText( + text: TextSpan( + children: [ + TextSpan(text: "Welcome ", style: textLabelRed), + TextSpan(text: username, style: textLabel), + ], + ), + ), + autofocus: true, + backgroundColor: utilPrimaryWhite, + labelPadding: EdgeInsets.all(2), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24), + ), + ), + ), + + //uaer profile picture + Positioned( + top: deviceH * 0.03, + right: deviceW * 0.03, + child: + imagebytes == null + ? CircleAvatar( + backgroundColor: utilPrimaryGrey, + radius: 24, + ) + : CircleAvatar( + backgroundColor: utilPrimaryGrey, + radius: 24, + backgroundImage: MemoryImage(imagebytes!), + ), + ), + //search bar + Positioned( + child: Padding( + padding: EdgeInsets.only(top: deviceH * 0.3), + child: searchBar(context), + ), + ), + ], + ), + ), + ); + } + + Widget searchBar(BuildContext context) { + final isPortrait = + MediaQuery.of(context).orientation == Orientation.portrait; + + return FloatingSearchBar( + hint: "Who you are looking for?", + controller: _floatingSearchBarController, + hintStyle: GoogleFonts.poppins( + color: utilPrimaryGrey, + fontSize: 11, + fontWeight: FontWeight.w500, + ), + scrollPadding: EdgeInsets.all(8), + transitionDuration: Duration(microseconds: 600), + transitionCurve: Curves.easeInOut, + autocorrect: true, + + borderRadius: BorderRadius.circular(24), + textInputAction: TextInputAction.search, + elevation: 2, + automaticallyImplyBackButton: false, + iconColor: utilPrimaryBlack, + leadingActions: [Icon(Icons.search, color: utilPrimaryGrey)], + physics: BouncingScrollPhysics(), + openAxisAlignment: 0, + width: isPortrait ? 500 : 750, + debounceDelay: Duration(microseconds: 400), + onQueryChanged: (query) { + setState(() { + _serchItem = query; + }); + }, + transition: CircularFloatingSearchBarTransition(), + + actions: [], + builder: (context, transition) { + return ClipRRect( + borderRadius: BorderRadius.circular(24), + child: Material(color: utilPrimaryWhite, elevation: 1), + ); + }, + ); + } +} diff --git a/undomain/lib/pages/home/homepage.dart b/undomain/lib/pages/home/homepage.dart deleted file mode 100644 index e14ca6c..0000000 --- a/undomain/lib/pages/home/homepage.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:flutter/material.dart'; - -class Homepage extends StatefulWidget { - const Homepage({super.key}); - - @override - State createState() => _HomepageState(); -} - -class _HomepageState extends State { - @override - Widget build(BuildContext context) { - return Scaffold(body: Column(children: [Text("Welcome to Homepage")])); - } -} diff --git a/undomain/lib/pages/home/main_screen.dart b/undomain/lib/pages/home/main_screen.dart new file mode 100644 index 0000000..6bd030c --- /dev/null +++ b/undomain/lib/pages/home/main_screen.dart @@ -0,0 +1,130 @@ +import 'package:flutter/material.dart'; +import 'package:persistent_bottom_nav_bar/persistent_bottom_nav_bar.dart'; +import 'package:undomain/pages/home/home_screen.dart'; +import 'package:undomain/pages/profile/profile_scren.dart'; +import 'package:undomain/pages/reels/reel_screen.dart'; +import 'package:undomain/pages/streaming/streaming_screen.dart'; +import 'package:undomain/pages/update/update_screen.dart'; +import 'package:undomain/util/colors/colors.dart'; +import 'package:undomain/util/textstyles/text_styles.dart'; + +class Homepage extends StatefulWidget { + // final String userId; + // final String? username; + // final String? email; + // final Uint8List? prfileUrl; + const Homepage({ + super.key, + // required this.userId, + + // this.userId, + // this.username, + // this.email, + // this.prfileUrl, + }); + + @override + State createState() => _HomepageState(); +} + +class _HomepageState extends State { + late PersistentTabController _tabController; + //renderd screens + List _buildScreen() { + return [ + HomeScreen(), + ReelScreen(), + StreamingScreen(), + UpdateScreen(), + ProfileScren(), + ]; + } + + //nav bar items + List _navBarItems() { + return [ + PersistentBottomNavBarItem( + icon: Icon(Icons.home_outlined), + title: "Home", + activeColorPrimary: utilPrimaryRed, + inactiveColorPrimary: utilPrimaryGrey, + ), + PersistentBottomNavBarItem( + icon: Icon(Icons.camera), + title: "Reels", + activeColorPrimary: utilPrimaryRed, + inactiveColorPrimary: utilPrimaryGrey, + ), + PersistentBottomNavBarItem( + icon: Icon(Icons.live_tv), + title: "Live", + activeColorPrimary: utilPrimaryRed, + inactiveColorPrimary: utilPrimaryGrey, + ), + PersistentBottomNavBarItem( + icon: Icon(Icons.update), + title: "Upgrade", + activeColorPrimary: utilPrimaryRed, + inactiveColorPrimary: utilPrimaryGrey, + ), + PersistentBottomNavBarItem( + icon: Icon(Icons.person_2_outlined), + title: "Profile", + textStyle: textLabel, + + activeColorPrimary: utilPrimaryRed, + inactiveColorPrimary: utilPrimaryGrey, + ), + ]; + } + + @override + void initState() { + _tabController = PersistentTabController(initialIndex: 0); + super.initState(); + } + + //Uint8List imageBytes = base64Decode() + @override + Widget build(BuildContext context) { + return PersistentTabView( + context, + screens: _buildScreen(), + controller: _tabController, + items: _navBarItems(), + confineToSafeArea: true, + // backgroundColor: Color.fromARGB(247, 254, 254, 254), + handleAndroidBackButtonPress: true, + resizeToAvoidBottomInset: true, + stateManagement: true, + hideNavigationBarWhenKeyboardAppears: true, + margin: EdgeInsets.symmetric(horizontal: 8, vertical: 8), + decoration: NavBarDecoration( + borderRadius: BorderRadius.circular(24), + colorBehindNavBar: utilPrimaryWhite, + boxShadow: [ + BoxShadow( + color: utilPrimaryGrey.withOpacity(0.5), + offset: Offset(0, 0.5), + spreadRadius: 0, + blurRadius: 1, + ), + ], + ), + popBehaviorOnSelectedNavBarItemPress: PopBehavior.all, + animationSettings: NavBarAnimationSettings( + navBarItemAnimation: ItemAnimationSettings( + duration: Duration(milliseconds: 400), + curve: Curves.ease, + ), + screenTransitionAnimation: ScreenTransitionAnimationSettings( + animateTabTransition: true, + curve: Curves.ease, + duration: Duration(milliseconds: 200), + screenTransitionAnimationType: ScreenTransitionAnimationType.fadeIn, + ), + ), + // navBarStyle: NavBarStyle.style10, + ); + } +} diff --git a/undomain/lib/pages/profile/profile_scren.dart b/undomain/lib/pages/profile/profile_scren.dart new file mode 100644 index 0000000..5584b5d --- /dev/null +++ b/undomain/lib/pages/profile/profile_scren.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class ProfileScren extends StatelessWidget { + const ProfileScren({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold(); + } +} \ No newline at end of file diff --git a/undomain/lib/pages/reels/reel_screen.dart b/undomain/lib/pages/reels/reel_screen.dart new file mode 100644 index 0000000..da4baf0 --- /dev/null +++ b/undomain/lib/pages/reels/reel_screen.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class ReelScreen extends StatelessWidget { + const ReelScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold(); + } +} \ No newline at end of file diff --git a/undomain/lib/pages/streaming/streaming_screen.dart b/undomain/lib/pages/streaming/streaming_screen.dart new file mode 100644 index 0000000..53e4315 --- /dev/null +++ b/undomain/lib/pages/streaming/streaming_screen.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class StreamingScreen extends StatelessWidget { + const StreamingScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold(); + } +} \ No newline at end of file diff --git a/undomain/lib/pages/update/update_screen.dart b/undomain/lib/pages/update/update_screen.dart new file mode 100644 index 0000000..59d446c --- /dev/null +++ b/undomain/lib/pages/update/update_screen.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class UpdateScreen extends StatelessWidget { + const UpdateScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold(); + } +} diff --git a/undomain/lib/router/go_router.dart b/undomain/lib/router/go_router.dart index 9fcc157..82fa70e 100644 --- a/undomain/lib/router/go_router.dart +++ b/undomain/lib/router/go_router.dart @@ -3,17 +3,18 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:undomain/pages/authentication/email_verification/email_verification.dart'; +import 'package:undomain/pages/authentication/fogotpassword/fogot_password.dart'; import 'package:undomain/pages/authentication/login/login_screen.dart'; import 'package:undomain/pages/authentication/register/register_screen.dart'; import 'package:undomain/pages/authentication/spalshscreen/spalsh.dart'; import 'package:undomain/pages/authentication/terms&conditions/terms_and_conditions.dart'; import 'package:undomain/pages/error/error_page.dart'; -import 'package:undomain/pages/home/homepage.dart'; +import 'package:undomain/pages/home/main_screen.dart'; import 'package:undomain/router/router_names.dart'; class Routes { final goRouter = GoRouter( - initialLocation: "/verify", + initialLocation: "/", errorPageBuilder: (context, state) { return const MaterialPage(child: ErrorPage()); }, @@ -42,7 +43,7 @@ class Routes { return const TermsAndConditions(); }, ), - // //registerpage + //registerpage GoRoute( path: "/register", name: RouterNames.registerPage, @@ -55,7 +56,15 @@ class Routes { path: "/verify", name: RouterNames.verificationPage, builder: (context, state) { - return EmailVerification(); + final String userId = (state.extra as Map)["userId"]; + final bool isFromRegister = + (state.extra as Map)["isFromRegister"]; + final String email = (state.extra as Map)["email"]; + return EmailVerification( + userid: userId, + isForRegister: isFromRegister, + email: email, + ); }, ), //Homepage @@ -63,9 +72,42 @@ class Routes { path: "/home", name: RouterNames.homePage, builder: (context, state) { - return Homepage(); + // String userId = (state.extra as Map)["userId"]; + // String username = (state.extra as Map)["username"]; + // String email = (state.extra as Map)["email"]; + // Uint8List profileUrl = + // (state.extra as Map)["profileUrl"]; + return Homepage( + // email: email, + // prfileUrl: profileUrl, + // userId: userId, + // username: username, + ); }, ), + //Homepage + GoRoute( + path: "/fogotpassword", + name: RouterNames.fogotpasswordScreen, + builder: (context, state) { + return FogotPassword(); + }, + ), + GoRoute( + path: "/wrapper", + name: RouterNames.wrapperScreen, + builder: (context, state) { + return WrapperScreen(); + }, + ), + //main screen + // GoRoute( + // path: "/main", + // name: RouterNames.mainScreen, + // builder: (context, state) { + // return Homepage(); + // }, + // ), ], ); } diff --git a/undomain/lib/router/router_names.dart b/undomain/lib/router/router_names.dart index 56106b0..e133fc7 100644 --- a/undomain/lib/router/router_names.dart +++ b/undomain/lib/router/router_names.dart @@ -2,7 +2,9 @@ class RouterNames { static const String loginPage = "login"; static const String registerPage = "register"; static const String verificationPage = "verify"; - static const String homePage = "home"; + static const String homePage = "main"; static const String termsAndConditions = "/terms"; static const String splashScreen = "/"; + static const String fogotpasswordScreen = "/fogotpassword"; + static const String wrapperScreen = "/wrapper"; } diff --git a/undomain/lib/services/auth_services/authservices.dart b/undomain/lib/services/auth_services/authservices.dart new file mode 100644 index 0000000..e3ebf24 --- /dev/null +++ b/undomain/lib/services/auth_services/authservices.dart @@ -0,0 +1,156 @@ +import "dart:convert"; +import "dart:io"; + +import "package:http/http.dart" as http; +import "package:shared_preferences/shared_preferences.dart"; + +class Authservices { + final baseUrl = "http://192.168.12.148:5000/api/auth"; + //register new user + Future> register( + File profileUrl, { + required String username, + required String email, + required String password, + }) async { + try { + final uri = Uri.parse("$baseUrl/register"); + //get response + final request = http.MultipartRequest('POST', uri); + //attach text fields + request.fields['username'] = username; + request.fields['email'] = email; + request.fields['password'] = password; + //attach file + request.files.add( + await http.MultipartFile.fromPath("profileUrl", profileUrl.path), + ); + //send request + final streamedResponse = await request.send(); + final response = await http.Response.fromStream(streamedResponse); + + //get body + final user = jsonDecode(response.body); + if (response.statusCode == 400 || response.statusCode == 500) { + return user; + } + + //store tooken in shared preferences + final SharedPreferences preferences = + await SharedPreferences.getInstance(); + //set jwt token + preferences.setString("token", user["newToken"]); + //set user id + preferences.setString("user", user["user"]["id"]); + print(user["newToken"]); + return user; + } catch (err) { + print("client side error $err"); + return {"succss": false, "massage": "Unexpected error"}; + } + } + + //verify new user + Future> verifyNewUser({ + required String userId, + required String verifyCode, + }) async { + try { + final response = await http.post( + Uri.parse("$baseUrl/verify"), + headers: {'Content-Type': 'application/json'}, + body: jsonEncode({"userId": userId, "verifyCode": verifyCode}), + ); + final user = jsonDecode(response.body); + if (response.statusCode == 400 || + response.statusCode == 408 || + response.statusCode == 500) { + return user; + } + return user; + } catch (err) { + print("client side error $err"); + return {"success": false, "massage": "Unexpected error"}; + } + } + + //login existing user + Future> login({ + required String username, + required String password, + }) async { + try { + final response = await http.post( + Uri.parse("$baseUrl/login"), + headers: {'Content-Type': 'application/json'}, + body: jsonEncode({"username": username, "password": password}), + ); + + final user = jsonDecode(response.body); + if (response.statusCode == 400 || response.statusCode == 500) { + return user; + } + //store tooken in shared preferences + final SharedPreferences preferences = + await SharedPreferences.getInstance(); + //save jwt + await preferences.setString("token", user["newToken"]); + //save user id + await preferences.setString("user", user["user"]["id"]); + print(user["newToken"]); + return user; + } catch (err) { + print("client side error $err"); + return {"success": false, "massage": "Unexpected error"}; + } + } + + //send reset password request with email and new password + Future> sendPasswordResetRequest({ + required String email, + }) async { + try { + final response = await http.post( + Uri.parse("$baseUrl/user-verification"), + headers: {'Content-Type': 'application/json'}, + body: jsonEncode({"email": email}), + ); + + final user = jsonDecode(response.body); + if (response.statusCode == 404 || response.statusCode == 500) { + return user; + } + + return user; + } catch (err) { + print("client side error $err"); + return {"success": false, "massage": "Unexpected error"}; + } + } + + //verify resset password + Future> verifyResetPassword({ + required String email, + required String otp, + required String password, + }) async { + try { + final response = await http.post( + Uri.parse("$baseUrl/reset-password"), + headers: {'Content-Type': 'application/json'}, + body: jsonEncode({"email": email, "otp": otp, "password": password}), + ); + + final user = jsonDecode(response.body); + if (response.statusCode == 404 || + response.statusCode == 500 || + response.statusCode == 400 || + response.statusCode == 408) { + return user; + } + return user; + } catch (err) { + return {"success": false, "massage": "Unexpected error"}; + } + } +} diff --git a/undomain/lib/services/userservices/userservices.dart b/undomain/lib/services/userservices/userservices.dart new file mode 100644 index 0000000..1b5c2aa --- /dev/null +++ b/undomain/lib/services/userservices/userservices.dart @@ -0,0 +1,108 @@ +import "dart:convert"; + +import "package:http/http.dart" as http; +import "package:shared_preferences/shared_preferences.dart"; + +class Userservices { + final baseUrl = "http://192.168.12.148:5000/api/user"; + //get jwt token + Future getToken() async { + final pref = await SharedPreferences.getInstance(); + return pref.getString("token"); + } + + //get userid + Future getUserId() async { + final pref = await SharedPreferences.getInstance(); + return pref.getString("user"); + } + + //get current device user details + Future> getCurrentUser() async { + try { + final token = await getToken(); + if (token == null) { + print("token not valid"); + return {"success": false, "massage": "Authenticated token not found"}; + } + final response = await http.get( + Uri.parse("$baseUrl/getcurrentuser"), + + headers: {'Content-Type': 'application/json', 'Authorization': token}, + ); + final user = jsonDecode(response.body); + print(user); + if (response.statusCode == 401) { + print("user getting error $user"); + return user; + } + + return user; + } catch (err) { + print("client side error $err"); + return {"success": false, "massage": "Unexpected error"}; + } + } + + //get all user details(avalible working) + Future>?> getAllUser() async { + try { + final token = await getToken(); + if (token == null) { + return [ + {"success": false, "massage": "Authenticated token not found"}, + ]; + } + final response = await http.get( + Uri.parse("$baseUrl/getalluser"), + + headers: {'Content-Type': 'application/json', 'Authorization': token}, + ); + + final allUsers = jsonDecode(response.body); + if (response.statusCode == 500) { + return [allUsers]; + } + + return allUsers["users"]; + } catch (err) { + print("client side error $err"); + return [ + {"success": false, "massage": "Unexpected error"}, + ]; + } + } + + //get user by usernname + Future>?> getUserByUserName(String username) async { + try { + final token = await getToken(); + if (token == null) { + return [ + {"success": false, "massage": "Authenticated token not found"}, + ]; + } + final response = await http.get( + Uri.parse("$baseUrl/getuserbyusername/$username"), + + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + final user = jsonDecode(response.body); + if (response.statusCode == 404 || response.statusCode == 500) { + return [user]; + } + if (user["users"].length > 1) { + return user["users"]; + } + return user["users"].toList(); + } catch (err) { + print("client side error $err"); + return [ + {"success": false, "massage": "Unexpected error"}, + ]; + } + } +} diff --git a/undomain/lib/util/colors/colors.dart b/undomain/lib/util/colors/colors.dart index 254bb27..6bacd4a 100644 --- a/undomain/lib/util/colors/colors.dart +++ b/undomain/lib/util/colors/colors.dart @@ -5,3 +5,4 @@ final utilPrimaryRed = Color(0xffCD0000); final utilPrimaryWhite = Color(0xffEDECEC); final utilPrimaryBlack = Color(0xff1E1E1E); final utilPrimaryGrey = Color(0xff676767); +final utilNavBarColor = Color(0xff476810); diff --git a/undomain/lib/util/global/global_function.dart b/undomain/lib/util/global/global_function.dart new file mode 100644 index 0000000..de0c90e --- /dev/null +++ b/undomain/lib/util/global/global_function.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import 'package:undomain/util/colors/colors.dart'; +import 'package:undomain/util/global/global_varibles.dart'; +import 'package:undomain/util/textstyles/text_styles.dart'; + +class GlobalFunction { + void snackBarMassage(BuildContext context, String text, int duration) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: utilPrimaryRed, + closeIconColor: utilPrimaryWhite, + elevation: 1, + showCloseIcon: true, + duration: Duration(seconds: duration), + padding: EdgeInsets.symmetric(horizontal: authScreenPaddingH), + content: Text(text, style: textSnackbar), + ), + ); + } +} diff --git a/undomain/lib/util/global/global_varibles.dart b/undomain/lib/util/global/global_varibles.dart index 8f087a1..14d050d 100644 --- a/undomain/lib/util/global/global_varibles.dart +++ b/undomain/lib/util/global/global_varibles.dart @@ -1,3 +1,7 @@ const double authScreenPaddingH = 20; const double authScreenPaddingV = 40; const double authButtonRadius = 36; +const double mainPagePaddingH = 10; +const double mainPagePaddingV = 15; + +bool isInitialUser = true; diff --git a/undomain/lib/util/textstyles/text_styles.dart b/undomain/lib/util/textstyles/text_styles.dart index 8accaad..f4e7984 100644 --- a/undomain/lib/util/textstyles/text_styles.dart +++ b/undomain/lib/util/textstyles/text_styles.dart @@ -38,3 +38,8 @@ final textTitalSmall = GoogleFonts.poppins( fontSize: 16, fontWeight: FontWeight.w600, ); +final textSnackbar = GoogleFonts.poppins( + color: utilPrimaryWhite, + fontSize: 11, + fontWeight: FontWeight.w400, +); diff --git a/undomain/lib/widgets/buttons/authpage_button.dart b/undomain/lib/widgets/buttons/authpage_button.dart index 0a0bfb0..bdfe6e9 100644 --- a/undomain/lib/widgets/buttons/authpage_button.dart +++ b/undomain/lib/widgets/buttons/authpage_button.dart @@ -1,30 +1,32 @@ import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; import 'package:undomain/util/colors/colors.dart'; import 'package:undomain/util/global/global_varibles.dart'; import 'package:undomain/util/textstyles/text_styles.dart'; class AuthpageButton extends StatelessWidget { final String text; - - final String path; - const AuthpageButton({super.key, required this.text, required this.path}); + final bool isLoading; + const AuthpageButton({ + super.key, + required this.text, + required this.isLoading, + }); @override Widget build(BuildContext context) { - return GestureDetector( - onTap: () { - GoRouter.of(context).goNamed(path); - }, - child: Container( - width: double.infinity, - height: MediaQuery.of(context).size.height * 0.07, - child: Center(child: Text(text, style: textTitle)), + return Container( + width: double.infinity, + height: MediaQuery.of(context).size.height * 0.07, + child: Center( + child: + isLoading + ? CircularProgressIndicator(color: utilPrimaryWhite) + : Text(text, style: textTitle), + ), - decoration: BoxDecoration( - color: utilPrimaryRed, - borderRadius: BorderRadius.circular(authButtonRadius), - ), + decoration: BoxDecoration( + color: utilPrimaryRed, + borderRadius: BorderRadius.circular(authButtonRadius), ), ); } diff --git a/undomain/lib/widgets/textboxes/authtext_box.dart b/undomain/lib/widgets/textboxes/authtext_box.dart index a9c90e2..e4486d4 100644 --- a/undomain/lib/widgets/textboxes/authtext_box.dart +++ b/undomain/lib/widgets/textboxes/authtext_box.dart @@ -9,6 +9,8 @@ class AuthtextBox extends StatelessWidget { final bool isShow; final TextInputAction textInputAction; final TextInputType textInputType; + final String? Function(String?)? validChecker; + final bool isValid; const AuthtextBox({ super.key, required this.onSubmit, @@ -17,20 +19,24 @@ class AuthtextBox extends StatelessWidget { required this.isShow, required this.textInputAction, required this.textInputType, + this.validChecker, + required this.isValid, }); @override Widget build(BuildContext context) { return TextFormField( onFieldSubmitted: onSubmit, + validator: validChecker, controller: controller, textInputAction: textInputAction, keyboardType: textInputType, obscureText: isShow, cursorColor: utilPrimaryGrey, + decoration: InputDecoration( hintText: hint, - hintStyle: textHint, + hintStyle: isValid ? textHint : textLabelRed, contentPadding: EdgeInsets.symmetric( vertical: MediaQuery.of(context).size.height * 0.02, diff --git a/undomain/linux/flutter/generated_plugin_registrant.cc b/undomain/linux/flutter/generated_plugin_registrant.cc index e71a16d..64a0ece 100644 --- a/undomain/linux/flutter/generated_plugin_registrant.cc +++ b/undomain/linux/flutter/generated_plugin_registrant.cc @@ -6,6 +6,10 @@ #include "generated_plugin_registrant.h" +#include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); } diff --git a/undomain/linux/flutter/generated_plugins.cmake b/undomain/linux/flutter/generated_plugins.cmake index 2e1de87..2db3c22 100644 --- a/undomain/linux/flutter/generated_plugins.cmake +++ b/undomain/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/undomain/macos/Flutter/GeneratedPluginRegistrant.swift b/undomain/macos/Flutter/GeneratedPluginRegistrant.swift index e777c67..4b4e1ac 100644 --- a/undomain/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/undomain/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,8 +5,12 @@ import FlutterMacOS import Foundation +import file_selector_macos import path_provider_foundation +import shared_preferences_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) } diff --git a/undomain/pubspec.lock b/undomain/pubspec.lock index 3a53c7d..9760d1c 100644 --- a/undomain/pubspec.lock +++ b/undomain/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + animated_splash_screen: + dependency: "direct main" + description: + name: animated_splash_screen + sha256: f45634db6ec4e8cf034c53e03f3bd83898a16fe3c9286bf5510b6831dfcf2124 + url: "https://pub.dev" + source: hosted + version: "1.3.0" ansicolor: dependency: transitive description: @@ -65,6 +73,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.19.1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" + url: "https://pub.dev" + source: hosted + version: "0.3.4+2" crypto: dependency: transitive description: @@ -105,6 +121,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33" + url: "https://pub.dev" + source: hosted + version: "0.9.3+2" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "271ab9986df0c135d45c3cdb6bd0faa5db6f4976d3e4b437cf7d0f258d941bfc" + url: "https://pub.dev" + source: hosted + version: "0.9.4+2" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b + url: "https://pub.dev" + source: hosted + version: "2.6.2" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b" + url: "https://pub.dev" + source: hosted + version: "0.9.3+4" flutter: dependency: "direct main" description: flutter @@ -126,6 +182,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.6" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: "5a1e6fb2c0561958d7e4c33574674bda7b77caaca7a33b758876956f2902eea3" + url: "https://pub.dev" + source: hosted + version: "2.0.27" flutter_test: dependency: "direct dev" description: flutter @@ -161,7 +225,7 @@ packages: source: hosted version: "0.15.5+1" http: - dependency: transitive + dependency: "direct main" description: name: http sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f @@ -184,6 +248,70 @@ packages: url: "https://pub.dev" source: hosted version: "4.5.4" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "8bd392ba8b0c8957a157ae0dc9fcf48c58e6c20908d5880aea1d79734df090e9" + url: "https://pub.dev" + source: hosted + version: "0.8.12+22" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100" + url: "https://pub.dev" + source: hosted + version: "0.8.12+2" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9" + url: "https://pub.dev" + source: hosted + version: "0.2.1+2" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1" + url: "https://pub.dev" + source: hosted + version: "0.2.1+2" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0" + url: "https://pub.dev" + source: hosted + version: "2.10.1" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" leak_tracker: dependency: transitive description: @@ -240,6 +368,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.11.1" + material_floating_search_bar_2: + dependency: "direct main" + description: + name: material_floating_search_bar_2 + sha256: ab0c6d209d9491f98dd4c72f2641d0ba1dd35c87effca1f23d8679bece43add0 + url: "https://pub.dev" + source: hosted + version: "0.5.0" meta: dependency: transitive description: @@ -248,6 +384,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.16.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + page_transition: + dependency: "direct main" + description: + name: page_transition + sha256: "9d2a780d7d68b53ae82fbcc43e06a16195e6775e9aae40e55dc0cbb593460f9d" + url: "https://pub.dev" + source: hosted + version: "2.2.1" path: dependency: transitive description: @@ -304,6 +456,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + persistent_bottom_nav_bar: + dependency: "direct main" + description: + name: persistent_bottom_nav_bar + sha256: "6aa9b97ced1abd92c90cedd1997d34ea0b35c3ded762ac6063baccc299b0c4c5" + url: "https://pub.dev" + source: hosted + version: "6.2.1" petitparser: dependency: transitive description: @@ -344,6 +504,62 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.1" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" + url: "https://pub.dev" + source: hosted + version: "2.5.3" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: c2c8c46297b5d6a80bed7741ec1f2759742c77d272f1a1698176ae828f8e1a18 + url: "https://pub.dev" + source: hosted + version: "2.4.9" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 + url: "https://pub.dev" + source: hosted + version: "2.4.3" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" sky_engine: dependency: transitive description: flutter diff --git a/undomain/pubspec.yaml b/undomain/pubspec.yaml index c047d5d..a946d3d 100644 --- a/undomain/pubspec.yaml +++ b/undomain/pubspec.yaml @@ -38,6 +38,14 @@ dependencies: go_router: ^14.8.1 pinput: ^5.0.1 flutter_native_splash: ^2.4.6 + animated_splash_screen: ^1.3.0 + page_transition: ^2.2.1 + image_picker: ^1.1.2 + http: ^1.3.0 + shared_preferences: ^2.5.3 + persistent_bottom_nav_bar: ^6.2.1 + material_floating_search_bar_2: ^0.5.0 + dev_dependencies: flutter_test: @@ -62,10 +70,9 @@ flutter: uses-material-design: true # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - + assets: + - assets/ + # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/to/resolution-aware-images diff --git a/undomain/windows/flutter/generated_plugin_registrant.cc b/undomain/windows/flutter/generated_plugin_registrant.cc index 8b6d468..77ab7a0 100644 --- a/undomain/windows/flutter/generated_plugin_registrant.cc +++ b/undomain/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,9 @@ #include "generated_plugin_registrant.h" +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); } diff --git a/undomain/windows/flutter/generated_plugins.cmake b/undomain/windows/flutter/generated_plugins.cmake index b93c4c3..a423a02 100644 --- a/undomain/windows/flutter/generated_plugins.cmake +++ b/undomain/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST