diff --git a/frontend/app/lib/gapi/client.dart b/frontend/app/lib/gapi/client.dart index ccd0006..5cd6d75 100644 --- a/frontend/app/lib/gapi/client.dart +++ b/frontend/app/lib/gapi/client.dart @@ -1,16 +1,16 @@ -import 'package:app/main.dart'; import 'package:app/pb/rpc_create_account.pb.dart'; import 'package:app/pb/rpc_get_account_info.pb.dart'; import 'package:app/pb/rpc_login.pb.dart'; import 'package:app/pb/service_df.pbgrpc.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; import 'package:grpc/grpc.dart'; class Client { String baseUrl = 'localhost'; int port = 9090; + Map metadata = {'Authorization': ''}; + String accessToken = ''; + dfClient stub = dfClient( ClientChannel('10.0.2.2', port: 9090, @@ -35,44 +35,51 @@ class Client { return CreateAccountResponse(); } - // LoginResponse Login(BuildContext context, LoginRequest request ){ - // try { - // final response = stub.login(request); - // return response; - // } catch (e) { - // ScaffoldMessenger.of(context).showSnackBar(SnackBar( - // content: Text('Login fehlgeschlagen: $e'), - // )); - // } - // return LoginResponse(); - - // } - - Future login(LoginRequest request, {Function? onError}) async { + Future login( + {required String email, + required String password, + required Function onError, + required Function onSuccess}) async { + LoginResponse response = LoginResponse(); try { - final response = await stub.login(request); - return response; + response = await stub.login(LoginRequest( + email: email, + password: password, + )); + accessToken = response.accessToken; + metadata['Authorization'] = 'Bearer ${response.accessToken}'; + print('auth: ${metadata['Authorization']}'); + onSuccess(); + // return response; } on GrpcError catch (e) { print('caught error: ${e.message}'); - onError!(); + metadata['Authorization'] = ''; + onError(); } catch (e) { - print('caught error: $e'); - onError!(); + print('caught error: ${e}'); + metadata['Authorization'] = ''; + onError(); } - return LoginResponse(); + return response; } Future getAccountInfo(GetAccountInfoRequest request, - {Function? onError}) async { + {required String token, required Function onError}) async { try { - final response = await stub.getAccountInfo(request); + Map metadata = {'Authorization': 'Bearer $token'}; + final response = await stub.getAccountInfo( + request, + options: CallOptions( + metadata: metadata, + ), + ); return response; } on GrpcError catch (e) { print('caught error: ${e.message}'); - onError!(); + onError(); } catch (e) { print('caught error: $e'); - onError!(); + onError(); } return GetAccountInfoResponse(); } diff --git a/frontend/app/lib/main.dart b/frontend/app/lib/main.dart index f2393fa..409b5fb 100644 --- a/frontend/app/lib/main.dart +++ b/frontend/app/lib/main.dart @@ -1,17 +1,35 @@ +import 'package:app/pages/login_page.dart'; +import 'package:app/widgets/background.dart'; import 'package:flutter/material.dart'; -import 'package:app/pages/main_screen.dart'; - -class GlobalVariable { - /// This global key is used in material app for navigation through firebase notifications. - static final GlobalKey navigatorState = - GlobalKey(); -} - void main() async { WidgetsFlutterBinding.ensureInitialized(); - runApp(MaterialApp( - navigatorKey: GlobalVariable.navigatorState, - home: MainScreen(), - )); + + runApp( + MaterialApp( + theme: ThemeData().copyWith( + textTheme: const TextTheme().copyWith( + titleLarge: const TextStyle( + color: Colors.white, + ), + titleMedium: const TextStyle( + color: Colors.white, + ), + titleSmall: const TextStyle( + color: Colors.white, + ), + ), + inputDecorationTheme: const InputDecorationTheme( + labelStyle: TextStyle( + color: Colors.white, + ), + ), + scaffoldBackgroundColor: Colors.transparent, + appBarTheme: const AppBarTheme().copyWith( + backgroundColor: Colors.black, + foregroundColor: Colors.white, + )), + home: Background(child: LoginPage()), + ), + ); } diff --git a/frontend/app/lib/pages/dashboard_page.dart b/frontend/app/lib/pages/dashboard_page.dart new file mode 100644 index 0000000..2a5cfb1 --- /dev/null +++ b/frontend/app/lib/pages/dashboard_page.dart @@ -0,0 +1,62 @@ +import 'package:app/gapi/client.dart'; +import 'package:flutter/material.dart'; + +class DashboardPage extends StatefulWidget { + DashboardPage({super.key, required this.client}); + + final Client client; + + @override + State createState() => _DashboardPageState(); +} + +class _DashboardPageState extends State { + bool _loading = false; + + void _setLoading(bool loading) { + setState(() { + _loading = loading; + }); + } + + @override + void initState() { + super.initState(); + if (widget.client.accessToken == '') { + Navigator.of(context).pop(); + } + } + + @override + Widget build(BuildContext context) { + print(widget.client.accessToken); + return Scaffold( + appBar: AppBar( + automaticallyImplyLeading: false, + backgroundColor: Colors.black, + flexibleSpace: Image.asset( + 'lib/assets/logo_300x200.png', + height: 80, + ), + // actions: [ + // IconButton( + // onPressed: () {}, + // icon: const Icon(Icons.menu), + // tooltip: 'Menu', + // ), + // IconButton( + // onPressed: () {}, + // icon: const Icon(Icons.login_sharp), + // tooltip: 'Login', + // ), + // ], + ), + body: Text( + widget.client.accessToken, + style: const TextStyle( + color: Colors.white, + ), + ), + ); + } +} diff --git a/frontend/app/lib/pages/home_screen.dart b/frontend/app/lib/pages/home_screen.dart deleted file mode 100644 index a391ab6..0000000 --- a/frontend/app/lib/pages/home_screen.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:app/pb/account_info.pb.dart'; -import 'package:flutter/material.dart'; - -class HomeScreen extends StatelessWidget { - HomeScreen({super.key, required this.account_info}); - - AccountInfo account_info; - - @override - Widget build(BuildContext context) { - return Column( - children: [ - Text( - 'Willkommen ${account_info.firstname}!', - style: const TextStyle( - fontSize: 30, - fontWeight: FontWeight.bold, - ), - ) - ], - ); - } -} diff --git a/frontend/app/lib/pages/login_page.dart b/frontend/app/lib/pages/login_page.dart new file mode 100644 index 0000000..4789cee --- /dev/null +++ b/frontend/app/lib/pages/login_page.dart @@ -0,0 +1,179 @@ +import 'package:app/gapi/client.dart'; +import 'package:app/pages/dashboard_page.dart'; +import 'package:app/pb/rpc_login.pb.dart'; +import 'package:flutter/material.dart'; + +class LoginPage extends StatefulWidget { + const LoginPage({super.key}); + + @override + State createState() => _LoginPageState(); +} + +class _LoginPageState extends State { + bool _loading = false; + + void _setLoading(bool loading) { + setState(() { + _loading = loading; + }); + } + + final Client client = Client(); + + final _formKey = GlobalKey(); + final mailController = TextEditingController(); + final passwordController = TextEditingController(); + + // @override + // void initState() { + // super.initState(); + // } + + // Future _login( + // {required BuildContext context, + // required String email, + // required String password, + // required Function onSuccess, + // required Function onError}) async { + // LoginResponse r = await client.login( + // LoginRequest( + // email: email, + // password: password, + // ), + // onError: onError, + // onSuccess: onSuccess, + // ); + // return r.accessToken; + // } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + automaticallyImplyLeading: false, + backgroundColor: Colors.black, + flexibleSpace: Image.asset( + 'lib/assets/logo_300x200.png', + height: 80, + ), + // actions: [ + // IconButton( + // onPressed: () {}, + // icon: const Icon(Icons.menu), + // tooltip: 'Menu', + // ), + // IconButton( + // onPressed: () {}, + // icon: const Icon(Icons.login_sharp), + // tooltip: 'Login', + // ), + // ], + ), + body: !_loading + ? Form( + key: _formKey, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + TextFormField( + style: TextStyle( + color: Theme.of(context).colorScheme.primary, + ), + controller: mailController, + decoration: const InputDecoration( + fillColor: Color.fromARGB(30, 255, 255, 255), + filled: true, + hintStyle: TextStyle( + color: Colors.white38, + ), + hintText: 'E-Mail Adresse', + ), + keyboardType: TextInputType.emailAddress, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Bitte eine gültige E-Mail Adresse eingeben'; + } + return null; + }, + ), + TextFormField( + style: const TextStyle( + color: Colors.white, + ), + controller: passwordController, + decoration: const InputDecoration( + fillColor: Color.fromARGB(30, 255, 255, 255), + filled: true, + hintStyle: TextStyle( + color: Colors.white38, + ), + hintText: 'Passwort', + ), + keyboardType: TextInputType.visiblePassword, + obscureText: true, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Bitte geben Sie Ihr Passwort ein'; + } + return null; + }, + ), + ElevatedButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + // final navigator = Navigator.of(context); + _setLoading(true); + client + .login( + email: mailController.text, + password: passwordController.text, + onError: () { + _setLoading(false); + ScaffoldMessenger.of(context) + .showSnackBar(const SnackBar( + content: Text('Login fehlgeschlagen'), + )); + }, + onSuccess: () { + // _setLoading(false); + ScaffoldMessenger.of(context) + .showSnackBar(const SnackBar( + content: Text('Login erfolgreich'), + )); + }, + ) + .then( + (r) { + if (r.accessToken != '') { + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute( + builder: (ctx) => DashboardPage( + client: client, + ), + ), + (route) => false); + } + // _setLoading(false); + }, + ); + } + }, + child: const Icon(Icons.arrow_forward)) + ], + ), + ) + : Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'lib/assets/logo_300x200.png', + height: 300, + ), + ], + ), + ); + } +} diff --git a/frontend/app/lib/pages/login_screen.dart b/frontend/app/lib/pages/login_screen.dart deleted file mode 100644 index 4a035b7..0000000 --- a/frontend/app/lib/pages/login_screen.dart +++ /dev/null @@ -1,102 +0,0 @@ -import 'package:app/gapi/client.dart'; -import 'package:app/pages/home_screen.dart'; -import 'package:app/pb/rpc_get_account_info.pb.dart'; -import 'package:app/pb/rpc_login.pb.dart'; -import 'package:flutter/material.dart'; - -class LoginScreen extends StatelessWidget { - LoginScreen({super.key}); - - Client client = Client(); - - final _formKey = GlobalKey(); - final mailController = TextEditingController(); - final passwordController = TextEditingController(); - - @override - Widget build(BuildContext context) { - return Form( - key: _formKey, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - TextFormField( - style: const TextStyle( - color: Colors.white, - ), - controller: mailController, - decoration: const InputDecoration( - fillColor: Color.fromARGB(30, 255, 255, 255), - filled: true, - hintStyle: TextStyle( - color: Colors.white38, - ), - hintText: 'E-Mail Adresse', - ), - keyboardType: TextInputType.emailAddress, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Bitte eine gültige E-Mail Adresse eingeben'; - } - return null; - }, - ), - TextFormField( - style: const TextStyle( - color: Colors.white, - ), - controller: passwordController, - decoration: const InputDecoration( - fillColor: Color.fromARGB(30, 255, 255, 255), - filled: true, - hintStyle: TextStyle( - color: Colors.white38, - ), - hintText: 'Passwort', - ), - keyboardType: TextInputType.visiblePassword, - obscureText: true, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Bitte geben Sie Ihr Passwort ein'; - } - return null; - }, - ), - ElevatedButton( - onPressed: () async { - if (_formKey.currentState!.validate()) { - // final navigator = Navigator.of(context); - LoginResponse response = await client.login( - LoginRequest( - email: mailController.text, - password: passwordController.text, - ), - onError: () { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text('Login fehlgeschlagen'), - )); - }, - ); - - print(response); - - // GetAccountInfoResponse resp = await client.getAccountInfo( - // GetAccountInfoRequest(accountId: response.accountId)); - // Navigator.push( - // context, - // MaterialPageRoute( - // builder: (context) => HomeScreen( - // account_info: resp.accountInfo, - // ), - // ), - // ); - } - }, - child: const Icon(Icons.arrow_forward)) - ], - ), - ); - } -} diff --git a/frontend/app/lib/pages/main_screen.dart b/frontend/app/lib/pages/main_screen.dart deleted file mode 100644 index 53e18e9..0000000 --- a/frontend/app/lib/pages/main_screen.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'package:app/gapi/client.dart'; -import 'package:app/pages/login_screen.dart'; -import 'package:flutter/material.dart'; - -Map screens = { - // 'main': MainScreen(), - 'login': LoginScreen(), -}; - -class MainScreen extends StatelessWidget { - MainScreen({super.key}); - - Client client = Client(); - - String currentScreen = 'login'; - - setPage(String screen) { - currentScreen = screen; - } - - @override - Widget build(BuildContext context) { - return Container( - decoration: const BoxDecoration( - // color: Color.fromARGB(230, 255, 255, 255), - gradient: LinearGradient( - colors: [Colors.black, Colors.white], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), - image: DecorationImage( - image: AssetImage( - 'lib/assets/hero-pattern-300x200.png', - // color: Colors.grey, - ), - repeat: ImageRepeat.repeat, - fit: BoxFit.contain, - ), - ), - child: Scaffold( - backgroundColor: Colors.transparent, - appBar: AppBar( - backgroundColor: Colors.black, - flexibleSpace: Image.asset( - 'lib/assets/logo_300x200.png', - height: 80, - ), - actions: [ - IconButton( - onPressed: () {}, - icon: const Icon(Icons.menu), - tooltip: 'Menu', - ), - // IconButton( - // onPressed: () {}, - // icon: const Icon(Icons.login_sharp), - // tooltip: 'Login', - // ), - ], - ), - body: Center( - child: screens[currentScreen], - ), - ), - ); - } -} diff --git a/frontend/app/lib/widgets/background.dart b/frontend/app/lib/widgets/background.dart new file mode 100644 index 0000000..b0232a3 --- /dev/null +++ b/frontend/app/lib/widgets/background.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; + +class Background extends StatelessWidget { + const Background({super.key, required this.child}); + + final Widget child; + + @override + Widget build(BuildContext context) { + return Container( + decoration: const BoxDecoration( + // color: Color.fromARGB(230, 255, 255, 255), + gradient: LinearGradient( + colors: [Colors.black, Colors.white], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + image: DecorationImage( + image: AssetImage( + 'lib/assets/hero-pattern-300x200.png', + // color: Colors.grey, + ), + repeat: ImageRepeat.repeat, + fit: BoxFit.contain, + ), + ), + child: child); + } +}