diff --git a/.gitignore b/.gitignore index 2ddde2a..cba8b95 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,5 @@ !**/ios/**/default.pbxuser !**/ios/**/default.perspectivev3 !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages +.flutter-plugins-dependencies +.gitignore diff --git a/lib/Login/signin.dart b/lib/Login/signin.dart deleted file mode 100644 index 669396e..0000000 --- a/lib/Login/signin.dart +++ /dev/null @@ -1,250 +0,0 @@ -import 'package:firebase_auth/firebase_auth.dart'; -import 'dart:async'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:peer_learning/dashboard.dart'; -import 'package:peer_learning/Login/signup.dart'; -import 'package:google_sign_in/google_sign_in.dart'; -import 'package:modal_progress_hud/modal_progress_hud.dart'; - -final FirebaseAuth _auth = FirebaseAuth.instance; -final GoogleSignIn _googleSignIn = GoogleSignIn(); - -class SigninPage extends StatefulWidget { - static String tag = 'login'; - - @override - State createState() { - return _SigninPageState(); - } -} - -class _SigninPageState extends State - with SingleTickerProviderStateMixin { - String _status; - - dynamic user; - - AnimationController controller; - Animation animation; - - void _signInAnon() async { - FirebaseUser user = (await _auth.signInAnonymously()).user; - if (user != null && user.isAnonymous == true) { - setState(() { - _status = "Signed in Anonymously"; - }); - } else { - setState(() { - _status = "Sign in failed"; - }); - } - } - - void _signOut() async { - await _auth.signOut(); - setState(() { - _status = "Signed Out"; - }); - } - - @override - void initState() { - super.initState(); - - _status = "Not Authenticated"; - - controller = - AnimationController(duration: Duration(seconds: 1), vsync: this); - animation = ColorTween(begin: Colors.blueGrey, end: Colors.white) - .animate(controller); - controller.forward(); - - controller.addListener(() { - setState(() {}); - }); - } - - @override - void dispose() { - super.dispose(); - controller.dispose(); - } - - final GlobalKey _formKey = GlobalKey(); - final TextEditingController _email = new TextEditingController(); - final TextEditingController _password = new TextEditingController(); - - bool _autoValidate = false; - bool _loadingVisible = false; - - @override - Widget build(BuildContext context) { - final Map args = ModalRoute.of(context).settings.arguments; - final _width = MediaQuery.of(context).size.width; - final _height = MediaQuery.of(context).size.height; - - return Scaffold( - appBar: AppBar( - centerTitle: true, - elevation: 0, - backgroundColor: Colors.blue, - title: Text( - 'Sign In', - style: TextStyle(fontSize: 30.0), - ), - ), - body: ModalProgressHUD( - inAsyncCall: _loadingVisible, - child: Center( - child: Container( - alignment: Alignment.center, - child: Form( - key: _formKey, - autovalidate: _autoValidate, - child: ListView( - children: [ - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Container( - child: Hero( - tag: 'logo', - child: Image.asset('assets/images/logo.png')), - height: _width < _height - ? (_width / 4) * controller.value - : (_height / 4) * controller.value, -// height: 150 * controller.value, - width: 150 * controller.value, - ), - SizedBox( - height: _width < _height ? _width / 20 : _height / 20, - ), - Padding( - padding: EdgeInsets.only( - left: 22, right: 22, top: 16, bottom: 8), - child: TextFormField( - autofocus: false, - controller: _email, -// validator: Validator.validateEmail, - keyboardType: TextInputType.emailAddress, - style: TextStyle(fontSize: 18), - decoration: InputDecoration( - labelText: 'Email', - ), - ), - ), - Padding( - padding: EdgeInsets.only( - left: 22, right: 22, top: 8, bottom: 8), - child: TextFormField( - autofocus: false, - controller: _password, -// validator: Validator.validatePassword, - obscureText: true, - style: TextStyle(fontSize: 18), - keyboardType: TextInputType.text, - decoration: InputDecoration( - labelText: 'Password', - ), - ), - ), - SizedBox( - height: _width < _height ? _width / 20 : _height / 20, - ), - Padding( - padding: EdgeInsets.only( - left: 22, right: 22, top: 16, bottom: 8), - child: Container( - color: Colors.transparent, - width: MediaQuery.of(context).size.width, - height: 50, - child: FlatButton( - shape: new RoundedRectangleBorder( -// borderRadius: new BorderRadius.circular(30.0), - ), - onPressed: () async { - _changeLoadingVisible(); - try { - user = await _auth.signInWithEmailAndPassword( - email: _email.text, - password: _password.text); - } catch (e) { - print(e); - _changeLoadingVisible(); - return showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: Text("Sign in failed!"), - content: Text( - "Your email/username is incorrect. Please check again and retry."), - ); - }); - } - _changeLoadingVisible(); - if (user != null) { - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) => Dashboard(), - ), - ); - } - - /* Anonymous signIn - try { - _signInAnon(); - - if (_status == "Signed in Anonymously") {} - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => Dashboard())); - } catch (e) { - print(e); - } - - */ - }, - color: Colors.blue, - child: Text( - "Sign In", - style: TextStyle( - color: Colors.white, - fontFamily: 'Raleway', - fontSize: 22.0, - ), - ), - ), - ), - ), - Text("Create an account:"), - FlatButton( - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => SignUpPage())); - }, - child: Text("sign up"), - ) - ], - ), - ], - ), - ), - ), - ), - )); - } - - Future _changeLoadingVisible() async { - setState(() { - _loadingVisible = !_loadingVisible; - }); - } -} diff --git a/lib/Login/signup.dart b/lib/Login/signup.dart deleted file mode 100644 index 74a39f1..0000000 --- a/lib/Login/signup.dart +++ /dev/null @@ -1,246 +0,0 @@ -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:modal_progress_hud/modal_progress_hud.dart'; - -import '../dashboard.dart'; - -class SignUpPage extends StatefulWidget { - @override - _SignUpPageState createState() => _SignUpPageState(); -} - -class _SignUpPageState extends State - with SingleTickerProviderStateMixin { - final _auth = FirebaseAuth.instance; - - dynamic newUser; - - AnimationController controller; - Animation animation; - - @override - void initState() { - super.initState(); - - controller = - AnimationController(duration: Duration(seconds: 1), vsync: this); - animation = ColorTween(begin: Colors.blueGrey, end: Colors.white) - .animate(controller); - controller.forward(); - - controller.addListener(() { - setState(() {}); - print(animation.value); - }); - } - - @override - void dispose() { - super.dispose(); - controller.dispose(); - } - - dynamic myController = TextEditingController(); - bool isSwitched = false; - final GlobalKey _formKey = GlobalKey(); - final TextEditingController _userName = TextEditingController(); - final TextEditingController _email = new TextEditingController(); - final TextEditingController _password = new TextEditingController(); - - bool _autoValidate = false; - bool _loadingVisible = false; - String _currentValue = "Mentor or Mentee"; - - String _currentProg = "Programming Language"; - - @override - Widget build(BuildContext context) { - final _width = MediaQuery.of(context).size.width; - final _height = MediaQuery.of(context).size.height; - - return Scaffold( - appBar: AppBar( - centerTitle: true, - title: Text( - "Sign Up", - style: TextStyle(fontSize: 30.0), - ), - ), - backgroundColor: Colors.white, - body: ModalProgressHUD( - inAsyncCall: _loadingVisible, - child: Container( - child: SafeArea( - child: ListView( - children: [ - Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Hero( - tag: 'logo', - child: Image.asset('assets/images/logo.png')), - height: _width < _height - ? (_width / 4) * controller.value - : (_height / 4) * controller.value, - width: 100 * controller.value, - ), - SizedBox( - height: _width < _height ? _width / 20 : _height / 20, - ), - Padding( - padding: const EdgeInsets.only( - left: 22, right: 22, top: 16, bottom: 8), - child: TextFormField( - autofocus: false, - controller: _userName, -// validator: Validator.validateEmail, - keyboardType: TextInputType.text, - style: TextStyle(fontSize: 18), - decoration: InputDecoration( - labelText: 'Username', - ), - ), - ), - Padding( - padding: const EdgeInsets.only( - left: 22, right: 22, top: 16, bottom: 8), - child: TextFormField( - autofocus: false, - controller: _email, -// validator: Validator.validateEmail, - keyboardType: TextInputType.emailAddress, - style: TextStyle(fontSize: 18), - decoration: InputDecoration( - labelText: 'Email', - ), - ), - ), //textArea for email - Padding( - padding: const EdgeInsets.only( - left: 22, right: 22, top: 16, bottom: 8), - child: TextFormField( - autofocus: false, - controller: _password, -// validator: Validator.validatePassword, - obscureText: true, - style: TextStyle(fontSize: 18), - keyboardType: TextInputType.text, - decoration: InputDecoration( - labelText: 'Password', - ), -// onChanged: getPassword(myController.text), - ), - ), // - // textArea for password - DropdownButton( - hint: Text(_currentValue), - items: [ - "Mentor", - 'Mentee', - ].map((String value) { - return new DropdownMenuItem( - value: value, - child: new Text(value), - ); - }).toList(), - onChanged: (value) { - setState(() { - _currentValue = value; - }); - }, - ), - DropdownButton( - hint: Text(_currentProg), - items: [ - "C", - 'C++', - "Dart", - 'Kotlin', - "Python", - "JavaScript", - ].map((String value) { - return new DropdownMenuItem( - value: value, - child: new Text(value), - ); - }).toList(), - onChanged: (value) { - setState(() { - _currentProg = value; - }); - }, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text("male"), - Switch( - value: isSwitched, - onChanged: (value) { - setState(() { - isSwitched = value; - }); - }, - activeTrackColor: Colors.lightGreenAccent, - //activeColor: Colors.green, - ), - Text('female'), - ], - ), - SizedBox( - height: _width < _height ? _width / 20 : _height / 20, - ), - RaisedButton( - onPressed: () async { - _changeLoadingVisible(); - try { - newUser = await _auth.createUserWithEmailAndPassword( - email: _email.text, password: _password.text); - } catch (e) { - print(e); - _changeLoadingVisible(); - return showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: Text("Sign up failed!"), - content: Text( - "Username already taken or You already got an account."), - ); - }); - } - _changeLoadingVisible(); - if (newUser != null) { - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) => - Dashboard(username: _userName.text), - ), - ); - } - }, // upon login we navigate to the dashboard - child: Text("Sign Up"), - ), - SizedBox( - height: _width < _height ? _width / 20 : _height / 20, - ), - ], - ), - ], - ), - ), - ), - ), - resizeToAvoidBottomInset: false, - ); - } - - Future _changeLoadingVisible() async { - setState(() { - _loadingVisible = !_loadingVisible; - }); - } -} diff --git a/lib/UI/LoadingScreen.dart b/lib/UI/LoadingScreen.dart new file mode 100644 index 0000000..f0e57e9 --- /dev/null +++ b/lib/UI/LoadingScreen.dart @@ -0,0 +1,58 @@ +import 'package:splashscreen/splashscreen.dart'; + +import 'package:flutter/material.dart'; +import 'package:peer_learning/UI/signin.dart'; + +class LoadingScreen extends StatefulWidget { + @override + _LoadingScreenState createState() => new _LoadingScreenState(); +} + +class _LoadingScreenState extends State + with SingleTickerProviderStateMixin { + AnimationController controller; + Animation animation; + + @override + void initState() { + super.initState(); + + controller = + AnimationController(duration: Duration(seconds: 1), vsync: this); + animation = ColorTween(begin: Colors.blueGrey, end: Colors.white) + .animate(controller); + controller.forward(); + + controller.addListener(() { + setState(() {}); + }); + } + + @override + Widget build(BuildContext context) { + return Hero( + tag: "logo", + child: SplashScreen( + seconds: 2, + navigateAfterSeconds: SigninPage(), + title: Text( + 'Welcome to Peer Learning', + style: TextStyle( + fontWeight: FontWeight.bold, fontSize: 25.0 * controller.value), + ), + image: Image.asset( + 'assets/images/logo.png', + ), + gradientBackground: new LinearGradient( + colors: [Colors.cyan, Colors.blue], + begin: Alignment.topLeft, + end: Alignment.bottomRight), + backgroundColor: Colors.white, + styleTextUnderTheLoader: TextStyle(), + photoSize: 70.0 * controller.value, + onClick: () => {}, + loaderColor: Colors.grey, + ), + ); + } +} diff --git a/lib/UI/chat_forrum.dart b/lib/UI/chat_forrum.dart new file mode 100644 index 0000000..59603a0 --- /dev/null +++ b/lib/UI/chat_forrum.dart @@ -0,0 +1,200 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:peer_learning/components/constants.dart'; +import 'package:peer_learning/models/chat_model.dart'; +import 'package:scoped_model/scoped_model.dart'; + +final _firestore = Firestore.instance; +FirebaseUser loggedUser; + +class ChatForrum extends StatefulWidget { + @override + _ChatForrumState createState() => _ChatForrumState(); +} + +class _ChatForrumState extends State { + final _auth = FirebaseAuth.instance; + + final messageTextController = TextEditingController(); + String messageText; + + @override + void initState() { + super.initState(); + getRegisterUser(); + } + + void getRegisterUser() async { + try { + final newUser = await _auth.currentUser(); + if (newUser != null) { + loggedUser = newUser; + print(loggedUser.email); + } + } catch (e) { + print(e); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: null, + actions: [ + IconButton( + icon: Icon(Icons.close), + onPressed: () { + _auth.signOut(); + Navigator.pop(context); + // getMessageStream(); + }), + ], + title: Text('♨Community'), + backgroundColor: Colors.lightBlueAccent, + ), + body: SafeArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + MessageStream(), + Container( + decoration: kMessageContainerDecoration, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: TextField( + controller: messageTextController, + onChanged: (value) { + messageText = value; + }, + decoration: kMessageTextFieldDecoration, + ), + ), + FlatButton( + onPressed: () { + if (messageText != null && messageText != '') { + messageTextController.clear(); + _firestore.collection("messages").add({ + "text": messageText, + "sender": loggedUser.email, + }); + messageText = ''; + } + }, + child: Icon( + Icons.send, + color: Colors.lightBlueAccent, + ), +// child: Text( +// 'Send', +// style: kSendButtonTextStyle, +// ), + ), + ], + ), + ), + ], + ), + ), + ); + } +} + +class MessageStream extends StatelessWidget { + @override + Widget build(BuildContext context) { + return StreamBuilder( + stream: _firestore.collection("messages").snapshots(), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Center( + child: CircularProgressIndicator( + backgroundColor: Colors.lightBlueAccent, + ), + ); + } + final messages = snapshot.data.documents; + List messageBubbleList = []; + for (var message in messages) { + String messageText = message.data['text']; + String messageSender = message.data['sender']; + + final currentUser = loggedUser.email; + + if (currentUser == messageSender) { + // + } + dynamic messageBubble = MessageBubble( + message: messageText, + sender: messageSender, + isMe: messageSender == currentUser, + ); + messageBubbleList.add(messageBubble); + } + + return Expanded( + child: ListView( + reverse: true, + padding: EdgeInsets.symmetric(horizontal: 10, vertical: 20), + children: messageBubbleList, + ), + ); + }, + ); + } +} + +class MessageBubble extends StatelessWidget { + MessageBubble({this.message, this.sender, this.isMe}); + final String message, sender; + final bool isMe; + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: + isMe ? CrossAxisAlignment.end : CrossAxisAlignment.start, + children: [ + Text( + sender, + style: TextStyle( + color: Colors.black54, + fontSize: 12, + ), + ), + Material( + borderRadius: isMe + ? BorderRadius.only( + topLeft: Radius.circular(30), + bottomLeft: Radius.circular(30), + bottomRight: Radius.circular(30)) + : BorderRadius.only( + topRight: Radius.circular(30), + bottomLeft: Radius.circular(30), + bottomRight: Radius.circular(30)), + elevation: 5.0, + color: isMe ? Colors.lightBlueAccent : Colors.white, + child: Padding( + padding: EdgeInsets.all(10.0), + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 3.0, vertical: 7.0), + child: Text( + message, + style: TextStyle( + fontSize: 20.0, + color: isMe ? Colors.white : Colors.black), + ), + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/coding_stats.dart b/lib/UI/coding_stats.dart similarity index 100% rename from lib/screens/coding_stats.dart rename to lib/UI/coding_stats.dart diff --git a/lib/UI/dashboard.dart b/lib/UI/dashboard.dart new file mode 100644 index 0000000..f766b19 --- /dev/null +++ b/lib/UI/dashboard.dart @@ -0,0 +1,139 @@ +import 'package:bottom_navy_bar/bottom_navy_bar.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:peer_learning/UI/chat_forrum.dart'; +import 'signup.dart'; +import 'signin.dart'; +import 'gender_stats.dart'; +import 'coding_stats.dart'; +import 'find_mentor.dart'; +import 'profile.dart'; + +FirebaseUser loggedUser; + +class Dashboard extends StatefulWidget { + final String username; + Dashboard({this.username}); + @override + _DashboardState createState() => _DashboardState(); +} + +class _DashboardState extends State { + final _auth = FirebaseAuth.instance; + + @override + void initState() { + getRegisteredUser(); + super.initState(); + } + + void getRegisteredUser() async { + try { + final newUser = await _auth.currentUser(); + if (newUser != null) { + loggedUser = newUser; + print(loggedUser.email); + } + } catch (e) { + print(e); + } + } + + var _selectedIndex = 0; + final _pageController = PageController(); + + var currentPage = Container( + child: SafeArea( + child: Center( + child: Column( + children: [ + Text("Test"), + ], + ), + ), + ), + ); +// final navBotton = Destination(title: "test", icon: Icons.home, color: Colors.lightBlueAccent) + + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: () async => true, + child: Scaffold( +// bottomNavigationBar: allDestinations, + body: new Center( + child: _getWidget(), + ), + bottomNavigationBar: BottomNavyBar( + selectedIndex: _selectedIndex, + showElevation: true, // use this to remove appBar's elevation + onItemSelected: (index) => setState(() { + _selectedIndex = index; + + // _pageController.animateToPage(index, duration: Duration(milliseconds: 300), curve: Curves.ease); + }), + items: [ + BottomNavyBarItem( + icon: Icon(Icons.person), + title: Text('Chat Area'), + activeColor: Colors.red, + ), + BottomNavyBarItem( + icon: Icon(Icons.people), + title: Text('Gender Stats'), + activeColor: Colors.purpleAccent, + ), + BottomNavyBarItem( + icon: Icon(Icons.code), + title: Text('Coding Stats'), + activeColor: Colors.pink), + BottomNavyBarItem( + icon: Icon(Icons.gps_fixed), + title: Text('Profile'), + activeColor: Colors.blue), + ], + ), + resizeToAvoidBottomInset: false, + ), + ); + } + + Widget _getWidget() { + switch (_selectedIndex) { + case 0: + return Container( + child: ChatForrum(), + ); + break; + case 1: + return Container( + child: GenderStats(), + ); + break; + case 2: + return Container( + child: CodingStats(), + ); + break; + default: + return Container( + child: Profile(), + ); + break; + } + } +} + +class Destination { + const Destination(this.title, this.icon, this.color); + final String title; + final IconData icon; + final MaterialColor color; +} + +const List allDestinations = [ + Destination('Recent', Icons.restore, Colors.teal), + Destination('Favorites', Icons.favorite_border, Colors.cyan), + Destination('School', Icons.school, Colors.orange), + Destination('Location', Icons.gps_fixed, Colors.blue) +]; diff --git a/lib/screens/find_mentor.dart b/lib/UI/find_mentor.dart similarity index 97% rename from lib/screens/find_mentor.dart rename to lib/UI/find_mentor.dart index 1887819..a4fd49e 100644 --- a/lib/screens/find_mentor.dart +++ b/lib/UI/find_mentor.dart @@ -1,8 +1,9 @@ import 'package:flutter/material.dart'; import 'package:loader_search_bar/loader_search_bar.dart'; +import 'package:peer_learning/UI/chat_forrum.dart'; import 'package:peer_learning/components/mentorProfileCard.dart'; -import '../dashboard.dart'; +import 'dashboard.dart'; class FindMentor extends StatefulWidget { @override @@ -49,7 +50,7 @@ class FindMentorState extends State { // List _getItemListForQuery(String query) { ... } // Widget _buildItemWidget(Item item) { ... } ), - + body: Center( child: Padding( padding: const EdgeInsets.only( @@ -131,7 +132,7 @@ class FindMentorState extends State { RaisedButton( onPressed: () { setState(() { - Navigator.push( + Navigator.pushReplacement( context, MaterialPageRoute( builder: (context) => Dashboard(), @@ -147,7 +148,6 @@ class FindMentorState extends State { ], ), ], - ), ), ), diff --git a/lib/screens/gender_stats.dart b/lib/UI/gender_stats.dart similarity index 100% rename from lib/screens/gender_stats.dart rename to lib/UI/gender_stats.dart diff --git a/lib/screens/profile.dart b/lib/UI/profile.dart similarity index 99% rename from lib/screens/profile.dart rename to lib/UI/profile.dart index 3f1f9ff..9f1fd33 100644 --- a/lib/screens/profile.dart +++ b/lib/UI/profile.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'dart:ui'; +import 'package:peer_learning/UI/signin.dart'; + class Profile extends StatefulWidget { @override State createState() { @@ -131,7 +133,6 @@ class _MyHomePageState extends State { ], ), ], - ), )) ], diff --git a/lib/UI/signin.dart b/lib/UI/signin.dart new file mode 100644 index 0000000..2b4e07f --- /dev/null +++ b/lib/UI/signin.dart @@ -0,0 +1,201 @@ +import 'package:firebase_auth/firebase_auth.dart'; +import 'dart:async'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:peer_learning/UI/chat_forrum.dart'; +import 'package:peer_learning/UI/dashboard.dart'; +import 'package:peer_learning/UI/signup.dart'; +import 'package:google_sign_in/google_sign_in.dart'; +import 'package:modal_progress_hud/modal_progress_hud.dart'; +import 'package:peer_learning/models/LoginModel.dart'; +import 'package:scoped_model/scoped_model.dart'; +import 'package:flutter/animation.dart'; + +class SigninPage extends StatefulWidget { + static String tag = 'login'; + + @override + State createState() { + return _SigninPageState(); + } +} + +class _SigninPageState extends State + with SingleTickerProviderStateMixin { + AnimationController controller; + Animation animation; + + dynamic customAlert; + + @override + void initState() { + super.initState(); + + controller = + AnimationController(duration: Duration(seconds: 1), vsync: this); + loginModel.animate(controller); + } + + @override + void dispose() { + super.dispose(); + controller.dispose(); + } + + final LoginModel loginModel = LoginModel(); + + @override + Widget build(BuildContext context) { + final Map args = ModalRoute.of(context).settings.arguments; + final _width = MediaQuery.of(context).size.width; + final _height = MediaQuery.of(context).size.height; + + return ScopedModel( + model: loginModel, + child: Scaffold( + appBar: AppBar( + centerTitle: true, + elevation: 0, + backgroundColor: Colors.blue, + title: Text( + 'Sign In', + style: TextStyle(fontSize: 30.0), + ), + ), + body: ScopedModelDescendant( + builder: (context, child, model) => ModalProgressHUD( + inAsyncCall: model.loadingVisible, + child: Center( + child: Container( + alignment: Alignment.center, + child: Form( + key: model.formKey, + autovalidate: model.autoValidate, + child: ListView( + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Container( + child: Hero( + tag: 'logo', + child: Image.asset('assets/images/logo.png')), + height: _width < _height + ? (_width / 4) * controller.value + : (_height / 4) * controller.value, + width: 150 * controller.value, + ), + SizedBox( + height: + _width < _height ? _width / 20 : _height / 20, + ), + Padding( + padding: EdgeInsets.only( + left: 22, right: 22, top: 16, bottom: 8), + child: TextFormField( + autofocus: false, + controller: model.email, + keyboardType: TextInputType.emailAddress, + style: TextStyle(fontSize: 18), + decoration: InputDecoration( + labelText: 'Email', + ), + ), + ), + Padding( + padding: EdgeInsets.only( + left: 22, right: 22, top: 8, bottom: 8), + child: TextFormField( + autofocus: false, + controller: model.password, + obscureText: true, + style: TextStyle(fontSize: 18), + keyboardType: TextInputType.text, + decoration: InputDecoration( + labelText: 'Password', + ), + ), + ), + SizedBox( + height: + _width < _height ? _width / 20 : _height / 20, + ), + Padding( + padding: EdgeInsets.only( + left: 22, right: 22, top: 16, bottom: 8), + child: Container( + color: Colors.transparent, + width: MediaQuery.of(context).size.width, + height: 50, + child: FlatButton( + shape: new RoundedRectangleBorder(), + onPressed: () async { + setState(() { + model.changeLoadingVisible(); + }); + await model.login(context + //context required to create alert if failure + ); + setState(() { + model.changeLoadingVisible(); + }); + if (model.user != null) { + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => Dashboard(), + ), + ); + } + /* Anonymous signIn + try { + _signInAnon(); + + if (_status == "Signed in Anonymously") {} + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => Dashboard())); + } catch (e) { + print(e); + } + + */ + }, + color: Colors.blue, + child: Text( + "Sign In", + style: TextStyle( + color: Colors.white, + fontFamily: 'Raleway', + fontSize: 22.0, + ), + ), + ), + ), + ), + Text("Create an account:"), + FlatButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SignUpPage())); + }, + child: Text("sign up"), + ) + ], + ), + ], + ), + ), + ), + ), + ), + )), + ); + } +} diff --git a/lib/UI/signup.dart b/lib/UI/signup.dart new file mode 100644 index 0000000..37ddfa7 --- /dev/null +++ b/lib/UI/signup.dart @@ -0,0 +1,216 @@ +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:modal_progress_hud/modal_progress_hud.dart'; +import 'package:peer_learning/UI/find_mentor.dart'; +import 'package:peer_learning/models/SignUpModel.dart'; +import 'package:scoped_model/scoped_model.dart'; + +import 'dashboard.dart'; + +class SignUpPage extends StatefulWidget { + @override + _SignUpPageState createState() => _SignUpPageState(); +} + +class _SignUpPageState extends State + with SingleTickerProviderStateMixin { + AnimationController controller; + Animation animation; + dynamic customAlert; + @override + void initState() { + super.initState(); + + controller = + AnimationController(duration: Duration(seconds: 1), vsync: this); + signUpModel.animate(controller); + } + + @override + void dispose() { + super.dispose(); + controller.dispose(); + } + + final SignUpModel signUpModel = SignUpModel(); + @override + Widget build(BuildContext context) { + final _width = MediaQuery.of(context).size.width; + final _height = MediaQuery.of(context).size.height; + + return ScopedModel( + model: signUpModel, + child: Scaffold( + appBar: AppBar( + centerTitle: true, + title: Text( + "Sign Up", + style: TextStyle(fontSize: 30.0), + ), + ), + backgroundColor: Colors.white, + body: ScopedModelDescendant( + builder: (context, child, model) => ModalProgressHUD( + inAsyncCall: model.loadingVisible, + child: Container( + child: SafeArea( + child: ListView( + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + child: Hero( + tag: 'logo', + child: Image.asset('assets/images/logo.png')), + height: _width < _height + ? (_width / 4) * controller.value + : (_height / 4) * controller.value, + width: 200 * controller.value, + ), + SizedBox( + height: _width < _height ? _width / 20 : _height / 20, + ), + Padding( + padding: const EdgeInsets.only( + left: 22, right: 22, top: 16, bottom: 8), + child: TextFormField( + autofocus: false, + controller: model.userName, + keyboardType: TextInputType.text, + style: TextStyle(fontSize: 18), + decoration: InputDecoration( + labelText: 'Username', + ), + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 22, right: 22, top: 16, bottom: 8), + child: Form( + key: model.formKey, + child: TextFormField( + autofocus: false, + controller: model.email, + keyboardType: TextInputType.emailAddress, + style: TextStyle(fontSize: 18), + decoration: InputDecoration( + labelText: 'Email', + ), + ), + ), + ), //textArea for email + Padding( + padding: const EdgeInsets.only( + left: 22, right: 22, top: 16, bottom: 8), + child: TextFormField( + autofocus: false, + controller: model.password, +// validator: Validator.validatePassword, + obscureText: true, + style: TextStyle(fontSize: 18), + keyboardType: TextInputType.text, + decoration: InputDecoration( + labelText: 'Password', + ), +// onChanged: getPassword(myController.text), + ), + ), // + // textArea for password + DropdownButton( + hint: Text(model.currentValue), + items: [ + "Mentor", + 'Mentee', + ].map((String value) { + return new DropdownMenuItem( + value: value, + child: new Text(value), + ); + }).toList(), + onChanged: (value) { + setState(() { + model.currentValue = value; + }); + }, + ), + DropdownButton( + hint: Text(model.currentProg), + items: [ + "C", + 'C++', + "Dart", + 'Kotlin', + "Python", + "JavaScript", + ].map((String value) { + return new DropdownMenuItem( + value: value, + child: new Text(value), + ); + }).toList(), + onChanged: (value) { + setState(() { + model.currentProg = value; + }); + }, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text("male"), + Switch( + value: model.isSwitched, + onChanged: (value) { + setState(() { + model.isSwitched = value; + }); + }, + activeTrackColor: Colors.lightGreenAccent, + //activeColor: Colors.green, + ), + Text('female'), + ], + ), + SizedBox( + height: _width < _height ? _width / 20 : _height / 20, + ), + RaisedButton( + onPressed: () async { + setState(() { + model.changeLoadingVisible(); + }); + await model.signUp( + context //Context require to generate alert if failure + ); + setState(() { + model.changeLoadingVisible(); + }); + if (model.newUser != null) { + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => FindMentor(), + ), + ); + } + }, // upon login we navigate to the dashboard + child: Text("Sign Up"), + ), + SizedBox( + height: _width < _height ? _width / 20 : _height / 20, + ), + ], + ), + ], + ), + ), + ), + ), + ), + resizeToAvoidBottomInset: false, + ), + ); + } +} diff --git a/lib/components/constants.dart b/lib/components/constants.dart index e69de29..dcaca5b 100644 --- a/lib/components/constants.dart +++ b/lib/components/constants.dart @@ -0,0 +1,37 @@ + +import 'package:flutter/material.dart'; + +const kSendButtonTextStyle = TextStyle( + color: Colors.lightBlueAccent, + fontWeight: FontWeight.bold, + fontSize: 18.0, +); + +const kMessageTextFieldDecoration = InputDecoration( + contentPadding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0), + hintText: 'Type your message here...', + border: InputBorder.none, +); + +const kMessageContainerDecoration = BoxDecoration( + border: Border( + top: BorderSide(color: Colors.lightBlueAccent, width: 2.0), + ), +); + +InputDecoration kmyInputDecoration({String text, Color colour}) => + InputDecoration( + hintText: text, + contentPadding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0), + border: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(32.0)), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: colour, width: 1.0), + borderRadius: BorderRadius.all(Radius.circular(32.0)), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: colour, width: 2.0), + borderRadius: BorderRadius.all(Radius.circular(32.0)), + ), + ); diff --git a/lib/dashboard.dart b/lib/dashboard.dart deleted file mode 100644 index e6b42ab..0000000 --- a/lib/dashboard.dart +++ /dev/null @@ -1,112 +0,0 @@ -import 'package:bottom_navy_bar/bottom_navy_bar.dart'; -import 'package:flutter/material.dart'; -import './Login/signup.dart'; -import './Login/signin.dart'; -import './screens/gender_stats.dart'; -import './screens/coding_stats.dart'; -import './screens/find_mentor.dart'; -import './screens/profile.dart'; - -class Dashboard extends StatefulWidget { - final String username; - Dashboard({this.username}); - @override - _DashboardState createState() => _DashboardState(); -} - -class _DashboardState extends State { - var _selectedIndex = 0; - final _pageController = PageController(); - - var currentPage = Container( - child: SafeArea( - child: Center( - child: Column( - children: [ - Text("Test"), - ], - ), - ), - ), - ); -// final navBotton = Destination(title: "test", icon: Icons.home, color: Colors.lightBlueAccent) - - @override - Widget build(BuildContext context) { - return Scaffold( -// bottomNavigationBar: allDestinations, - body: new Center( - child: _getWidget(), - ), - bottomNavigationBar: BottomNavyBar( - selectedIndex: _selectedIndex, - showElevation: true, // use this to remove appBar's elevation - onItemSelected: (index) => setState(() { - _selectedIndex = index; - - // _pageController.animateToPage(index, duration: Duration(milliseconds: 300), curve: Curves.ease); - }), - items: [ - BottomNavyBarItem( - icon: Icon(Icons.person), - title: Text('Find Mentor'), - activeColor: Colors.red, - ), - BottomNavyBarItem( - icon: Icon(Icons.people), - title: Text('Gender Stats'), - activeColor: Colors.purpleAccent, - ), - BottomNavyBarItem( - icon: Icon(Icons.code), - title: Text('Coding Stats'), - activeColor: Colors.pink), - BottomNavyBarItem( - icon: Icon(Icons.gps_fixed), - title: Text('Profile'), - activeColor: Colors.blue), - ], - ), - resizeToAvoidBottomInset: false, - ); - } - - Widget _getWidget() { - switch (_selectedIndex) { - case 0: - return Container( - child: FindMentor(), - ); - break; - case 1: - return Container( - child: GenderStats(), - ); - break; - case 2: - return Container( - child: CodingStats(), - ); - break; - default: - return Container( - child: Profile(), - ); - break; - } - } -} - -class Destination { - const Destination(this.title, this.icon, this.color); - final String title; - final IconData icon; - final MaterialColor color; -} - -const List allDestinations = [ - Destination('Recent', Icons.restore, Colors.teal), - Destination('Favorites', Icons.favorite_border, Colors.cyan), - Destination('School', Icons.school, Colors.orange), - Destination('Location', Icons.gps_fixed, Colors.blue) -]; diff --git a/lib/main.dart b/lib/main.dart index 369ddc1..ee8371a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,19 +1,25 @@ import 'package:flutter/material.dart'; -import 'package:peer_learning/screens/LoadingScreen.dart'; -import './Login/signup.dart'; -import './Login/signin.dart'; +import 'package:peer_learning/UI/LoadingScreen.dart'; +import 'package:peer_learning/models/AppModel.dart'; +import 'package:peer_learning/services/service_locator.dart'; +import 'package:scoped_model/scoped_model.dart'; +import 'UI/signup.dart'; +import 'UI/signin.dart'; - -void main() => runApp(MyApp()); +void main() { + setupLocator(); + runApp(MyApp()); +} class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - return MaterialApp( - debugShowCheckedModeBanner:false, - home: LoadingScreen(), - + debugShowCheckedModeBanner: false, + home: ScopedModel( + model: AppModel(), + child: LoadingScreen(), + ), ); } } diff --git a/lib/models/AppModel.dart b/lib/models/AppModel.dart new file mode 100644 index 0000000..b772d78 --- /dev/null +++ b/lib/models/AppModel.dart @@ -0,0 +1,3 @@ +import 'package:scoped_model/scoped_model.dart'; + +class AppModel extends Model {} diff --git a/lib/models/LoginModel.dart b/lib/models/LoginModel.dart new file mode 100644 index 0000000..a79f7c5 --- /dev/null +++ b/lib/models/LoginModel.dart @@ -0,0 +1,71 @@ +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:google_sign_in/google_sign_in.dart'; +import 'package:scoped_model/scoped_model.dart'; + +class LoginModel extends Model { + final FirebaseAuth auth = FirebaseAuth.instance; + final GoogleSignIn googleSignIn = GoogleSignIn(); + dynamic user; + final GlobalKey formKey = GlobalKey(); + final TextEditingController email = new TextEditingController(); + final TextEditingController password = new TextEditingController(); + bool _autoValidate = false; + bool _loadingVisible = false; + Animation animation; + + animate(controller) { + animation = ColorTween(begin: Colors.blueGrey, end: Colors.white) + .animate(controller); + controller.forward(); + + controller.addListener(() { + notifyListeners(); + }); + } + + String status = "Not Authenticated"; + + bool get loadingVisible => _loadingVisible; + + bool get autoValidate => _autoValidate; + + Future changeLoadingVisible() async { + _loadingVisible = !_loadingVisible; + } + + Future login(context) async { + try { + user = await auth.signInWithEmailAndPassword( + email: email.text, password: password.text); + } catch (e) { + print(e); + await showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text("Sign in failed!"), + content: Text( + "Your email/username is incorrect. Please check again and retry."), + ); + }); + } + } + + void signInAnon() async { + FirebaseUser user = (await auth.signInAnonymously()).user; + if (user != null && user.isAnonymous == true) { + status = "Signed in Anonymously"; + } else { + status = "Sign in failed"; + } + notifyListeners(); + } + + void signOut() async { + await auth.signOut(); + + status = "Signed Out"; + //no need to call notifyListener since we will pop page + } +} diff --git a/lib/models/SignUpModel.dart b/lib/models/SignUpModel.dart new file mode 100644 index 0000000..d191f70 --- /dev/null +++ b/lib/models/SignUpModel.dart @@ -0,0 +1,79 @@ +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:google_sign_in/google_sign_in.dart'; +import 'package:scoped_model/scoped_model.dart'; + +class SignUpModel extends Model { + final FirebaseAuth auth = FirebaseAuth.instance; + final GoogleSignIn googleSignIn = GoogleSignIn(); + dynamic newUser; + dynamic myController = TextEditingController(); + bool isSwitched = false; + final GlobalKey formKey = GlobalKey(); + final TextEditingController userName = TextEditingController(); + final TextEditingController email = new TextEditingController(); + final TextEditingController password = new TextEditingController(); + Animation animation; + + animate(controller) { + animation = ColorTween(begin: Colors.blueGrey, end: Colors.white) + .animate(controller); + controller.forward(); + + controller.addListener(() { + notifyListeners(); + }); + } + + bool _autoValidate = false; + bool _loadingVisible = false; + String currentValue = "Mentor or Mentee"; + + String currentProg = "Programming Language"; + + String status = "Not Authenticated"; + + bool get loadingVisible => _loadingVisible; + + bool get autoValidate => _autoValidate; + + Future changeLoadingVisible() async { + _loadingVisible = !_loadingVisible; + } + + Future signUp(context) async { + try { + newUser = await auth.createUserWithEmailAndPassword( + email: email.text, password: password.text); + } catch (e) { + print(e); + await showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text("Sign up failed!"), + content: + Text("Username already taken or You already got an account."), + ); + }, + ); + } + } + + void signInAnon() async { + FirebaseUser user = (await auth.signInAnonymously()).user; + if (user != null && user.isAnonymous == true) { + status = "Signed in Anonymously"; + } else { + status = "Sign in failed"; + } + notifyListeners(); + } + + void signOut() async { + await auth.signOut(); + + status = "Signed Out"; + //no need to call notifyListener since we will pop page + } +} diff --git a/lib/models/chat_model.dart b/lib/models/chat_model.dart new file mode 100644 index 0000000..67a8720 --- /dev/null +++ b/lib/models/chat_model.dart @@ -0,0 +1,48 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:peer_learning/UI/chat_forrum.dart'; +import 'package:scoped_model/scoped_model.dart'; + +class ChatModel extends Model { + final messageTextController = TextEditingController(); + String messageText; + FirebaseAuth auth = FirebaseAuth.instance; + + static final firestore = Firestore.instance; + + static getFirebaseMessage() { + dynamic snapshots = firestore.collection("messages").snapshots(); + + print(snapshots); + return snapshots; + } + + static FirebaseUser loggedUser; + + getMessage(value) { + messageText = value; + notifyListeners(); + } + + static List _messageBubbleList = []; + + List get messageBubbleList => _messageBubbleList; + + updateMessageBubble(bubble) { + _messageBubbleList.add(bubble); + notifyListeners(); + } + + sendMessage(String text) { + if (text != null && text != '') { + messageTextController.clear(); + firestore.collection("messages").add({ + "text": text, + "sender": loggedUser.email, + }); + messageText = ''; + } + notifyListeners(); + } +} diff --git a/lib/screens/LoadingScreen.dart b/lib/screens/LoadingScreen.dart deleted file mode 100644 index c735314..0000000 --- a/lib/screens/LoadingScreen.dart +++ /dev/null @@ -1,151 +0,0 @@ -import 'dart:io'; -import 'package:splashscreen/splashscreen.dart'; - -import 'package:flutter/material.dart'; -import 'package:peer_learning/Login/signin.dart'; -import 'package:animated_text_kit/animated_text_kit.dart'; -import 'package:flutter/scheduler.dart'; - -import 'package:flutter/material.dart'; -import 'package:splashscreen/splashscreen.dart'; - -class LoadingScreen extends StatefulWidget { - @override - _LoadingScreenState createState() => new _LoadingScreenState(); -} - -class _LoadingScreenState extends State - with SingleTickerProviderStateMixin { - AnimationController controller; - Animation animation; - - @override - void initState() { - super.initState(); - - controller = - AnimationController(duration: Duration(seconds: 1), vsync: this); - animation = ColorTween(begin: Colors.blueGrey, end: Colors.white) - .animate(controller); - controller.forward(); - - controller.addListener(() { - setState(() {}); - }); - } - -// @override -// void dispose() { -// super.dispose(); -// controller.dispose(); -// } - - @override - Widget build(BuildContext context) { - return Hero( - tag: "logo", - child: SplashScreen( - seconds: 2, - navigateAfterSeconds: SigninPage(), - title: Text( - 'Welcome to Peer Learning', - style: TextStyle( - fontWeight: FontWeight.bold, fontSize: 25.0 * controller.value), - ), - image: Image.asset( - 'assets/images/logo.png', - ), - gradientBackground: new LinearGradient( - colors: [Colors.cyan, Colors.blue], - begin: Alignment.topLeft, - end: Alignment.bottomRight), - backgroundColor: Colors.white, - styleTextUnderTheLoader: TextStyle(), - photoSize: 70.0 * controller.value, - onClick: () => {}, - loaderColor: Colors.grey, - ), - ); - } -} - -// -//class LoadingScreen extends StatefulWidget { -// @override -// _LoadingScreenState createState() => _LoadingScreenState(); -//} -// -//class _LoadingScreenState extends State -// with SingleTickerProviderStateMixin { -// AnimationController controller; -// Animation animation; -// -// @override -// void initState() { -// super.initState(); -// -// controller = -// AnimationController(duration: Duration(seconds: 1), vsync: this); -// animation = ColorTween(begin: Colors.blueGrey, end: Colors.white) -// .animate(controller); -// controller.forward(); -// -// controller.addListener(() { -// setState(() {}); -// print(animation.value); -// }); -// } -// -//// @override -//// void dispose() { -//// super.dispose(); -//// controller.dispose(); -//// } -// -//// goToLogin() { -//// setState(() { -//// Navigator.push( -//// context, MaterialPageRoute(builder: (context) => SigninPage())); -//// }); -//// } -// -// @override -// Widget build(BuildContext context) { -// SchedulerBinding.instance.addPostFrameCallback((_) => setState(() { -// sleep(Duration(seconds: 10)); -// Navigator.pushReplacement( -// context, MaterialPageRoute(builder: (context) => SigninPage())); -// })); -// -// return Scaffold( -// backgroundColor: animation.value, -// body: Padding( -// padding: EdgeInsets.symmetric(horizontal: 24.0), -// child: Column( -// mainAxisAlignment: MainAxisAlignment.center, -// crossAxisAlignment: CrossAxisAlignment.stretch, -// children: [ -// Row( -// children: [ -//// Hero( -//// tag: "logo", -//// child: Container( -//// child: Image.asset('images/logo.png'), -//// height: 60.0 * controller.value, -//// ), -//// ), -// TypewriterAnimatedTextKit( -// text: ['Peer Learning'], -// textStyle: TextStyle( -// fontSize: 45.0 * controller.value, -// fontWeight: FontWeight.w900, -// ), -// ), -// ], -// ), -// ], -// ), -// ), -// ); -// } -//} diff --git a/lib/services/service_locator.dart b/lib/services/service_locator.dart new file mode 100644 index 0000000..84a16e7 --- /dev/null +++ b/lib/services/service_locator.dart @@ -0,0 +1,17 @@ +import 'package:get_it/get_it.dart'; +import 'package:peer_learning/models/AppModel.dart'; +import 'package:peer_learning/models/LoginModel.dart'; +import 'package:peer_learning/models/SignUpModel.dart'; +import 'package:peer_learning/models/chat_model.dart'; + +GetIt locator = GetIt.instance; + +void setupLocator() { + //Register Services + + //Register Models + locator.registerFactory(() => AppModel()); + locator.registerFactory(() => LoginModel()); + locator.registerFactory(() => SignUpModel()); + locator.registerFactory(() => ChatModel()); +} diff --git a/pubspec.lock b/pubspec.lock index 77796e7..b8665a1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -163,6 +163,13 @@ packages: description: flutter source: sdk version: "0.0.0" + get_it: + dependency: "direct main" + description: + name: get_it + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" google_sign_in: dependency: "direct main" description: @@ -282,6 +289,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.5" + scoped_model: + dependency: "direct main" + description: + name: scoped_model + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" sky_engine: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 60315ca..d69d576 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,6 +32,8 @@ dependencies: google_sign_in: ^4.1.1 firebase_auth: ^0.15.3 modal_progress_hud: ^0.1.3 + scoped_model: ^1.0.1 + get_it: ^3.1.0 dev_dependencies: