ft/adds dashboard screen and refactores
adds: - loading screen - global background image refactores: - no more screens, just pages fixes: - login callback functions
This commit is contained in:
parent
a14b87012a
commit
d0687e2d3f
@ -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<String, dynamic> 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<LoginResponse> login(LoginRequest request, {Function? onError}) async {
|
||||
Future<LoginResponse> 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<GetAccountInfoResponse> getAccountInfo(GetAccountInfoRequest request,
|
||||
{Function? onError}) async {
|
||||
{required String token, required Function onError}) async {
|
||||
try {
|
||||
final response = await stub.getAccountInfo(request);
|
||||
Map<String, String> 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();
|
||||
}
|
||||
|
@ -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> navigatorState =
|
||||
GlobalKey<NavigatorState>();
|
||||
}
|
||||
|
||||
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()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
62
frontend/app/lib/pages/dashboard_page.dart
Normal file
62
frontend/app/lib/pages/dashboard_page.dart
Normal file
@ -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<DashboardPage> createState() => _DashboardPageState();
|
||||
}
|
||||
|
||||
class _DashboardPageState extends State<DashboardPage> {
|
||||
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,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -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,
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
179
frontend/app/lib/pages/login_page.dart
Normal file
179
frontend/app/lib/pages/login_page.dart
Normal file
@ -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<LoginPage> createState() => _LoginPageState();
|
||||
}
|
||||
|
||||
class _LoginPageState extends State<LoginPage> {
|
||||
bool _loading = false;
|
||||
|
||||
void _setLoading(bool loading) {
|
||||
setState(() {
|
||||
_loading = loading;
|
||||
});
|
||||
}
|
||||
|
||||
final Client client = Client();
|
||||
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
final mailController = TextEditingController();
|
||||
final passwordController = TextEditingController();
|
||||
|
||||
// @override
|
||||
// void initState() {
|
||||
// super.initState();
|
||||
// }
|
||||
|
||||
// Future<String> _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,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -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<FormState>();
|
||||
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))
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
import 'package:app/gapi/client.dart';
|
||||
import 'package:app/pages/login_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
Map<String, Widget> 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],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
29
frontend/app/lib/widgets/background.dart
Normal file
29
frontend/app/lib/widgets/background.dart
Normal file
@ -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);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user