diff --git a/lib/firebase_options.dart b/lib/firebase_options.dart new file mode 100644 index 0000000..e51c0a0 --- /dev/null +++ b/lib/firebase_options.dart @@ -0,0 +1,60 @@ +// File generated by FlutterFire CLI. +// ignore_for_file: lines_longer_than_80_chars +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'; +/// // ... +/// await Firebase.initializeApp( +/// options: DefaultFirebaseOptions.currentPlatform, +/// ); +/// ``` +class DefaultFirebaseOptions { + static FirebaseOptions get currentPlatform { + if (kIsWeb) { + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for web - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + } + // ignore: missing_enum_constant_in_switch + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return android; + case TargetPlatform.iOS: + return ios; + case TargetPlatform.macOS: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for macos - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + } + + throw UnsupportedError( + 'DefaultFirebaseOptions are not supported for this platform.', + ); + } + + static const FirebaseOptions android = FirebaseOptions( + apiKey: 'AIzaSyAmUEAR1SB7bf29XoGNpOExo_GWoNl68J8', + appId: '1:903921644523:android:8b1be795cfa3b71a079fae', + messagingSenderId: '903921644523', + projectId: 'leg-barkr', + storageBucket: 'leg-barkr.appspot.com', + ); + + static const FirebaseOptions ios = FirebaseOptions( + apiKey: 'AIzaSyA6haaqDGLGt5gYLc_z1r0P-jWl0bF3Xlc', + appId: '1:903921644523:ios:9294b2d611ff71fc079fae', + messagingSenderId: '903921644523', + projectId: 'leg-barkr', + storageBucket: 'leg-barkr.appspot.com', + iosClientId: '903921644523-cq15mvp7kj64spro7ugkh781kvp4bm42.apps.googleusercontent.com', + iosBundleId: 'com.legbarkr.app', + ); +} diff --git a/lib/home.dart b/lib/home.dart index b15d7c1..7599e0c 100644 --- a/lib/home.dart +++ b/lib/home.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:leg_barkr_app/view/auth/register_form.dart'; +import 'package:firebase_auth/firebase_auth.dart'; import 'package:leg_barkr_app/view/metrics/metrics_page.dart'; import 'package:leg_barkr_app/view/steps/steps_page.dart'; import 'package:leg_barkr_app/view/map_page.dart'; @@ -16,6 +16,16 @@ class _HomeScreenState extends State { int _page = 0; PageController _pageController = PageController(); + _HomeScreenState(){ + FirebaseAuth.instance + .authStateChanges() + .listen((User? user) { + if (user == null) { + Navigator.pushNamed(context, "/login"); + } + }); + } + void onBottomBarPressed(int page) { setState(() { _page = page; @@ -30,8 +40,7 @@ class _HomeScreenState extends State { body: PageView( controller: _pageController, children: const [ - RegisterForm(), // Purely for testing purposes. - //MetricsPage(), + MetricsPage(), StepsPage(), MapPage(), SettingsPage() diff --git a/lib/main.dart b/lib/main.dart index 6a0194c..e872c27 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,10 +1,18 @@ +import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:leg_barkr_app/home.dart'; import 'package:flutter/services.dart'; +import 'package:leg_barkr_app/view/auth/login_form.dart'; +import 'package:leg_barkr_app/view/auth/register_form.dart'; +import 'firebase_options.dart'; -void main() { +void main() async { SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(statusBarColor: Colors.black12)); - runApp(const Main()); + WidgetsFlutterBinding.ensureInitialized(); + await Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ); + runApp(Main()); } class Main extends StatelessWidget { @@ -14,7 +22,13 @@ class Main extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( theme: ThemeData.light(), - home: HomeScreen() + //home: HomeScreen(), + initialRoute: '/', + routes: { + '/': (context) => const HomeScreen(), + '/login': (context) => const LoginForm(), + '/register': (context) => const RegisterForm() + } ); } } diff --git a/lib/view/auth/login_form.dart b/lib/view/auth/login_form.dart new file mode 100644 index 0000000..baa7e9a --- /dev/null +++ b/lib/view/auth/login_form.dart @@ -0,0 +1,150 @@ +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; + + +class LoginForm extends StatefulWidget { + const LoginForm({Key? key}) : super(key: key); + + @override + _LoginFormState createState() => _LoginFormState(); +} + +class _LoginFormState extends State { + final GlobalKey _formKey = GlobalKey(); + late String _email, _password; + bool _loggingIn = false; + + void attemptLogin(){ + final form = _formKey.currentState; + if (form!.validate()) { + form.save(); + setState(() { _loggingIn = true; }); + loginUser(); + } else { + setState(() { _loggingIn = false; }); + } + } + + Future loginUser() async { + try { + await FirebaseAuth.instance.signInWithEmailAndPassword(email: _email, password: _password); + Navigator.pushNamed(context, "/"); + } on FirebaseAuthException catch (e) { + if (e.code == 'user-not-found') { + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Invalid email"))); + setState(() { _loggingIn = false; }); + } else if (e.code == 'wrong-password') { + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Incorrect password"))); + setState(() { _loggingIn = false; }); + } + } + } + + @override + Widget build(BuildContext context) { + final TextFormField emailInput = TextFormField( + autofocus: false, + cursorColor: Colors.green, + decoration: const InputDecoration( + border: OutlineInputBorder(), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.green, + width: 2 + ) + ), + hintText: 'Email', + //labelStyle: TextStyle(color: Colors.green), + ), + validator: (value) => value!.isEmpty ? "Please enter email" : null, + onSaved: (value) => _email = value!, + ); + + final TextFormField passwordInput = TextFormField( + autofocus: false, + obscureText: true, + cursorColor: Colors.green, + decoration: const InputDecoration( + border: OutlineInputBorder(), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.green, + width: 2 + ) + ), + hintText: 'Password', + //labelStyle: TextStyle(color: Colors.green), + ), + validator: (value) => value!.isEmpty ? "Please enter password" : null, + onSaved: (value) => _password = value!, + ); + + final Container loading = Container( + alignment: Alignment.center, + child: CircularProgressIndicator( + backgroundColor: Colors.green, + color: Colors.green, + ), + ); + + final Container loginBtn = Container( + width: double.infinity, + height: 50, + child: ElevatedButton( + onPressed: attemptLogin, + child: Text('Sign In'), + style: ElevatedButton.styleFrom( + alignment: Alignment.center, + primary: Colors.green, + ) + ) + ); + + final Container registerBtn = Container( + width: double.infinity, + height: 50, + child: ElevatedButton( + onPressed: (){ Navigator.pushNamed(context, '/register'); }, + child: Text('No account? Register now!', + style: TextStyle( + color: Colors.black, + fontSize: 15 + ) + ), + style: ElevatedButton.styleFrom( + alignment: Alignment.center, + primary: Colors.white, + side: BorderSide( + color: Colors.green, + width: 2 + ) + ) + ) + ); + + return Scaffold( + appBar: null, + body: Center( + child: SingleChildScrollView( + child: Form( + key: _formKey, + child:Container( + padding: EdgeInsets.all(10), + child: Column( + children: [ + emailInput, + SizedBox(height: 20), + passwordInput, + SizedBox(height: 20), + _loggingIn ? loading : loginBtn, + SizedBox(height: 20), + _loggingIn ? Text("") : registerBtn + ] + ) + ) + ), + ) + ) + ); + } +} \ No newline at end of file diff --git a/lib/view/auth/register_form.dart b/lib/view/auth/register_form.dart index 6c5cce2..be2f311 100644 --- a/lib/view/auth/register_form.dart +++ b/lib/view/auth/register_form.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'package:leg_barkr_app/home.dart'; import 'package:leg_barkr_app/utils/endpoints.dart' as Endpoints; +import 'package:leg_barkr_app/view/auth/login_form.dart'; class RegisterForm extends StatefulWidget { const RegisterForm({Key? key}) : super(key: key); @@ -47,7 +48,7 @@ class _RegisterFormState extends State { }), ); if (response.statusCode == 201){ - Navigator.push(context, MaterialPageRoute(builder: (context) => HomeScreen())); + Navigator.push(context, MaterialPageRoute(builder: (context) => LoginForm())); } else if (response.statusCode == 400){ ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Fields missing!"))); } else if (response.statusCode == 409){ @@ -204,8 +205,9 @@ class _RegisterFormState extends State { ); - return SafeArea( - child: SingleChildScrollView( + return Scaffold( + appBar: null, + body: SingleChildScrollView( child: Form( key: _formKey, child:Container( diff --git a/pubspec.lock b/pubspec.lock index 8b24093..b95cc4d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -78,6 +78,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + firebase_auth: + dependency: "direct main" + description: + name: firebase_auth + url: "https://pub.dartlang.org" + source: hosted + version: "3.3.7" + firebase_auth_platform_interface: + dependency: transitive + description: + name: firebase_auth_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.11" + firebase_auth_web: + dependency: transitive + description: + name: firebase_auth_web + url: "https://pub.dartlang.org" + source: hosted + version: "3.3.7" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + url: "https://pub.dartlang.org" + source: hosted + version: "1.12.0" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "4.2.4" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.4" flutter: dependency: "direct main" description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 743abb7..6e6afc0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -39,6 +39,8 @@ dependencies: charts_flutter: ^0.12.0 syncfusion_flutter_gauges: ^19.4.50 http: ^0.13.4 + firebase_core: ^1.12.0 + firebase_auth: ^3.3.7 dev_dependencies: