diff --git a/Frontend/plannerly/assets/images/logo_black_bg.png b/Frontend/plannerly/assets/images/logo_black_bg.png new file mode 100644 index 0000000..78ecee7 Binary files /dev/null and b/Frontend/plannerly/assets/images/logo_black_bg.png differ diff --git a/Frontend/plannerly/assets/images/logo_transparent.png b/Frontend/plannerly/assets/images/logo_transparent.png new file mode 100644 index 0000000..f77ec57 Binary files /dev/null and b/Frontend/plannerly/assets/images/logo_transparent.png differ diff --git a/Frontend/plannerly/lib/bloc/signup/signup_bloc.dart b/Frontend/plannerly/lib/bloc/signup/signup_bloc.dart new file mode 100644 index 0000000..755c5f9 --- /dev/null +++ b/Frontend/plannerly/lib/bloc/signup/signup_bloc.dart @@ -0,0 +1,13 @@ +import 'package:bloc/bloc.dart'; +import 'package:meta/meta.dart'; + +part 'signup_event.dart'; +part 'signup_state.dart'; + +class SignupBloc extends Bloc { + SignupBloc() : super(SignupInitial()) { + on((event, emit) { + // TODO: implement event handler + }); + } +} diff --git a/Frontend/plannerly/lib/bloc/signup/signup_event.dart b/Frontend/plannerly/lib/bloc/signup/signup_event.dart new file mode 100644 index 0000000..cddb1da --- /dev/null +++ b/Frontend/plannerly/lib/bloc/signup/signup_event.dart @@ -0,0 +1,4 @@ +part of 'signup_bloc.dart'; + +@immutable +sealed class SignupEvent {} diff --git a/Frontend/plannerly/lib/bloc/signup/signup_state.dart b/Frontend/plannerly/lib/bloc/signup/signup_state.dart new file mode 100644 index 0000000..51f79e5 --- /dev/null +++ b/Frontend/plannerly/lib/bloc/signup/signup_state.dart @@ -0,0 +1,26 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +part of 'signup_bloc.dart'; + +@immutable +sealed class SignupState {} + +abstract class SignupActionState extends SignupState {} + +final class SignupInitial extends SignupState {} + +class SignupLoading extends SignupState {} + +class SignupLoadedSuccess extends SignupState {} + +class SignupLoadedError extends SignupState {} + +class SignupButtonClicked extends SignupActionState {} + +class SignupPageLoginButtonClicked extends SignupActionState {} + +class SignupPageError extends SignupActionState { + String errorMessage; + SignupPageError({ + required this.errorMessage, + }); +} diff --git a/Frontend/plannerly/lib/main.dart b/Frontend/plannerly/lib/main.dart index 12f965b..fda82de 100644 --- a/Frontend/plannerly/lib/main.dart +++ b/Frontend/plannerly/lib/main.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:plannerly/screens/home/home.dart'; +import 'package:plannerly/screens/signup/signup.dart'; void main() { runApp(const MyApp()); @@ -18,7 +19,7 @@ class MyApp extends StatelessWidget { darkTheme: ThemeData.dark(), themeMode: ThemeMode.dark, debugShowCheckedModeBanner: false, - home: const HomeScreen(), + home: const SignUpPage(), ); } } diff --git a/Frontend/plannerly/lib/models/task_model.dart b/Frontend/plannerly/lib/models/task_model.dart index 17b0c54..ed3c944 100644 --- a/Frontend/plannerly/lib/models/task_model.dart +++ b/Frontend/plannerly/lib/models/task_model.dart @@ -1,5 +1,3 @@ -import 'dart:convert'; - // ignore_for_file: public_member_api_docs, sort_constructors_first class TaskModel { final String taskId; diff --git a/Frontend/plannerly/lib/models/user_model.dart b/Frontend/plannerly/lib/models/user_model.dart index bde5d14..5581dd5 100644 --- a/Frontend/plannerly/lib/models/user_model.dart +++ b/Frontend/plannerly/lib/models/user_model.dart @@ -1,3 +1,5 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first + class User { // ID primitive.ObjectID `bson:"_id"` // First_name *string `json:"first_name" validate:"required,min=2,max=100"` @@ -16,4 +18,68 @@ class User { String? token; String? phone; String? userId; + User({ + this.firstName, + this.lastName, + this.email, + this.token, + this.phone, + this.userId, + }); + + User copyWith({ + String? firstName, + String? lastName, + String? email, + String? token, + String? phone, + String? userId, + }) { + return User( + firstName: firstName ?? this.firstName, + lastName: lastName ?? this.lastName, + email: email ?? this.email, + token: token ?? this.token, + phone: phone ?? this.phone, + userId: userId ?? this.userId, + ); + } + + User fromJson(dynamic json) { + return User( + firstName: json["first_name"], + lastName: json["last_name"], + email: json["email"], + token: json["token"], + phone: json["phone"], + userId: json["user_id"], + ); + } + + @override + String toString() { + return 'User(firstName: $firstName, lastName: $lastName, email: $email, token: $token, phone: $phone, userId: $userId)'; + } + + @override + bool operator ==(covariant User other) { + if (identical(this, other)) return true; + + return other.firstName == firstName && + other.lastName == lastName && + other.email == email && + other.token == token && + other.phone == phone && + other.userId == userId; + } + + @override + int get hashCode { + return firstName.hashCode ^ + lastName.hashCode ^ + email.hashCode ^ + token.hashCode ^ + phone.hashCode ^ + userId.hashCode; + } } diff --git a/Frontend/plannerly/lib/screens/home/home.dart b/Frontend/plannerly/lib/screens/home/home.dart index 214a9e0..fe92b15 100644 --- a/Frontend/plannerly/lib/screens/home/home.dart +++ b/Frontend/plannerly/lib/screens/home/home.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:fluttertoast/fluttertoast.dart'; +import 'package:plannerly/screens/home/home_loading.dart'; import 'package:plannerly/screens/regular_tasks/regular_tasks_page.dart'; import 'package:plannerly/screens/urgent_tasks/urgent_tasks_page.dart'; import 'package:plannerly/screens/widgets/form_field.dart'; @@ -115,13 +116,13 @@ class _HomeScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ TaskFormField( - title: "Title", + title: "Title :", hint: "Title", controller: titleContr, ), const SizedBox(height: 14), TaskFormField( - title: "Description", + title: "Description :", hint: "Description", controller: descContr, height: size.height * 0.16, @@ -129,19 +130,19 @@ class _HomeScreenState extends State { ), const SizedBox(height: 14), TaskFormField( - title: "Date", + title: "Date :", hint: "DD/MM/YYYY", controller: dateContr, ), const SizedBox(height: 14), TaskFormField( - title: "Time", + title: "Time :", hint: "HH:MM:SS", controller: timeContr, ), const SizedBox(height: 14), TaskFormField( - title: "Urgent", + title: "Urgent :", hint: "True/False", controller: urgContr, ), @@ -212,10 +213,7 @@ class _HomeScreenState extends State { builder: (context, state) { switch (state.runtimeType) { case HomeLoadingState: - return const Scaffold( - backgroundColor: AppColors.backgroundDark, - body: Center(child: CircularProgressIndicator()), - ); + return const HomeLoading(); case HomeLoadedSuccessState: final successState = state as HomeLoadedSuccessState; return Scaffold( diff --git a/Frontend/plannerly/lib/screens/home/home_loading.dart b/Frontend/plannerly/lib/screens/home/home_loading.dart new file mode 100644 index 0000000..db4cf65 --- /dev/null +++ b/Frontend/plannerly/lib/screens/home/home_loading.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:loading_animation_widget/loading_animation_widget.dart'; +import 'package:plannerly/utils/colors/colors.dart'; + +class HomeLoading extends StatelessWidget { + const HomeLoading({super.key}); + + @override + Widget build(BuildContext context) { + Size size = MediaQuery.of(context).size; + return Scaffold( + backgroundColor: AppColors.backgroundDark, + body: Center( + child: Container( + height: size.height * 0.16, + width: size.width * 0.5, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(18), + color: AppColors.backgroundLight), + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + children: [ + const Text( + 'Please wait...!!', + style: TextStyle( + color: AppColors.white, + fontSize: 19, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 10), + LoadingAnimationWidget.fourRotatingDots( + color: AppColors.buttonBlue, + size: 50, + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/Frontend/plannerly/lib/screens/login/login.dart b/Frontend/plannerly/lib/screens/login/login.dart new file mode 100644 index 0000000..c58999b --- /dev/null +++ b/Frontend/plannerly/lib/screens/login/login.dart @@ -0,0 +1,131 @@ +import 'package:flutter/material.dart'; +import 'package:plannerly/screens/widgets/form_field.dart'; +import 'package:plannerly/utils/colors/colors.dart'; + +class LoginPage extends StatefulWidget { + const LoginPage({super.key}); + + @override + State createState() => _LoginPageState(); +} + +class _LoginPageState extends State { + @override + Widget build(BuildContext context) { + Size size = MediaQuery.of(context).size; + TextEditingController userName = TextEditingController(); + TextEditingController pass = TextEditingController(); + return Scaffold( + backgroundColor: AppColors.backgroundDark, + body: SafeArea( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Center( + child: Text( + "Welcome to Plannerly !!", + style: TextStyle( + color: AppColors.white, + fontSize: 25, + fontWeight: FontWeight.w500, + ), + ), + ), + const SizedBox(height: 10), + const Center( + child: Text( + // "Let's get your things planned.", + "Planning Your Way to Productivity.", + style: TextStyle( + color: AppColors.white, + fontSize: 18, + fontWeight: FontWeight.w300, + ), + ), + ), + const SizedBox(height: 10), + Image.asset( + 'assets/images/logo_transparent.png', + scale: 1.8, + ), + SizedBox( + width: size.width * 0.8, + child: Column( + children: [ + TaskFormField( + title: '', + hint: 'Username', + controller: userName, + ), + TaskFormField( + title: '', + hint: 'Password', + controller: pass, + ), + ], + ), + ), + SizedBox(height: size.height * 0.05), + Center( + child: GestureDetector( + onTap: () {}, + child: Container( + width: size.width * 0.7, + height: size.height * 0.07, + decoration: BoxDecoration( + color: AppColors.buttonBlue, + borderRadius: BorderRadius.circular(16), + ), + child: const Center( + child: Text( + "Login", + style: TextStyle( + color: AppColors.white, + fontSize: 20, + fontWeight: FontWeight.w400, + ), + ), + ), + ), + ), + ), + const SizedBox(height: 10), + Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + "Don't have an account?", + style: TextStyle( + color: AppColors.white, + fontSize: 18, + fontWeight: FontWeight.w300, + ), + ), + TextButton( + onPressed: () {}, + child: const Center( + child: Text( + "Sign-up", + style: TextStyle( + decoration: TextDecoration.underline, + color: AppColors.buttonBlue, + fontSize: 18, + fontWeight: FontWeight.w400, + ), + ), + ), + ), + ], + ), + ) + ], + ), + ), + ), + ); + } +} diff --git a/Frontend/plannerly/lib/screens/regular_tasks/regular_tasks_page.dart b/Frontend/plannerly/lib/screens/regular_tasks/regular_tasks_page.dart index 545bc9a..130c5cd 100644 --- a/Frontend/plannerly/lib/screens/regular_tasks/regular_tasks_page.dart +++ b/Frontend/plannerly/lib/screens/regular_tasks/regular_tasks_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:plannerly/bloc/home/home_bloc.dart'; +import 'package:plannerly/screens/home/home_loading.dart'; import 'package:plannerly/screens/widgets/task.dart'; import 'package:plannerly/utils/colors/colors.dart'; @@ -34,10 +35,7 @@ class _RegularTasksState extends State { builder: (context, state) { switch (state.runtimeType) { case HomeLoadingState: - return const Scaffold( - backgroundColor: AppColors.backgroundDark, - body: Center(child: CircularProgressIndicator()), - ); + return const HomeLoading(); case HomeLoadedSuccessState: final successState = state as HomeLoadedSuccessState; return Scaffold( diff --git a/Frontend/plannerly/lib/screens/signup/signup.dart b/Frontend/plannerly/lib/screens/signup/signup.dart new file mode 100644 index 0000000..231e58f --- /dev/null +++ b/Frontend/plannerly/lib/screens/signup/signup.dart @@ -0,0 +1,152 @@ +import 'package:flutter/material.dart'; +import 'package:plannerly/screens/widgets/form_field.dart'; +import 'package:plannerly/utils/colors/colors.dart'; + +class SignUpPage extends StatefulWidget { + const SignUpPage({super.key}); + + @override + State createState() => _SignUpPageState(); +} + +class _SignUpPageState extends State { + @override + Widget build(BuildContext context) { + Size size = MediaQuery.of(context).size; + TextEditingController fuserName = TextEditingController(); + TextEditingController luserName = TextEditingController(); + TextEditingController email = TextEditingController(); + TextEditingController phone = TextEditingController(); + TextEditingController pass = TextEditingController(); + return Scaffold( + backgroundColor: AppColors.backgroundDark, + body: SafeArea( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // SizedBox(height: size.height * 0.12), + Image.asset( + 'assets/images/logo_transparent.png', + scale: 3.2, + ), + const Center( + child: Text( + "Welcome to Plannerly !!", + style: TextStyle( + color: AppColors.white, + fontSize: 25, + fontWeight: FontWeight.w500, + ), + ), + ), + const SizedBox(height: 10), + const Center( + child: Text( + // "Let's get your things planned.", + "Planning Your Way to Productivity.", + style: TextStyle( + color: AppColors.white, + fontSize: 18, + fontWeight: FontWeight.w300, + ), + ), + ), + const SizedBox(height: 10), + SizedBox( + width: size.width * 0.8, + child: Column( + children: [ + TaskFormField( + title: '', + hint: 'First-name', + controller: fuserName, + ), + TaskFormField( + title: '', + hint: 'Last-name', + controller: luserName, + ), + TaskFormField( + title: '', + hint: 'Phone', + controller: phone, + ), + TaskFormField( + title: '', + hint: 'Email', + controller: email, + ), + TaskFormField( + title: '', + hint: 'Password', + controller: pass, + ), + ], + ), + ), + SizedBox(height: size.height * 0.05), + Center( + child: GestureDetector( + onTap: () {}, + child: Container( + width: size.width * 0.7, + height: size.height * 0.07, + decoration: BoxDecoration( + color: AppColors.buttonBlue, + borderRadius: BorderRadius.circular(16), + ), + child: const Center( + child: Text( + "Sign-Up", + style: TextStyle( + color: AppColors.white, + fontSize: 20, + fontWeight: FontWeight.w400, + ), + ), + ), + ), + ), + ), + const SizedBox(height: 10), + Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + "Already have an account?", + style: TextStyle( + color: AppColors.white, + fontSize: 18, + fontWeight: FontWeight.w300, + ), + ), + TextButton( + onPressed: () {}, + child: const Center( + child: Text( + "Login", + style: TextStyle( + decoration: TextDecoration.underline, + color: AppColors.buttonBlue, + fontSize: 18, + fontWeight: FontWeight.w400, + ), + ), + ), + ), + ], + ), + ) + ], + ), + ), + ), + ), + ); + } +} diff --git a/Frontend/plannerly/lib/screens/urgent_tasks/urgent_tasks_page.dart b/Frontend/plannerly/lib/screens/urgent_tasks/urgent_tasks_page.dart index 59fa710..ed5deb3 100644 --- a/Frontend/plannerly/lib/screens/urgent_tasks/urgent_tasks_page.dart +++ b/Frontend/plannerly/lib/screens/urgent_tasks/urgent_tasks_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:plannerly/bloc/home/home_bloc.dart'; +import 'package:plannerly/screens/home/home_loading.dart'; import 'package:plannerly/screens/widgets/task.dart'; import 'package:plannerly/utils/colors/colors.dart'; @@ -34,10 +35,7 @@ class _UrgentTasksState extends State { builder: (context, state) { switch (state.runtimeType) { case HomeLoadingState: - return const Scaffold( - backgroundColor: AppColors.backgroundDark, - body: Center(child: CircularProgressIndicator()), - ); + return const HomeLoading(); case HomeLoadedSuccessState: final successState = state as HomeLoadedSuccessState; return Scaffold( diff --git a/Frontend/plannerly/lib/screens/widgets/form_field.dart b/Frontend/plannerly/lib/screens/widgets/form_field.dart index bcb9e28..a6b5ccc 100644 --- a/Frontend/plannerly/lib/screens/widgets/form_field.dart +++ b/Frontend/plannerly/lib/screens/widgets/form_field.dart @@ -27,7 +27,7 @@ class _TaskFormFieldState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "${widget.title} : ", + "${widget.title} ", style: const TextStyle( color: AppColors.white, fontSize: 20, diff --git a/Frontend/plannerly/lib/utils/server/server_constants.dart b/Frontend/plannerly/lib/utils/server/server_constants.dart index c390685..b495d43 100644 --- a/Frontend/plannerly/lib/utils/server/server_constants.dart +++ b/Frontend/plannerly/lib/utils/server/server_constants.dart @@ -3,4 +3,4 @@ var userId = "653a2f71e2330ac369e93c9b"; // var baseUrl = "http://192.168.2.52:8000"; var baseUrl = "https://go-plannerly-api.onrender.com"; var token = - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJFbWFpbCI6ImpvaG4uZG9lQGdtYWlsLmNvbSIsIkZpcnN0X25hbWUiOiJKb2huIiwiTGFzdF9uYW1lIjoiRG9lIiwiVWlkIjoiNjUzYTJmNzFlMjMzMGFjMzY5ZTkzYzliIiwiZXhwIjoxNjk5Mjc3MTYwfQ.xvzZ3bdzAagcorXju4cR8o3M51ZC0ZILbMxQmnYG4DE"; + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJFbWFpbCI6ImpvaG4uZG9lQGdtYWlsLmNvbSIsIkZpcnN0X25hbWUiOiJKb2huIiwiTGFzdF9uYW1lIjoiRG9lIiwiVWlkIjoiNjUzYTJmNzFlMjMzMGFjMzY5ZTkzYzliIiwiZXhwIjoxNjk5NDQyMzY1fQ.3RxKBUZWuWwdT-5CtSWA36bR_80Z95GnDHbB0l84ePY"; diff --git a/Frontend/plannerly/pubspec.lock b/Frontend/plannerly/pubspec.lock index 9b21f11..31134e8 100644 --- a/Frontend/plannerly/pubspec.lock +++ b/Frontend/plannerly/pubspec.lock @@ -128,6 +128,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + loading_animation_widget: + dependency: "direct main" + description: + name: loading_animation_widget + sha256: "1901682600273a966c34cf44a85fc5355da92a8d08a8a43c11adc4e471993e3a" + url: "https://pub.dev" + source: hosted + version: "1.2.0+4" matcher: dependency: transitive description: diff --git a/Frontend/plannerly/pubspec.yaml b/Frontend/plannerly/pubspec.yaml index 73a03f2..2f79a1d 100644 --- a/Frontend/plannerly/pubspec.yaml +++ b/Frontend/plannerly/pubspec.yaml @@ -39,6 +39,7 @@ dependencies: cupertino_icons: ^1.0.2 http: ^1.1.0 fluttertoast: ^8.2.2 + loading_animation_widget: ^1.2.0+4 dev_dependencies: flutter_test: