From 4263997c3e419ef1cf7447d447c5582a322acf74 Mon Sep 17 00:00:00 2001 From: Marvin Borner Date: Fri, 20 Jul 2018 18:14:18 +0200 Subject: Began basic login screen feature (mvp architecture) --- android/.project | 17 ++ android/.settings/org.eclipse.buildship.core.prefs | 8 + android/app/.classpath | 6 + android/app/.project | 23 +++ .../app/.settings/org.eclipse.buildship.core.prefs | 2 + android/app/build.gradle | 2 +- android/app/src/main/AndroidManifest.xml | 12 +- .../BEAM_Messenger/MainActivity.java | 14 -- .../beam_messenger/MainActivity.java | 14 ++ assets/login_background.jpg | Bin 0 -> 120886 bytes lib/auth.dart | 43 +++++ lib/chat.dart | 181 ++++++++++++++++++++ lib/data/database_helper.dart | 54 ++++++ lib/data/rest_ds.dart | 22 +++ lib/main.dart | 182 ++------------------- lib/models/user.dart | 21 +++ lib/routes.dart | 9 + lib/screens/home/home_screen.dart | 14 ++ lib/screens/login/login_screen.dart | 141 ++++++++++++++++ lib/screens/login/login_screen_presenter.dart | 19 +++ lib/utils/network_util.dart | 38 +++++ pubspec.yaml | 50 +----- 22 files changed, 632 insertions(+), 240 deletions(-) create mode 100644 android/.project create mode 100644 android/.settings/org.eclipse.buildship.core.prefs create mode 100644 android/app/.classpath create mode 100644 android/app/.project create mode 100644 android/app/.settings/org.eclipse.buildship.core.prefs delete mode 100644 android/app/src/main/java/de/beam_messenger/BEAM_Messenger/MainActivity.java create mode 100644 android/app/src/main/java/de/beam_messenger/beam_messenger/MainActivity.java create mode 100644 assets/login_background.jpg create mode 100644 lib/auth.dart create mode 100644 lib/chat.dart create mode 100644 lib/data/database_helper.dart create mode 100644 lib/data/rest_ds.dart create mode 100644 lib/models/user.dart create mode 100644 lib/routes.dart create mode 100644 lib/screens/home/home_screen.dart create mode 100644 lib/screens/login/login_screen.dart create mode 100644 lib/screens/login/login_screen_presenter.dart create mode 100644 lib/utils/network_util.dart diff --git a/android/.project b/android/.project new file mode 100644 index 0000000..3964dd3 --- /dev/null +++ b/android/.project @@ -0,0 +1,17 @@ + + + android + Project android created by Buildship. + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/android/.settings/org.eclipse.buildship.core.prefs b/android/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 0000000..22b1843 --- /dev/null +++ b/android/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,8 @@ +auto.sync=false +build.scans.enabled=false +connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) +connection.project.dir= +eclipse.preferences.version=1 +gradle.user.home= +offline.mode=false +override.workspace.settings=true diff --git a/android/app/.classpath b/android/app/.classpath new file mode 100644 index 0000000..8d8d85f --- /dev/null +++ b/android/app/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/android/app/.project b/android/app/.project new file mode 100644 index 0000000..ac485d7 --- /dev/null +++ b/android/app/.project @@ -0,0 +1,23 @@ + + + app + Project app created by Buildship. + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/android/app/.settings/org.eclipse.buildship.core.prefs b/android/app/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 0000000..b1886ad --- /dev/null +++ b/android/app/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,2 @@ +connection.project.dir=.. +eclipse.preferences.version=1 diff --git a/android/app/build.gradle b/android/app/build.gradle index 0fa8004..8e0ce10 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -26,7 +26,7 @@ android { testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "de.beam_messenger.BEAM_Messenger" + applicationId "de.beam_messenger.beam_messenger" } buildTypes { diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 1cae011..3018739 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,7 +1,4 @@ - + @@ -17,12 +14,7 @@ additional functionality it is fine to subclass or reimplement FlutterApplication and put your custom class here. --> - + diff --git a/android/app/src/main/java/de/beam_messenger/BEAM_Messenger/MainActivity.java b/android/app/src/main/java/de/beam_messenger/BEAM_Messenger/MainActivity.java deleted file mode 100644 index bdf997d..0000000 --- a/android/app/src/main/java/de/beam_messenger/BEAM_Messenger/MainActivity.java +++ /dev/null @@ -1,14 +0,0 @@ -package de.beam_messenger.BEAM_Messenger; - -import android.os.Bundle; - -import io.flutter.app.FlutterActivity; -import io.flutter.plugins.GeneratedPluginRegistrant; - -public class MainActivity extends FlutterActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - GeneratedPluginRegistrant.registerWith(this); - } -} diff --git a/android/app/src/main/java/de/beam_messenger/beam_messenger/MainActivity.java b/android/app/src/main/java/de/beam_messenger/beam_messenger/MainActivity.java new file mode 100644 index 0000000..dc271a0 --- /dev/null +++ b/android/app/src/main/java/de/beam_messenger/beam_messenger/MainActivity.java @@ -0,0 +1,14 @@ +package de.beam_messenger.beam_messenger; + +import android.os.Bundle; + +import io.flutter.app.FlutterActivity; +import io.flutter.plugins.GeneratedPluginRegistrant; + +public class MainActivity extends FlutterActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + GeneratedPluginRegistrant.registerWith(this); + } +} diff --git a/assets/login_background.jpg b/assets/login_background.jpg new file mode 100644 index 0000000..ba466fc Binary files /dev/null and b/assets/login_background.jpg differ diff --git a/lib/auth.dart b/lib/auth.dart new file mode 100644 index 0000000..6ee8a0b --- /dev/null +++ b/lib/auth.dart @@ -0,0 +1,43 @@ +import 'package:beam_messenger/data/database_helper.dart'; + +enum AuthState { LOGGED_IN, LOGGED_OUT } + +abstract class AuthStateListener { + void onAuthStateChanged(AuthState state); +} + +// A naive implementation of Observer/Subscriber Pattern. Will do for now. +class AuthStateProvider { + static final AuthStateProvider _instance = new AuthStateProvider.internal(); + + List _subscribers; + + factory AuthStateProvider() => _instance; + AuthStateProvider.internal() { + _subscribers = new List(); + initState(); + } + + void initState() async { + var db = new DatabaseHelper(); + var isLoggedIn = await db.isLoggedIn(); + if (isLoggedIn) + notify(AuthState.LOGGED_IN); + else + notify(AuthState.LOGGED_OUT); + } + + void subscribe(AuthStateListener listener) { + _subscribers.add(listener); + } + + void dispose(AuthStateListener listener) { + for (var l in _subscribers) { + if (l == listener) _subscribers.remove(l); + } + } + + void notify(AuthState state) { + _subscribers.forEach((AuthStateListener s) => s.onAuthStateChanged(state)); + } +} diff --git a/lib/chat.dart b/lib/chat.dart new file mode 100644 index 0000000..d20cde4 --- /dev/null +++ b/lib/chat.dart @@ -0,0 +1,181 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +void main() { + runApp(new MessengerApp()); +} + +final ThemeData kIOSTheme = new ThemeData( + primarySwatch: Colors.orange, + primaryColor: Colors.grey[100], + primaryColorBrightness: Brightness.light, +); + +final ThemeData kDefaultTheme = new ThemeData( + primarySwatch: Colors.blue, + accentColor: Colors.orangeAccent[400], +); + +const String _name = "Marvin Borner"; + +class MessengerApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new MaterialApp( + title: "BEAM-Messenger", + theme: defaultTargetPlatform == TargetPlatform.iOS + ? kIOSTheme + : kDefaultTheme, + home: new ChatScreen(), + ); + } +} + +class ChatMessage extends StatelessWidget { + ChatMessage({this.text, this.animationController}); + final String text; + final AnimationController animationController; + @override + Widget build(BuildContext context) { + return new SizeTransition( + sizeFactor: new CurvedAnimation( + parent: animationController, + curve: Curves.easeOut + ), + axisAlignment: 0.0, + child: new Container( + margin: const EdgeInsets.symmetric(vertical: 10.0), + child: new Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + margin: const EdgeInsets.only(right: 16.0), + child: new CircleAvatar(child: new Text(_name[0])), + ), + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text(_name, style: Theme.of(context).textTheme.subhead), + new Container( + margin: const EdgeInsets.only(top: 5.0), + child: new Text(text), + ), + ], + ), + ), + ], + ), + ) + ); + } +} + +class ChatScreen extends StatefulWidget { + @override + State createState() => new ChatScreenState(); +} + +class ChatScreenState extends State with TickerProviderStateMixin { + final List _messages = []; + final TextEditingController _textController = new TextEditingController(); + bool _isComposing = false; + + void _handleSubmitted(String text) { + _textController.clear(); + setState(() { + _isComposing = false; + }); + ChatMessage message = new ChatMessage( + text: text, + animationController: new AnimationController( + duration: new Duration(milliseconds: 700), + vsync: this, + ), + ); + setState(() { + _messages.insert(0, message); + }); + message.animationController.forward(); + } + + void dispose() { + for (ChatMessage message in _messages) + message.animationController.dispose(); + super.dispose(); + } + + Widget _buildTextComposer() { + return new IconTheme( + data: new IconThemeData(color: Theme.of(context).accentColor), + child: new Container( + margin: const EdgeInsets.symmetric(horizontal: 8.0), + child: new Row(children: [ + new Flexible( + child: new TextField( + controller: _textController, + onChanged: (String text) { + setState(() { + _isComposing = text.length > 0; + }); + }, + onSubmitted: _handleSubmitted, + decoration: + new InputDecoration.collapsed(hintText: "Send a message..."), + ), + ), + new Container( + margin: new EdgeInsets.symmetric(horizontal: 4.0), + child: Theme.of(context).platform == TargetPlatform.iOS + ? new CupertinoButton( + child: new Text("Send"), + onPressed: _isComposing + ? () => _handleSubmitted(_textController.text) + : null, + ) + : new IconButton( + icon: new Icon(Icons.send), + onPressed: _isComposing + ? () => _handleSubmitted(_textController.text) + : null, + )), + ]), + decoration: Theme.of(context).platform == TargetPlatform.iOS + ? new BoxDecoration( + border: + new Border(top: new BorderSide(color: Colors.grey[200]))) + : null), + ); + } + + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text("BEAM-Messenger"), + elevation: + Theme.of(context).platform == TargetPlatform.iOS ? 0.0 : 4.0 + ), + body: new Container( + child: new Column( + children: [ + new Flexible( + child: new ListView.builder( + padding: new EdgeInsets.all(8.0), + reverse: true, + itemBuilder: (_, int index) => _messages[index], + itemCount: _messages.length, + ) + ), + new Divider(height: 1.0), + new Container( + decoration: new BoxDecoration( + color: Theme.of(context).cardColor), + child: _buildTextComposer(), + ), + ] + ), + decoration: Theme.of(context).platform == TargetPlatform.iOS ? new BoxDecoration(border: new Border(top: new BorderSide(color: Colors.grey[200]))) : null), + ); + } +} diff --git a/lib/data/database_helper.dart b/lib/data/database_helper.dart new file mode 100644 index 0000000..da65dcc --- /dev/null +++ b/lib/data/database_helper.dart @@ -0,0 +1,54 @@ +import 'dart:async'; +import 'dart:io' as io; + +import 'package:path/path.dart'; +import 'package:beam_messenger/models/user.dart'; +import 'package:sqflite/sqflite.dart'; +import 'package:path_provider/path_provider.dart'; + +class DatabaseHelper { + static final DatabaseHelper _instance = new DatabaseHelper.internal(); + factory DatabaseHelper() => _instance; + + static Database _db; + + Future get db async { + if (_db != null) return _db; + _db = await initDb(); + return _db; + } + + DatabaseHelper.internal(); + + initDb() async { + io.Directory documentsDirectory = await getApplicationDocumentsDirectory(); + String path = join(documentsDirectory.path, "main.db"); + var theDb = await openDatabase(path, version: 1, onCreate: _onCreate); + return theDb; + } + + void _onCreate(Database db, int version) async { + // When creating the db, create the table + await db.execute( + "CREATE TABLE User(id INTEGER PRIMARY KEY, email TEXT, password TEXT)"); + print("Created tables"); + } + + Future saveUser(User user) async { + var dbClient = await db; + int res = await dbClient.insert("User", user.toMap()); + return res; + } + + Future deleteUsers() async { + var dbClient = await db; + int res = await dbClient.delete("User"); + return res; + } + + Future isLoggedIn() async { + var dbClient = await db; + var res = await dbClient.query("User"); + return res.length > 0 ? true : false; + } +} diff --git a/lib/data/rest_ds.dart b/lib/data/rest_ds.dart new file mode 100644 index 0000000..7d66d4a --- /dev/null +++ b/lib/data/rest_ds.dart @@ -0,0 +1,22 @@ +import 'dart:async'; +import 'dart:convert'; // not needed for later use + +import 'package:beam_messenger/utils/network_util.dart'; +import 'package:beam_messenger/models/user.dart'; + +class RestDatasource { + NetworkUtil _netUtil = new NetworkUtil(); + static final BASE_URL = "http://192.168.0.74:8000"; + static final LOGIN_URL = BASE_URL + "/login"; + + Future login(String email, String password) { + return _netUtil.post(LOGIN_URL, + body: {"email": email, "password": password}).then((dynamic res) { + print(res.toString()); + if (res["status"]) throw new Exception(res["message"]); + return jsonDecode( + "{ error: false, user: { email: “marvin@borners.de”, password: “password” } }"); // later: access token + // return new User.map(res["user"]); + }); + } +} diff --git a/lib/main.dart b/lib/main.dart index d20cde4..a7df267 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,181 +1,19 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:beam_messenger/auth.dart'; +import 'package:beam_messenger/routes.dart'; -void main() { - runApp(new MessengerApp()); -} - -final ThemeData kIOSTheme = new ThemeData( - primarySwatch: Colors.orange, - primaryColor: Colors.grey[100], - primaryColorBrightness: Brightness.light, -); - -final ThemeData kDefaultTheme = new ThemeData( - primarySwatch: Colors.blue, - accentColor: Colors.orangeAccent[400], -); - -const String _name = "Marvin Borner"; - -class MessengerApp extends StatelessWidget { - @override - Widget build(BuildContext context) { - return new MaterialApp( - title: "BEAM-Messenger", - theme: defaultTargetPlatform == TargetPlatform.iOS - ? kIOSTheme - : kDefaultTheme, - home: new ChatScreen(), - ); - } -} +void main() => runApp(new LoginApp()); -class ChatMessage extends StatelessWidget { - ChatMessage({this.text, this.animationController}); - final String text; - final AnimationController animationController; +class LoginApp extends StatelessWidget { + // This widget is the root of your application. @override Widget build(BuildContext context) { - return new SizeTransition( - sizeFactor: new CurvedAnimation( - parent: animationController, - curve: Curves.easeOut - ), - axisAlignment: 0.0, - child: new Container( - margin: const EdgeInsets.symmetric(vertical: 10.0), - child: new Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - new Container( - margin: const EdgeInsets.only(right: 16.0), - child: new CircleAvatar(child: new Text(_name[0])), - ), - new Expanded( - child: new Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - new Text(_name, style: Theme.of(context).textTheme.subhead), - new Container( - margin: const EdgeInsets.only(top: 5.0), - child: new Text(text), - ), - ], - ), - ), - ], - ), - ) - ); - } -} - -class ChatScreen extends StatefulWidget { - @override - State createState() => new ChatScreenState(); -} - -class ChatScreenState extends State with TickerProviderStateMixin { - final List _messages = []; - final TextEditingController _textController = new TextEditingController(); - bool _isComposing = false; - - void _handleSubmitted(String text) { - _textController.clear(); - setState(() { - _isComposing = false; - }); - ChatMessage message = new ChatMessage( - text: text, - animationController: new AnimationController( - duration: new Duration(milliseconds: 700), - vsync: this, + return new MaterialApp( + title: 'Login', + theme: new ThemeData( + primarySwatch: Colors.red, ), + routes: routes, ); - setState(() { - _messages.insert(0, message); - }); - message.animationController.forward(); - } - - void dispose() { - for (ChatMessage message in _messages) - message.animationController.dispose(); - super.dispose(); - } - - Widget _buildTextComposer() { - return new IconTheme( - data: new IconThemeData(color: Theme.of(context).accentColor), - child: new Container( - margin: const EdgeInsets.symmetric(horizontal: 8.0), - child: new Row(children: [ - new Flexible( - child: new TextField( - controller: _textController, - onChanged: (String text) { - setState(() { - _isComposing = text.length > 0; - }); - }, - onSubmitted: _handleSubmitted, - decoration: - new InputDecoration.collapsed(hintText: "Send a message..."), - ), - ), - new Container( - margin: new EdgeInsets.symmetric(horizontal: 4.0), - child: Theme.of(context).platform == TargetPlatform.iOS - ? new CupertinoButton( - child: new Text("Send"), - onPressed: _isComposing - ? () => _handleSubmitted(_textController.text) - : null, - ) - : new IconButton( - icon: new Icon(Icons.send), - onPressed: _isComposing - ? () => _handleSubmitted(_textController.text) - : null, - )), - ]), - decoration: Theme.of(context).platform == TargetPlatform.iOS - ? new BoxDecoration( - border: - new Border(top: new BorderSide(color: Colors.grey[200]))) - : null), - ); - } - - Widget build(BuildContext context) { - return new Scaffold( - appBar: new AppBar( - title: new Text("BEAM-Messenger"), - elevation: - Theme.of(context).platform == TargetPlatform.iOS ? 0.0 : 4.0 - ), - body: new Container( - child: new Column( - children: [ - new Flexible( - child: new ListView.builder( - padding: new EdgeInsets.all(8.0), - reverse: true, - itemBuilder: (_, int index) => _messages[index], - itemCount: _messages.length, - ) - ), - new Divider(height: 1.0), - new Container( - decoration: new BoxDecoration( - color: Theme.of(context).cardColor), - child: _buildTextComposer(), - ), - ] - ), - decoration: Theme.of(context).platform == TargetPlatform.iOS ? new BoxDecoration(border: new Border(top: new BorderSide(color: Colors.grey[200]))) : null), - ); } } diff --git a/lib/models/user.dart b/lib/models/user.dart new file mode 100644 index 0000000..89e3ace --- /dev/null +++ b/lib/models/user.dart @@ -0,0 +1,21 @@ +class User { + String _email; + String _password; + User(this._email, this._password); + + User.map(dynamic obj) { + this._email = obj["email"]; + this._password = obj["password"]; + } + + String get email => _email; + String get password => _password; + + Map toMap() { + var map = new Map(); + map["email"] = _email; + map["password"] = _password; + + return map; + } +} diff --git a/lib/routes.dart b/lib/routes.dart new file mode 100644 index 0000000..4a9ae07 --- /dev/null +++ b/lib/routes.dart @@ -0,0 +1,9 @@ +import 'package:flutter/material.dart'; +import 'package:beam_messenger/screens/home/home_screen.dart'; +import 'package:beam_messenger/screens/login/login_screen.dart'; + +final routes = { + '/login': (BuildContext context) => new LoginScreen(), + '/home': (BuildContext context) => new HomeScreen(), + '/': (BuildContext context) => new LoginScreen(), +}; diff --git a/lib/screens/home/home_screen.dart b/lib/screens/home/home_screen.dart new file mode 100644 index 0000000..46acd22 --- /dev/null +++ b/lib/screens/home/home_screen.dart @@ -0,0 +1,14 @@ +import 'package:flutter/material.dart'; + +class HomeScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar(title: new Text("Home"),), + body: new Center( + child: new Text("Welcome home!"), + ), + ); + } + +} \ No newline at end of file diff --git a/lib/screens/login/login_screen.dart b/lib/screens/login/login_screen.dart new file mode 100644 index 0000000..7c8845e --- /dev/null +++ b/lib/screens/login/login_screen.dart @@ -0,0 +1,141 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:beam_messenger/auth.dart'; +import 'package:beam_messenger/data/database_helper.dart'; +import 'package:beam_messenger/models/user.dart'; +import 'package:beam_messenger/screens/login/login_screen_presenter.dart'; + +class LoginScreen extends StatefulWidget { + @override + State createState() { + return new LoginScreenState(); + } +} + +class LoginScreenState extends State + implements LoginScreenContract, AuthStateListener { + BuildContext _ctx; + + bool _isLoading = false; + final formKey = new GlobalKey(); + final scaffoldKey = new GlobalKey(); + String _password, _email; + + LoginScreenPresenter _presenter; + + LoginScreenState() { + _presenter = new LoginScreenPresenter(this); + var authStateProvider = new AuthStateProvider(); + authStateProvider.subscribe(this); + } + + void _submit() { + final form = formKey.currentState; + + if (form.validate()) { + setState(() => _isLoading = true); + form.save(); + _presenter.doLogin(_email, _password); + } + } + + void _showSnackBar(String text) { + scaffoldKey.currentState + .showSnackBar(new SnackBar(content: new Text(text))); + } + + @override + onAuthStateChanged(AuthState state) { + if (state == AuthState.LOGGED_IN) + Navigator.of(_ctx).pushReplacementNamed("/home"); + } + + @override + Widget build(BuildContext context) { + _ctx = context; + var loginBtn = new RaisedButton( + onPressed: _submit, + child: new Text("LOGIN"), + color: Colors.primaries[0], + ); + var loginForm = new Column( + children: [ + new Text( + "Login", + textScaleFactor: 2.0, + ), + new Form( + key: formKey, + child: new Column( + children: [ + new Padding( + padding: const EdgeInsets.all(8.0), + child: new TextFormField( + onSaved: (val) => _email = val, + validator: (val) { + return val.length < 10 + ? "email must have atleast 10 chars" + : null; + }, + decoration: new InputDecoration(labelText: "email"), + ), + ), + new Padding( + padding: const EdgeInsets.all(8.0), + child: new TextFormField( + onSaved: (val) => _password = val, + decoration: new InputDecoration(labelText: "Password"), + ), + ), + ], + ), + ), + _isLoading ? new CircularProgressIndicator() : loginBtn + ], + crossAxisAlignment: CrossAxisAlignment.center, + ); + + return new Scaffold( + appBar: null, + key: scaffoldKey, + body: new Container( + decoration: new BoxDecoration( + image: new DecorationImage( + image: new AssetImage("assets/login_background.jpg"), + fit: BoxFit.cover), + ), + child: new Center( + child: new ClipRect( + child: new BackdropFilter( + filter: new ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), + child: new Container( + child: loginForm, + height: 300.0, + width: 300.0, + decoration: new BoxDecoration( + color: Colors.grey.shade200.withOpacity(0.5)), + ), + ), + ), + ), + ), + ); + } + + @override + void onLoginError(String errorTxt) { + _showSnackBar(errorTxt); + setState(() => _isLoading = false); + } + + @override + void onLoginSuccess(User user) async { + _showSnackBar(user.toString()); + setState(() => _isLoading = false); + var db = new DatabaseHelper(); + await db.saveUser(user); + var authStateProvider = new AuthStateProvider(); + authStateProvider.notify(AuthState.LOGGED_IN); + } +} diff --git a/lib/screens/login/login_screen_presenter.dart b/lib/screens/login/login_screen_presenter.dart new file mode 100644 index 0000000..fc5da4f --- /dev/null +++ b/lib/screens/login/login_screen_presenter.dart @@ -0,0 +1,19 @@ +import 'package:beam_messenger/data/rest_ds.dart'; +import 'package:beam_messenger/models/user.dart'; + +abstract class LoginScreenContract { + void onLoginSuccess(User user); + void onLoginError(String errorTxt); +} + +class LoginScreenPresenter { + LoginScreenContract _view; + RestDatasource api = new RestDatasource(); + LoginScreenPresenter(this._view); + + doLogin(String email, String password) { + api.login(email, password).then((User user) { + _view.onLoginSuccess(user); + }).catchError((Exception error) => _view.onLoginError(error.toString())); + } +} diff --git a/lib/utils/network_util.dart b/lib/utils/network_util.dart new file mode 100644 index 0000000..463e98f --- /dev/null +++ b/lib/utils/network_util.dart @@ -0,0 +1,38 @@ +import 'dart:async'; +import 'dart:convert'; +import 'package:http/http.dart' as http; + +class NetworkUtil { + // next three lines makes this class a Singleton + static NetworkUtil _instance = new NetworkUtil.internal(); + NetworkUtil.internal(); + factory NetworkUtil() => _instance; + + final JsonDecoder _decoder = new JsonDecoder(); + + Future get(String url) { + return http.get(url).then((http.Response response) { + final String res = response.body; + final int statusCode = response.statusCode; + + if (statusCode < 200 || statusCode > 400 || json == null) { + throw new Exception("Error while fetching data"); + } + return _decoder.convert(res); + }); + } + + Future post(String url, {Map headers, body, encoding}) { + return http + .post(url, body: body, headers: headers, encoding: encoding) + .then((http.Response response) { + final String res = response.body; + final int statusCode = response.statusCode; + + if (statusCode < 200 || statusCode > 400 || json == null) { + throw new Exception("Error while fetching data"); + } + return _decoder.convert(res); + }); + } +} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index e1a823b..6977814 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,51 +1,15 @@ -name: BEAM_Messenger +name: beam_messenger description: A new flutter project. dependencies: + http: any + sqflite: any + path_provider: any + cupertino_icons: any flutter: sdk: flutter -# For information on the generic Dart part of this file, see the -# following page: https://www.dartlang.org/tools/pub/pubspec - -# The following section is specific to Flutter. flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the Icons class. uses-material-design: true - - # To add assets to your application, add an assets section here, in - # this "flutter" section, as in: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # To add assets from package dependencies, first ensure the asset - # is in the lib/ directory of the dependency. Then, - # refer to the asset with a path prefixed with - # `packages/PACKAGE_NAME/`. Note: the `lib/` is implied, do not - # include `lib/` in the asset path. - # - # Here is an example: - # - # assets: - # - packages/PACKAGE_NAME/path/to/asset - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 + assets: + - assets/login_background.jpg \ No newline at end of file -- cgit v1.2.3