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:
itsscb 2023-10-26 03:32:07 +02:00
parent a14b87012a
commit d0687e2d3f
8 changed files with 334 additions and 231 deletions

View File

@ -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();
}

View File

@ -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()),
),
);
}

View 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,
),
),
);
}
}

View File

@ -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,
),
)
],
);
}
}

View 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,
),
],
),
);
}
}

View File

@ -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))
],
),
);
}
}

View File

@ -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],
),
),
);
}
}

View 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);
}
}