From 70f3744274cb357eaae2689d6a8975c84da32140 Mon Sep 17 00:00:00 2001 From: Praveen Krishna <84656853+praveenkrishna0512@users.noreply.github.com> Date: Wed, 22 Jun 2022 18:25:51 +0800 Subject: [PATCH] Feat/refining user auth (#14) * Added Form widget to signup page * Added Form validation to signup page * Made Form Validation.dart * Added Form validation to all fields in signup page Moving forward, use flutter:validators library to conduct form field checks * Made Sign Up Page scrollable * Added proper sign up functionality * Completed half update of user data from sign up page * Added server-side signup functionality * Configured Firebase * Added sign in functoinality * Commented out supabase stuff * Bypassed splash page * Shifted user authstate flow to main_page.dart * reverted prev commit * Enabled login funcitonality * Added logout functionality to feed page * fixed setState before build issue * removed firebase auth logic for navigating through pages, for now * Added auth_services.dart * Added auth_provider.dart * Rearranged some files * Added home_controller.dart * configured main.dart to use hom controller * Added sign up functionality * minor edits --- android/app/google-services.json | 90 ++++++ ios/firebase_app_id_file.json | 7 + lib/components/auth_required_state.dart | 13 - lib/components/auth_state.dart | 28 -- lib/firebase/auth_provider.dart | 19 ++ lib/firebase/auth_service.dart | 14 + lib/firebase/firebase_options.dart | 83 +++++ lib/home_controller.dart | 29 ++ lib/main.dart | 55 ++-- lib/models/ForBorrowing.dart | 2 +- lib/models/ForRenting.dart | 2 +- lib/models/ListingCard.dart | 2 +- lib/models/feedTitle.dart | 2 +- lib/pages/feed_page.dart | 18 +- lib/pages/forget_password.dart | 6 +- lib/pages/login_page.dart | 37 ++- lib/pages/profile_page.dart | 15 +- lib/pages/signup_page.dart | 297 ++++++++++-------- lib/pages/splash_page.dart | 44 +-- lib/supabase/supabase_manager.dart | 49 --- lib/{ => utils}/apptheme.dart | 0 lib/{ => utils}/const_templates.dart | 0 lib/utils/constants.dart | 2 - lib/utils/form_validation.dart | 23 ++ macos/Flutter/GeneratedPluginRegistrant.swift | 4 + macos/firebase_app_id_file.json | 7 + pubspec.lock | 105 +++++++ pubspec.yaml | 5 + 28 files changed, 650 insertions(+), 308 deletions(-) create mode 100644 android/app/google-services.json create mode 100644 ios/firebase_app_id_file.json delete mode 100644 lib/components/auth_required_state.dart delete mode 100644 lib/components/auth_state.dart create mode 100644 lib/firebase/auth_provider.dart create mode 100644 lib/firebase/auth_service.dart create mode 100644 lib/firebase/firebase_options.dart create mode 100644 lib/home_controller.dart delete mode 100644 lib/supabase/supabase_manager.dart rename lib/{ => utils}/apptheme.dart (100%) rename lib/{ => utils}/const_templates.dart (100%) create mode 100644 lib/utils/form_validation.dart create mode 100644 macos/firebase_app_id_file.json diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 0000000..77e775e --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,90 @@ +{ + "project_info": { + "project_number": "10879165640", + "project_id": "justsharelah-6dca5", + "storage_bucket": "justsharelah-6dca5.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:10879165640:android:c657eaf794db8614dff1fd", + "android_client_info": { + "package_name": "com.example.justsharelah_v1" + } + }, + "oauth_client": [ + { + "client_id": "10879165640-678p35fbbk6hq6upl2m32tl5mi54o8d7.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCp1VNKc82AuklUJVaLTWczmSflEcmYAzE" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "10879165640-678p35fbbk6hq6upl2m32tl5mi54o8d7.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "10879165640-82ja20ouc8u9tu8id6cbr81nffqkd03p.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "com.summer.justsharelah" + } + } + ] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:10879165640:android:387e1e6c8d037fd4dff1fd", + "android_client_info": { + "package_name": "com.summer.justsharelah" + } + }, + "oauth_client": [ + { + "client_id": "10879165640-ipqeaemtarv9h5kpgsr216su9r9pueqk.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.summer.justsharelah", + "certificate_hash": "9b1b89208acdf122cea3ff6c734bd622640ee6aa" + } + }, + { + "client_id": "10879165640-678p35fbbk6hq6upl2m32tl5mi54o8d7.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCp1VNKc82AuklUJVaLTWczmSflEcmYAzE" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "10879165640-678p35fbbk6hq6upl2m32tl5mi54o8d7.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "10879165640-82ja20ouc8u9tu8id6cbr81nffqkd03p.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "com.summer.justsharelah" + } + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/ios/firebase_app_id_file.json b/ios/firebase_app_id_file.json new file mode 100644 index 0000000..af86760 --- /dev/null +++ b/ios/firebase_app_id_file.json @@ -0,0 +1,7 @@ +{ + "file_generated_by": "FlutterFire CLI", + "purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory", + "GOOGLE_APP_ID": "1:10879165640:ios:f463674769a076dadff1fd", + "FIREBASE_PROJECT_ID": "justsharelah-6dca5", + "GCM_SENDER_ID": "10879165640" +} \ No newline at end of file diff --git a/lib/components/auth_required_state.dart b/lib/components/auth_required_state.dart deleted file mode 100644 index af06050..0000000 --- a/lib/components/auth_required_state.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:supabase_flutter/supabase_flutter.dart'; - -class AuthRequiredState - extends SupabaseAuthRequiredState { - @override - void onUnauthenticated() { - /// Users will be sent back to the LoginPage if they sign out. - if (mounted) { - Navigator.of(context).pushNamedAndRemoveUntil('/login', (route) => false); - } - } -} \ No newline at end of file diff --git a/lib/components/auth_state.dart b/lib/components/auth_state.dart deleted file mode 100644 index a9028f5..0000000 --- a/lib/components/auth_state.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:supabase_flutter/supabase_flutter.dart'; -import 'package:justsharelah_v1/utils/constants.dart'; - -class AuthState extends SupabaseAuthState { - @override - void onUnauthenticated() { - if (mounted) { - Navigator.of(context).pushNamedAndRemoveUntil('/login', (route) => false); - } - } - - @override - void onAuthenticated(Session session) { - if (mounted) { - Navigator.of(context) - .pushNamedAndRemoveUntil('/feed', (route) => false); - } - } - - @override - void onPasswordRecovery(Session session) {} - - @override - void onErrorAuthenticating(String message) { - context.showErrorSnackBar(message: message); - } -} \ No newline at end of file diff --git a/lib/firebase/auth_provider.dart b/lib/firebase/auth_provider.dart new file mode 100644 index 0000000..d04f42a --- /dev/null +++ b/lib/firebase/auth_provider.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; +import 'auth_service.dart'; + +class Provider extends InheritedWidget { + final AuthService auth; + const Provider({ + Key? key, + required Widget child, + required this.auth, + }) : super(key: key, child: child); + + @override + bool updateShouldNotify(InheritedWidget oldWiddget) { + return true; + } + + static Provider? of(BuildContext context) => + (context.dependOnInheritedWidgetOfExactType()); +} \ No newline at end of file diff --git a/lib/firebase/auth_service.dart b/lib/firebase/auth_service.dart new file mode 100644 index 0000000..04d5fd3 --- /dev/null +++ b/lib/firebase/auth_service.dart @@ -0,0 +1,14 @@ +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:google_sign_in/google_sign_in.dart'; + +class AuthService { + final FirebaseAuth _firebaseAuth = FirebaseAuth.instance; + final GoogleSignIn _googleSignIn = GoogleSignIn(); + + Stream get onAuthStateChanged => _firebaseAuth.authStateChanges(); + + // GET UID + Future getCurrentUID() async { + return _firebaseAuth.currentUser?.uid; + } +} \ No newline at end of file diff --git a/lib/firebase/firebase_options.dart b/lib/firebase/firebase_options.dart new file mode 100644 index 0000000..ce4ea0d --- /dev/null +++ b/lib/firebase/firebase_options.dart @@ -0,0 +1,83 @@ +// File generated by FlutterFire CLI. +// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members +import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; +import 'package:flutter/foundation.dart' + show defaultTargetPlatform, kIsWeb, TargetPlatform; + +/// Default [FirebaseOptions] for use with your Firebase apps. +/// +/// Example: +/// ```dart +/// import 'firebase_options.dart'; +/// // ... + +/// ``` +class DefaultFirebaseOptions { + static FirebaseOptions get currentPlatform { + if (kIsWeb) { + return web; + } + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return android; + case TargetPlatform.iOS: + return ios; + case TargetPlatform.macOS: + return macos; + case TargetPlatform.windows: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for windows - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.linux: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for linux - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + default: + throw UnsupportedError( + 'DefaultFirebaseOptions are not supported for this platform.', + ); + } + } + + static const FirebaseOptions web = FirebaseOptions( + apiKey: 'AIzaSyAmt6eFJ7rvE-ke6AVJ01wDzUwpbUqnVKI', + appId: '1:10879165640:web:e8fc1af81bacce30dff1fd', + messagingSenderId: '10879165640', + projectId: 'justsharelah-6dca5', + authDomain: 'justsharelah-6dca5.firebaseapp.com', + storageBucket: 'justsharelah-6dca5.appspot.com', + measurementId: 'G-G1LWCXS2T0', + ); + + static const FirebaseOptions android = FirebaseOptions( + apiKey: 'AIzaSyCp1VNKc82AuklUJVaLTWczmSflEcmYAzE', + appId: '1:10879165640:android:c657eaf794db8614dff1fd', + messagingSenderId: '10879165640', + projectId: 'justsharelah-6dca5', + storageBucket: 'justsharelah-6dca5.appspot.com', + ); + + static const FirebaseOptions ios = FirebaseOptions( + apiKey: 'AIzaSyDQsTMIfIVUGUi9bfyHjBpgQPzo-4vHPhc', + appId: '1:10879165640:ios:f463674769a076dadff1fd', + messagingSenderId: '10879165640', + projectId: 'justsharelah-6dca5', + storageBucket: 'justsharelah-6dca5.appspot.com', + androidClientId: '10879165640-ipqeaemtarv9h5kpgsr216su9r9pueqk.apps.googleusercontent.com', + iosClientId: '10879165640-q602g5sl8aupgj1vmh1mfj22u8qp9vf6.apps.googleusercontent.com', + iosBundleId: 'com.example.justsharelahV1', + ); + + static const FirebaseOptions macos = FirebaseOptions( + apiKey: 'AIzaSyDQsTMIfIVUGUi9bfyHjBpgQPzo-4vHPhc', + appId: '1:10879165640:ios:f463674769a076dadff1fd', + messagingSenderId: '10879165640', + projectId: 'justsharelah-6dca5', + storageBucket: 'justsharelah-6dca5.appspot.com', + androidClientId: '10879165640-ipqeaemtarv9h5kpgsr216su9r9pueqk.apps.googleusercontent.com', + iosClientId: '10879165640-q602g5sl8aupgj1vmh1mfj22u8qp9vf6.apps.googleusercontent.com', + iosBundleId: 'com.example.justsharelahV1', + ); +} diff --git a/lib/home_controller.dart b/lib/home_controller.dart new file mode 100644 index 0000000..ae59577 --- /dev/null +++ b/lib/home_controller.dart @@ -0,0 +1,29 @@ +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:justsharelah_v1/pages/feed_page.dart'; +import 'package:justsharelah_v1/pages/login_page.dart'; + +import 'firebase/auth_provider.dart'; +import 'firebase/auth_service.dart'; + +class HomeController extends StatelessWidget { + const HomeController({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final AuthService auth = Provider.of(context)!.auth; + + return StreamBuilder( + stream: auth.onAuthStateChanged, + builder: (context, AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.active) { + final bool signedIn = snapshot.hasData; + return signedIn ? const FeedPage() : const LoginPage(); + } + return Container( + color: Colors.black, + ); + }, + ); + } +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 3c5eb1c..3108afc 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,50 +1,55 @@ +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; -import 'package:justsharelah_v1/apptheme.dart'; +import 'package:justsharelah_v1/firebase/auth_service.dart'; +import 'package:justsharelah_v1/utils/apptheme.dart'; import 'package:justsharelah_v1/pages/activity.dart'; import 'package:justsharelah_v1/pages/addListing.dart'; import 'package:justsharelah_v1/pages/feed_page.dart'; import 'package:justsharelah_v1/pages/forget_password.dart'; +import 'package:justsharelah_v1/home_controller.dart'; import 'package:justsharelah_v1/pages/signup_page.dart'; import 'package:justsharelah_v1/pages/profile_page.dart'; -import 'package:supabase_flutter/supabase_flutter.dart'; -import 'package:justsharelah_v1/pages/account_page.dart'; import 'package:justsharelah_v1/pages/login_page.dart'; import 'package:justsharelah_v1/pages/splash_page.dart'; -import 'package:google_fonts/google_fonts.dart'; import 'package:justsharelah_v1/pages/chat_page.dart'; +import 'firebase/auth_provider.dart'; +import 'firebase/firebase_options.dart'; + Future main() async { WidgetsFlutterBinding.ensureInitialized(); - - // TODO: Use .env - await Supabase.initialize( - url: 'https://etegbwhzssurytyojhtf.supabase.co', - anonKey: - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImV0ZWdid2h6c3N1cnl0eW9qaHRmIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTMyMTIyMjEsImV4cCI6MTk2ODc4ODIyMX0.AbyAtt9P8DPc1MuvfAaPmZ03xI9LjA4L1jc3NZujPbU', + await Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, ); runApp(MyApp()); } +final navigatorKey = GlobalKey(); + class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { - return MaterialApp( - title: 'JustShareLah', - theme: AppTheme().buildThemeData(), - initialRoute: '/', - routes: { - '/': (_) => const SplashPage(), - '/forget_password': (_) => const ForgetPassword(), - '/login': (_) => const LoginPage(), - '/signup': (_) => const SignupPage(), - '/feed': (_) => const FeedPage(), - '/chat': (_) => const ChatPage(), - '/addlisting': (_) => const AddListingPage(), - '/profile': (_) => const ProfilePage(), - '/activity': (_) => const ActivityPage(), - }, + return Provider( + auth: AuthService(), + child: MaterialApp( + title: 'JustShareLah', + theme: AppTheme().buildThemeData(), + navigatorKey: navigatorKey, + home: const HomeController(), + routes: { + '/forget_password': (_) => const ForgetPassword(), + '/login': (_) => const LoginPage(), + '/signup': (_) => const SignupPage(), + '/feed': (_) => const FeedPage(), + '/chat': (_) => const ChatPage(), + '/addlisting': (_) => const AddListingPage(), + '/profile': (_) => const ProfilePage(), + '/activity': (_) => const ActivityPage(), + }, + ), ); } } diff --git a/lib/models/ForBorrowing.dart b/lib/models/ForBorrowing.dart index c826b7f..b3c07ba 100644 --- a/lib/models/ForBorrowing.dart +++ b/lib/models/ForBorrowing.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:justsharelah_v1/const_templates.dart'; +import 'package:justsharelah_v1/utils/const_templates.dart'; import 'package:justsharelah_v1/models/ListingCard.dart'; import 'package:justsharelah_v1/models/enlarged_listing.dart'; import 'package:justsharelah_v1/models/feedTitle.dart'; diff --git a/lib/models/ForRenting.dart b/lib/models/ForRenting.dart index e1659f0..3e991d3 100644 --- a/lib/models/ForRenting.dart +++ b/lib/models/ForRenting.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:justsharelah_v1/const_templates.dart'; +import 'package:justsharelah_v1/utils/const_templates.dart'; import 'package:justsharelah_v1/models/ListingCard.dart'; import 'package:justsharelah_v1/models/enlarged_listing.dart'; import 'package:justsharelah_v1/models/feedTitle.dart'; diff --git a/lib/models/ListingCard.dart b/lib/models/ListingCard.dart index 0e8e112..51e94ad 100644 --- a/lib/models/ListingCard.dart +++ b/lib/models/ListingCard.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import '../const_templates.dart'; +import '../utils/const_templates.dart'; class ListingCard extends StatelessWidget { const ListingCard({ diff --git a/lib/models/feedTitle.dart b/lib/models/feedTitle.dart index 7fe186f..bb69e07 100644 --- a/lib/models/feedTitle.dart +++ b/lib/models/feedTitle.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:justsharelah_v1/const_templates.dart'; +import 'package:justsharelah_v1/utils/const_templates.dart'; class FeedTitle extends StatelessWidget { const FeedTitle({ diff --git a/lib/pages/feed_page.dart b/lib/pages/feed_page.dart index 1eff9a2..1ca0c05 100644 --- a/lib/pages/feed_page.dart +++ b/lib/pages/feed_page.dart @@ -1,12 +1,12 @@ // ignore_for_file: prefer_const_constructors +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:justsharelah_v1/apptheme.dart'; +import 'package:justsharelah_v1/utils/apptheme.dart'; import 'package:justsharelah_v1/models/ForRenting.dart'; import 'package:justsharelah_v1/models/feedTitle.dart'; import 'package:supabase/supabase.dart'; -import 'package:justsharelah_v1/components/auth_required_state.dart'; import 'package:justsharelah_v1/utils/constants.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; import '../models/ForBorrowing.dart'; @@ -14,7 +14,7 @@ import '../models/ListingCard.dart'; import 'chat_page.dart'; import 'addListing.dart'; import 'package:justsharelah_v1/pages/profile_page.dart'; -import 'package:justsharelah_v1/const_templates.dart'; +import 'package:justsharelah_v1/utils/const_templates.dart'; import 'package:justsharelah_v1/utils/appbar.dart'; import 'package:justsharelah_v1/utils/bottom_nav_bar.dart'; import 'package:justsharelah_v1/models/listings.dart'; @@ -95,12 +95,8 @@ class _FeedPageState extends State { super.dispose(); } - Future _signOut() async { - final response = await supabase.auth.signOut(); - final error = response.error; - if (error != null) { - context.showErrorSnackBar(message: error.message); - } + _signOut() async { + FirebaseAuth.instance.signOut(); } @override @@ -109,7 +105,9 @@ class _FeedPageState extends State { appBar: AppBar( leading: IconButton( icon: const Icon(Icons.arrow_back_rounded), - onPressed: () {}, + onPressed: () { + _signOut(); + }, ), title: Row( mainAxisAlignment: MainAxisAlignment.center, diff --git a/lib/pages/forget_password.dart b/lib/pages/forget_password.dart index d550f3e..ace4a24 100644 --- a/lib/pages/forget_password.dart +++ b/lib/pages/forget_password.dart @@ -1,7 +1,7 @@ // ignore_for_file: prefer_const_constructors import 'package:flutter/material.dart'; -import 'package:justsharelah_v1/const_templates.dart'; +import 'package:justsharelah_v1/utils/const_templates.dart'; import 'package:justsharelah_v1/utils/constants.dart'; class ForgetPassword extends StatelessWidget { @@ -52,7 +52,9 @@ class ForgetPassword extends StatelessWidget { SizedBox( height: 20, ), - ElevatedButton(onPressed: () {}, child: Text('Send')), + ElevatedButton( + onPressed: () {}, + child: Text('Send')), ], ), ) diff --git a/lib/pages/login_page.dart b/lib/pages/login_page.dart index 03021c6..e099c04 100644 --- a/lib/pages/login_page.dart +++ b/lib/pages/login_page.dart @@ -1,10 +1,8 @@ -// ignore_for_file: prefer_const_constructors - +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; -import 'package:justsharelah_v1/components/auth_state.dart'; -import 'package:justsharelah_v1/const_templates.dart'; +import 'package:justsharelah_v1/utils/const_templates.dart'; +import 'package:justsharelah_v1/main.dart'; import 'package:justsharelah_v1/utils/constants.dart'; -// import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart'; class LoginPage extends StatefulWidget { const LoginPage({Key? key}) : super(key: key); @@ -13,7 +11,7 @@ class LoginPage extends StatefulWidget { _LoginPageState createState() => _LoginPageState(); } -class _LoginPageState extends AuthState { +class _LoginPageState extends State { bool _isLoading = false; late final TextEditingController _emailController; late final TextEditingController _passwordController; @@ -22,17 +20,18 @@ class _LoginPageState extends AuthState { setState(() { _isLoading = true; }); + + try { + final response = await FirebaseAuth.instance.signInWithEmailAndPassword( + email: _emailController.text.trim(), + password: _passwordController.text.trim(), + ); - final response = await supabase.auth.signIn( - email: _emailController.text, - password: _passwordController.text, - ); - - final error = response.error; - if (error != null) { - context.showErrorSnackBar(message: error.message); - } else { - Navigator.of(context).pushNamedAndRemoveUntil('/feed', (route) => false); + if (response.user == null) { + context.showErrorSnackBar(message: "Error Signing In"); + } + } on FirebaseAuthException catch (e) { + print(e); } setState(() { @@ -114,7 +113,11 @@ class _LoginPageState extends AuthState { children: [ Expanded( child: ElevatedButton( - onPressed: _isLoading ? null : _signIn, + onPressed: _isLoading + ? null + : () { + _signIn(); + }, child: Text(_isLoading ? 'Loading' : 'Log In'), ), ), diff --git a/lib/pages/profile_page.dart b/lib/pages/profile_page.dart index d583240..61fafe7 100644 --- a/lib/pages/profile_page.dart +++ b/lib/pages/profile_page.dart @@ -1,8 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:justsharelah_v1/apptheme.dart'; +import 'package:justsharelah_v1/utils/apptheme.dart'; import 'package:justsharelah_v1/utils/bottom_nav_bar.dart'; import 'package:supabase/supabase.dart'; -import 'package:justsharelah_v1/components/auth_required_state.dart'; import 'package:justsharelah_v1/utils/constants.dart'; class ProfilePage extends StatefulWidget { @@ -12,7 +11,7 @@ class ProfilePage extends StatefulWidget { _ProfilePageState createState() => _ProfilePageState(); } -class _ProfilePageState extends AuthRequiredState { +class _ProfilePageState extends State { var _loading = false; // Index for bottom nav bar int _selectedIndex = 0; @@ -71,11 +70,11 @@ class _ProfilePageState extends AuthRequiredState { } Future _signOut() async { - final response = await supabase.auth.signOut(); - final error = response.error; - if (error != null) { - context.showErrorSnackBar(message: error.message); - } + // final response = await supabase.auth.signOut(); + // final error = response.error; + // if (error != null) { + // context.showErrorSnackBar(message: error.message); + // } } @override diff --git a/lib/pages/signup_page.dart b/lib/pages/signup_page.dart index ab78d2a..1c9fe7e 100644 --- a/lib/pages/signup_page.dart +++ b/lib/pages/signup_page.dart @@ -1,12 +1,14 @@ -// ignore_for_file: prefer_const_constructors - +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:justsharelah_v1/utils/form_validation.dart'; import 'package:supabase/supabase.dart'; -import 'package:justsharelah_v1/components/auth_state.dart'; import 'package:justsharelah_v1/utils/constants.dart'; -import 'package:justsharelah_v1/const_templates.dart'; +import 'package:justsharelah_v1/utils/const_templates.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:uuid/uuid.dart'; class SignupPage extends StatefulWidget { const SignupPage({Key? key}) : super(key: key); @@ -15,8 +17,9 @@ class SignupPage extends StatefulWidget { _SignupPageState createState() => _SignupPageState(); } -class _SignupPageState extends AuthState { +class _SignupPageState extends State { bool _isLoading = false; + final _signupFormKey = GlobalKey(); late final TextEditingController _emailController; late final TextEditingController _usernameController; late final TextEditingController _firstnameController; @@ -24,25 +27,35 @@ class _SignupPageState extends AuthState { late final TextEditingController _passwordController; late final TextEditingController _cfmpasswordController; - Future _signUp() async { + Future _signUp() async { setState(() { _isLoading = true; }); - final response = await supabase.auth - .signUp(_emailController.text, _passwordController.text); + try { + final response = + await FirebaseAuth.instance.createUserWithEmailAndPassword( + email: _emailController.text.trim(), + password: _passwordController.text.trim(), + ); - final error = response.error; - if (error != null) { - context.showErrorSnackBar(message: error.message); - } else { - context.showSnackBar(message: 'Sign Up Successful!'); - Navigator.of(context).pushNamedAndRemoveUntil("/login", (route) => false); + if (response.user == null) { + return false; + } + } on FirebaseAuthException catch (e) { + print(e); + // ScaffoldMessenger.of(context).showSnackBar( + // const SnackBar( + // content: Text('Signed Up Successfully!'), + // ), + // ); } setState(() { _isLoading = false; }); + // return success; + return true; } @override @@ -75,130 +88,154 @@ class _SignupPageState extends AuthState { title: const Text("JustShareLah!"), centerTitle: true, leading: IconButton( - icon: Icon(Icons.close), + icon: const Icon(Icons.close), onPressed: () { Navigator.pop(context); }), ), - body: Column( - children: [ - Container( - padding: EdgeInsets.all(20.0), - alignment: Alignment.center, - child: Text( - 'Register Your Details!', - style: kHeadingText, - ), - ), - SizedBox( - height: 20.0, - ), - TextFormField( - obscureText: false, - textAlign: TextAlign.center, - controller: _emailController, - decoration: kTextFormFieldDecoration.copyWith( - hintText: 'Enter your email', - labelText: 'Email', - floatingLabelBehavior: FloatingLabelBehavior.always), - ), - const SizedBox(height: 18), - TextFormField( - obscureText: false, - textAlign: TextAlign.center, - controller: _usernameController, - decoration: kTextFormFieldDecoration.copyWith( - hintText: 'Enter your username', - labelText: 'Username', - floatingLabelBehavior: FloatingLabelBehavior.always), - ), - const SizedBox(height: 18), - TextFormField( - obscureText: false, - textAlign: TextAlign.center, - controller: _firstnameController, - decoration: kTextFormFieldDecoration.copyWith( - hintText: 'Enter your first name', - labelText: 'First Name', - floatingLabelBehavior: FloatingLabelBehavior.always), - ), - const SizedBox(height: 18), - TextFormField( - obscureText: false, - textAlign: TextAlign.center, - controller: _lastnameController, - decoration: kTextFormFieldDecoration.copyWith( - hintText: 'Enter your last name', - labelText: 'Last Name', - floatingLabelBehavior: FloatingLabelBehavior.always), - ), - const SizedBox(height: 18), - //TODO: Make sure the passwords are the same - TextFormField( - obscureText: true, - textAlign: TextAlign.center, - controller: _passwordController, - decoration: kTextFormFieldDecoration.copyWith( - hintText: 'Enter your password', - labelText: 'Password', - floatingLabelBehavior: FloatingLabelBehavior.always), - ), - // make sure that the password is same - idk why but doesn't work - const SizedBox(height: 18), - TextFormField( - obscureText: true, - textAlign: TextAlign.center, - controller: _cfmpasswordController, - validator: (value) { - if (value != _passwordController.text) { - return 'Passwords do not match'; - } - return null; - }, - decoration: kTextFormFieldDecoration.copyWith( - hintText: 'Enter the same password as above', - labelText: 'Confirm Password', - floatingLabelBehavior: FloatingLabelBehavior.always), - ), - Expanded(child: const SizedBox()), - Row( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: [ - Align( - alignment: Alignment.bottomCenter, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - // primary: Colors.redAccent, - side: BorderSide(width: 4, color: Colors.black), - elevation: 15, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(20)), - padding: EdgeInsets.all(15)), - onPressed: _isLoading ? null : _signUp, - child: Text(_isLoading ? 'Loading' : 'Register'), - ), + body: SingleChildScrollView( + child: Form( + key: _signupFormKey, + child: SizedBox( + height: MediaQuery.of(context).size.height - + AppBar().preferredSize.height, + width: MediaQuery.of(context).size.width, + child: Padding( + padding: + const EdgeInsets.symmetric(vertical: 18, horizontal: 12), + child: Column( + children: [ + Container( + alignment: Alignment.center, + child: const Text( + 'Register Your Details!', + style: kHeadingText, + ), + ), + const SizedBox( + height: 20.0, + ), + TextFormField( + obscureText: false, + textAlign: TextAlign.center, + controller: _emailController, + validator: FormValidation.validEmail, + decoration: kTextFormFieldDecoration.copyWith( + hintText: 'Enter your email', + labelText: 'Email', + floatingLabelBehavior: FloatingLabelBehavior.always), + ), + const SizedBox(height: 18), + TextFormField( + obscureText: false, + textAlign: TextAlign.center, + controller: _usernameController, + validator: (text) => + FormValidation.enforceNumOfChars(text, 6), + decoration: kTextFormFieldDecoration.copyWith( + hintText: 'Enter your username', + labelText: 'Username', + floatingLabelBehavior: FloatingLabelBehavior.always), + ), + const SizedBox(height: 18), + TextFormField( + obscureText: false, + textAlign: TextAlign.center, + controller: _firstnameController, + validator: FormValidation.formFieldEmpty, + decoration: kTextFormFieldDecoration.copyWith( + hintText: 'Enter your first name', + labelText: 'First Name', + floatingLabelBehavior: FloatingLabelBehavior.always), + ), + const SizedBox(height: 18), + TextFormField( + obscureText: false, + textAlign: TextAlign.center, + controller: _lastnameController, + validator: FormValidation.formFieldEmpty, + decoration: kTextFormFieldDecoration.copyWith( + hintText: 'Enter your last name', + labelText: 'Last Name', + floatingLabelBehavior: FloatingLabelBehavior.always), + ), + const SizedBox(height: 18), + TextFormField( + obscureText: true, + textAlign: TextAlign.center, + controller: _passwordController, + validator: FormValidation.formFieldEmpty, + decoration: kTextFormFieldDecoration.copyWith( + hintText: 'Enter your password', + labelText: 'Password', + floatingLabelBehavior: FloatingLabelBehavior.always), + ), + // make sure that the password is same - idk why but doesn't work + const SizedBox(height: 18), + TextFormField( + obscureText: true, + textAlign: TextAlign.center, + controller: _cfmpasswordController, + validator: (value) { + if (value != _passwordController.text) { + return 'Passwords do not match'; + } + return null; + }, + decoration: kTextFormFieldDecoration.copyWith( + hintText: 'Enter the same password as above', + labelText: 'Confirm Password', + floatingLabelBehavior: FloatingLabelBehavior.always), + ), + const Expanded(child: SizedBox()), + Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: [ + Align( + alignment: Alignment.bottomCenter, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + // primary: Colors.redAccent, + side: const BorderSide( + width: 4, color: Colors.black), + elevation: 15, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20)), + padding: const EdgeInsets.all(15)), + onPressed: () async { + if (_isLoading || + !_signupFormKey.currentState!.validate()) + return; + + bool signedUp = await _signUp(); + if (!signedUp) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text( + 'Error signing up. Try Again.'))); + return; + } + + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: + Text('Signed Up Successfully!'))); + Navigator.of(context).pop(); + }, + child: Text(_isLoading ? 'Loading' : 'Register'), + ), + ), + ], + ), + const SizedBox(height: 30), + ], ), - ], + ), ), - const SizedBox(height: 30), - ], + ), ), ) ]); } } - -// ,)]),) -// Container( -// padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 12), -// child: ListView( -// children: [ -// const SizedBox(height: 32), -// Center( -// child: Text( -// 'Registration', -// style: TextStyle( -// fontSize: -// Theme.of(context).textTheme.headline4?.fontSize ?? -// 32), diff --git a/lib/pages/splash_page.dart b/lib/pages/splash_page.dart index 0a3a101..6ac1102 100644 --- a/lib/pages/splash_page.dart +++ b/lib/pages/splash_page.dart @@ -1,24 +1,28 @@ -import 'package:flutter/material.dart'; -import 'package:justsharelah_v1/components/auth_state.dart'; +// import 'package:flutter/material.dart'; -class SplashPage extends StatefulWidget { - const SplashPage({Key? key}) : super(key: key); +// =================NOT IN USE================================== // - @override - _SplashPageState createState() => _SplashPageState(); -} +// class SplashPage extends StatefulWidget { +// const SplashPage({Key? key}) : super(key: key); -class _SplashPageState extends AuthState { - @override - void initState() { - recoverSupabaseSession(); - super.initState(); - } +// @override +// _SplashPageState createState() => _SplashPageState(); +// } - @override - Widget build(BuildContext context) { - return const Scaffold( - body: Center(child: CircularProgressIndicator()), - ); - } -} \ No newline at end of file +// class _SplashPageState extends State { +// @override +// void initState() { +// super.initState(); +// WidgetsBinding.instance.addPostFrameCallback( +// (_) => Navigator.of(context).pushReplacementNamed("/login")); +// } + +// @override +// Widget build(BuildContext context) { +// return const Scaffold( +// body: Center(child: CircularProgressIndicator()), +// ); +// } +// } + +// =================NOT IN USE================================== // \ No newline at end of file diff --git a/lib/supabase/supabase_manager.dart b/lib/supabase/supabase_manager.dart deleted file mode 100644 index 5f3cc5c..0000000 --- a/lib/supabase/supabase_manager.dart +++ /dev/null @@ -1,49 +0,0 @@ -// import 'package:flutter/material.dart'; -// import 'package:supabase/supabase.dart'; -// import 'package:justsharelah_v1/core/toast.dart'; - -// const String supabaseUrl = "your supabase url goes here "; -// const String token = -// "your supabase token goes here"; - -// class SupabaseManager { -// final client = SupabaseClient(supabaseUrl, token); - - -// Future signUpUser(context, {String? email, String? password}) async { -// debugPrint("email:$email password:$password"); -// final result = await client.auth.signUp(email!, password!); - -// debugPrint(result.data!.toJson().toString()); - -// if (result.data != null) { -// showToastMessage('Registration Success', isError: false); -// Navigator.pushReplacementNamed(context, 'login'); -// showToastMessage('Success', isError: false); -// } else if (result.error?.message != null) { -// showToastMessage('Error:${result.error!.message.toString()}', -// isError: true); -// } -// } - -// Future signInUser(context, {String? email, String? password}) async { -// debugPrint("email:$email password:$password"); -// final result = await client.auth.signIn(email: email!, password: password!); -// debugPrint(result.data!.toJson().toString()); - -// if (result.data != null) { -// showToastMessage('Login Success', isError: false); -// Navigator.pushReplacementNamed(context, '/home'); -// showToastMessage('Success', isError: false); -// } else if (result.error?.message != null) { -// showToastMessage('Error:${result.error!.message.toString()}', -// isError: true); -// } -// } - - -// Future logout (context)async{ -// await client.auth.signOut(); -// Navigator.pushReplacementNamed(context, 'login'); -// } -// } \ No newline at end of file diff --git a/lib/apptheme.dart b/lib/utils/apptheme.dart similarity index 100% rename from lib/apptheme.dart rename to lib/utils/apptheme.dart diff --git a/lib/const_templates.dart b/lib/utils/const_templates.dart similarity index 100% rename from lib/const_templates.dart rename to lib/utils/const_templates.dart diff --git a/lib/utils/constants.dart b/lib/utils/constants.dart index 6161705..3f64e74 100644 --- a/lib/utils/constants.dart +++ b/lib/utils/constants.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:supabase_flutter/supabase_flutter.dart'; -final supabase = Supabase.instance.client; extension ShowSnackBar on BuildContext { void showSnackBar({ diff --git a/lib/utils/form_validation.dart b/lib/utils/form_validation.dart new file mode 100644 index 0000000..2884fbc --- /dev/null +++ b/lib/utils/form_validation.dart @@ -0,0 +1,23 @@ +//TODO: USE FLUTTER VALIDATORS PACKAGE + +import 'package:email_validator/email_validator.dart'; + +class FormValidation { + static String? formFieldEmpty(String? text) { + return text!.isEmpty ? "This field cannot be empty" : null; + } + + static String? enforceNumOfChars(String? text, int numOfChars) { + return text!.length < numOfChars + ? "This field must have at least $numOfChars characters" + : null; + } + + static String? validEmail(String? email) { + return email!.isEmpty + ? "This field cannot be empty" + : !EmailValidator.validate(email) + ? "Please enter a valid email" + : null; + } +} diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 766b5cf..67246ea 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,11 +5,15 @@ import FlutterMacOS import Foundation +import firebase_auth +import firebase_core import path_provider_macos import shared_preferences_macos import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin")) + FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) diff --git a/macos/firebase_app_id_file.json b/macos/firebase_app_id_file.json new file mode 100644 index 0000000..af86760 --- /dev/null +++ b/macos/firebase_app_id_file.json @@ -0,0 +1,7 @@ +{ + "file_generated_by": "FlutterFire CLI", + "purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory", + "GOOGLE_APP_ID": "1:10879165640:ios:f463674769a076dadff1fd", + "FIREBASE_PROJECT_ID": "justsharelah-6dca5", + "GCM_SENDER_ID": "10879165640" +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 938b094..96eca39 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -57,6 +57,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.4" + email_validator: + dependency: "direct main" + description: + name: email_validator + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" fake_async: dependency: transitive description: @@ -78,6 +85,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.1.2" + firebase_auth: + dependency: "direct main" + description: + name: firebase_auth + url: "https://pub.dartlang.org" + source: hosted + version: "3.3.20" + firebase_auth_platform_interface: + dependency: transitive + description: + name: firebase_auth_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "6.2.8" + firebase_auth_web: + dependency: transitive + description: + name: firebase_auth_web + url: "https://pub.dartlang.org" + source: hosted + version: "3.3.17" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + url: "https://pub.dartlang.org" + source: hosted + version: "1.18.0" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "4.4.1" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.6.5" flutter: dependency: "direct main" description: flutter @@ -128,6 +177,41 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.1" + google_sign_in: + dependency: "direct main" + description: + name: google_sign_in + url: "https://pub.dartlang.org" + source: hosted + version: "5.3.3" + google_sign_in_android: + dependency: transitive + description: + name: google_sign_in_android + url: "https://pub.dartlang.org" + source: hosted + version: "5.2.8" + google_sign_in_ios: + dependency: transitive + description: + name: google_sign_in_ios + url: "https://pub.dartlang.org" + source: hosted + version: "5.3.1" + google_sign_in_platform_interface: + dependency: transitive + description: + name: google_sign_in_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.3" + google_sign_in_web: + dependency: transitive + description: + name: google_sign_in_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.10.1+3" gotrue: dependency: transitive description: @@ -163,6 +247,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.0.1" + intl: + dependency: transitive + description: + name: intl + url: "https://pub.dartlang.org" + source: hosted + version: "0.17.0" js: dependency: transitive description: @@ -303,6 +394,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.2.4" + quiver: + dependency: transitive + description: + name: quiver + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" realtime_client: dependency: transitive description: @@ -525,6 +623,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.1" + uuid: + dependency: "direct main" + description: + name: uuid + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.6" vector_math: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 6b84699..b04fa9b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,6 +40,11 @@ dependencies: google_fonts: ^3.0.1 material_design_icons_flutter: ^5.0.6595 font_awesome_flutter: ^10.1.0 + uuid: ^3.0.6 + firebase_core: ^1.18.0 + firebase_auth: ^3.3.20 + google_sign_in: ^5.3.3 + email_validator: ^2.0.1 dev_dependencies: flutter_test: