ft/adds toasts to api calls
This commit is contained in:
parent
604c2bdd27
commit
c4da7bea27
@ -1,5 +1,4 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:app/pb/session.pbjson.dart';
|
|
||||||
import 'package:fixnum/fixnum.dart';
|
import 'package:fixnum/fixnum.dart';
|
||||||
|
|
||||||
import 'package:app/pb/google/protobuf/timestamp.pb.dart';
|
import 'package:app/pb/google/protobuf/timestamp.pb.dart';
|
||||||
@ -167,7 +166,7 @@ class Session {
|
|||||||
final db = await database;
|
final db = await database;
|
||||||
|
|
||||||
final List<Map<String, Object?>> maps = await db.query('sessions');
|
final List<Map<String, Object?>> maps = await db.query('sessions');
|
||||||
print(maps);
|
// print(maps);
|
||||||
final List<Session> sessions = List.generate(
|
final List<Session> sessions = List.generate(
|
||||||
maps.length,
|
maps.length,
|
||||||
(i) {
|
(i) {
|
||||||
|
@ -41,7 +41,9 @@ void main() async {
|
|||||||
backgroundColor: Colors.black,
|
backgroundColor: Colors.black,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
)),
|
)),
|
||||||
home: const HomePage(),
|
home: HomePage(
|
||||||
|
loggedOut: false,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ class ApiResponse<T> {
|
|||||||
|
|
||||||
ApiResponse.initial(this.message) : status = Status.INITIAL;
|
ApiResponse.initial(this.message) : status = Status.INITIAL;
|
||||||
ApiResponse.loading(this.message) : status = Status.LOADING;
|
ApiResponse.loading(this.message) : status = Status.LOADING;
|
||||||
ApiResponse.completed(this.data, this.message) : status = Status.COMPLETED;
|
ApiResponse.completed(this.data) : status = Status.COMPLETED;
|
||||||
ApiResponse.error(this.message) : status = Status.ERROR;
|
ApiResponse.error(this.message) : status = Status.ERROR;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -3,9 +3,11 @@ import 'dart:io';
|
|||||||
import 'package:app/model/apis/app_exception.dart';
|
import 'package:app/model/apis/app_exception.dart';
|
||||||
import 'package:app/pb/account.pb.dart';
|
import 'package:app/pb/account.pb.dart';
|
||||||
import 'package:app/pb/account_info.pb.dart';
|
import 'package:app/pb/account_info.pb.dart';
|
||||||
|
import 'package:app/pb/google/protobuf/timestamp.pb.dart';
|
||||||
import 'package:app/pb/person.pb.dart';
|
import 'package:app/pb/person.pb.dart';
|
||||||
import 'package:app/data/database.dart';
|
import 'package:app/data/database.dart';
|
||||||
import 'package:app/pb/rpc_create_account.pb.dart';
|
import 'package:app/pb/rpc_create_account.pb.dart';
|
||||||
|
import 'package:app/pb/rpc_create_person.pb.dart';
|
||||||
import 'package:app/pb/rpc_get_account.pb.dart';
|
import 'package:app/pb/rpc_get_account.pb.dart';
|
||||||
import 'package:app/pb/rpc_get_account_info.pb.dart';
|
import 'package:app/pb/rpc_get_account_info.pb.dart';
|
||||||
import 'package:app/pb/rpc_get_person.pb.dart';
|
import 'package:app/pb/rpc_get_person.pb.dart';
|
||||||
@ -15,7 +17,6 @@ import 'package:app/pb/rpc_refresh_token.pb.dart';
|
|||||||
import 'package:app/pb/service_df.pbgrpc.dart';
|
import 'package:app/pb/service_df.pbgrpc.dart';
|
||||||
import 'package:fixnum/fixnum.dart';
|
import 'package:fixnum/fixnum.dart';
|
||||||
import 'package:grpc/grpc.dart';
|
import 'package:grpc/grpc.dart';
|
||||||
import 'package:sqflite/sqflite.dart';
|
|
||||||
|
|
||||||
class BackendService {
|
class BackendService {
|
||||||
BackendService() {
|
BackendService() {
|
||||||
@ -138,17 +139,16 @@ class BackendService {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
final GetAccountResponse response = await _client.getAccount(
|
final GetAccountResponse response = await _client.getAccount(
|
||||||
GetAccountRequest(id: session!.accountId),
|
GetAccountRequest(id: session.accountId),
|
||||||
options: CallOptions(
|
options: CallOptions(
|
||||||
metadata: {'Authorization': 'Bearer ${session.accessToken}'}));
|
metadata: {'Authorization': 'Bearer ${session.accessToken}'}));
|
||||||
return response.account;
|
return response.account;
|
||||||
} on SocketException {
|
} on SocketException {
|
||||||
throw FetchDataException('Keine Internet Verbindung');
|
throw FetchDataException('Keine Internet Verbindung');
|
||||||
} on GrpcError catch (err) {
|
} on GrpcError catch (err) {
|
||||||
// if (err.code == 16) {
|
if (err.code == 16) {
|
||||||
// await refreshToken(session);
|
throw UnauthorizedException(err.message);
|
||||||
// return getAccount();
|
}
|
||||||
// }
|
|
||||||
throw FetchDataException(err.message);
|
throw FetchDataException(err.message);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw InternalException(err.toString());
|
throw InternalException(err.toString());
|
||||||
@ -207,6 +207,47 @@ class BackendService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Person> createPerson(
|
||||||
|
{required String firstname,
|
||||||
|
required String lastname,
|
||||||
|
required String street,
|
||||||
|
required String zip,
|
||||||
|
required String city,
|
||||||
|
required String country,
|
||||||
|
required DateTime birthday}) async {
|
||||||
|
Session session = await Session.session;
|
||||||
|
if (session.accessTokenExpiresAt == null) {
|
||||||
|
throw UnauthorizedException('Keine Siztung gefunden');
|
||||||
|
}
|
||||||
|
if (session.accessTokenExpiresAt!.toDateTime().isBefore(DateTime.now())) {
|
||||||
|
session = await refreshToken(session);
|
||||||
|
if (session.accessTokenExpiresAt == null) {
|
||||||
|
throw UnauthorizedException('Sitzung ist abgelaufen');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final CreatePersonResponse response = await _client.createPerson(
|
||||||
|
CreatePersonRequest(
|
||||||
|
accountId: session.accountId,
|
||||||
|
lastname: lastname,
|
||||||
|
firstname: firstname,
|
||||||
|
street: street,
|
||||||
|
zip: zip,
|
||||||
|
country: country,
|
||||||
|
birthday: Timestamp.fromDateTime(birthday),
|
||||||
|
),
|
||||||
|
options: CallOptions(
|
||||||
|
metadata: {'Authorization': 'Bearer ${session.accessToken}'}));
|
||||||
|
return response.person;
|
||||||
|
} on SocketException {
|
||||||
|
throw FetchDataException('Keine Internet Verbindung');
|
||||||
|
} on GrpcError catch (err) {
|
||||||
|
throw FetchDataException(err.message);
|
||||||
|
} catch (err) {
|
||||||
|
throw InternalException(err.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<List<Person>> listPersons() async {
|
Future<List<Person>> listPersons() async {
|
||||||
Session session = await Session.session;
|
Session session = await Session.session;
|
||||||
if (session.accessTokenExpiresAt == null) {
|
if (session.accessTokenExpiresAt == null) {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import 'package:app/model/apis/api_response.dart';
|
import 'package:app/model/apis/api_response.dart';
|
||||||
import 'package:app/model/services/backend_service.dart';
|
import 'package:app/model/services/backend_service.dart';
|
||||||
|
import 'package:app/model/view_model/base_vm.dart';
|
||||||
import 'package:app/pb/account.pb.dart';
|
import 'package:app/pb/account.pb.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class AccountViewModel with ChangeNotifier {
|
class AccountViewModel extends BaseViewModel {
|
||||||
AccountViewModel() {
|
AccountViewModel() {
|
||||||
_init();
|
_init();
|
||||||
}
|
}
|
||||||
@ -21,36 +21,12 @@ class AccountViewModel with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _init() async {
|
void _init() async {
|
||||||
_apiResponse = ApiResponse.loading('Bereite alles vor');
|
super.init();
|
||||||
try {
|
// try {
|
||||||
_apiResponse = ApiResponse.completed(await _service.getAccount(), 'done');
|
// _apiResponse = ApiResponse.completed(await _service.getAccount());
|
||||||
} catch (e) {
|
// } catch (e) {
|
||||||
_apiResponse = ApiResponse.error(e.toString());
|
// _apiResponse = ApiResponse.error(e.toString());
|
||||||
}
|
// }
|
||||||
notifyListeners();
|
// notifyListeners();
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> fetchAccount() async {
|
|
||||||
_apiResponse = ApiResponse.loading('Hole Account');
|
|
||||||
notifyListeners();
|
|
||||||
try {
|
|
||||||
_apiResponse = ApiResponse.completed(await _service.getAccount(), 'done');
|
|
||||||
} catch (e) {
|
|
||||||
_apiResponse = ApiResponse.error(e.toString());
|
|
||||||
}
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> logout() async {
|
|
||||||
_apiResponse = ApiResponse.loading('Logge aus');
|
|
||||||
notifyListeners();
|
|
||||||
try {
|
|
||||||
await BackendService.logout();
|
|
||||||
_apiResponse = ApiResponse.completed(null, 'Erfolgreich ausgeloggt');
|
|
||||||
} catch (e) {
|
|
||||||
_apiResponse = ApiResponse.error(e.toString());
|
|
||||||
}
|
|
||||||
print(_apiResponse.message);
|
|
||||||
notifyListeners();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
254
frontend/app/lib/model/view_model/base_vm.dart
Normal file
254
frontend/app/lib/model/view_model/base_vm.dart
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
import 'package:app/model/apis/api_response.dart';
|
||||||
|
import 'package:app/model/services/backend_service.dart';
|
||||||
|
import 'package:app/pages/home_page.dart';
|
||||||
|
import 'package:app/util/colors.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class BaseViewModel with ChangeNotifier {
|
||||||
|
BaseViewModel() {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
ApiResponse _apiResponse = ApiResponse.initial('Keine Daten');
|
||||||
|
|
||||||
|
final BackendService _service = BackendService();
|
||||||
|
|
||||||
|
ApiResponse get response {
|
||||||
|
return _apiResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init() async {
|
||||||
|
// if (await BackendService.isLoggedIn) {
|
||||||
|
try {
|
||||||
|
_apiResponse = ApiResponse.completed(await _service.getAccount());
|
||||||
|
} catch (e) {
|
||||||
|
_apiResponse = ApiResponse.error(e.toString());
|
||||||
|
}
|
||||||
|
notifyListeners();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> isLoggedIn(BuildContext context) async {
|
||||||
|
final messenger = ScaffoldMessenger.of(context);
|
||||||
|
final navigator = Navigator.of(context);
|
||||||
|
bool loggedIn = false;
|
||||||
|
try {
|
||||||
|
loggedIn = await BackendService.isLoggedIn;
|
||||||
|
} catch (err) {
|
||||||
|
if (err.toString().contains('session is blocked')) {
|
||||||
|
_apiResponse = ApiResponse.error('Sitzung ist abgelaufen');
|
||||||
|
navigator.pushAndRemoveUntil(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (builder) => HomePage(
|
||||||
|
loggedOut: true,
|
||||||
|
)),
|
||||||
|
(route) => false);
|
||||||
|
messenger.showSnackBar(SnackBar(
|
||||||
|
backgroundColor: CustomColors.error,
|
||||||
|
content: const Text(
|
||||||
|
'Sitzung ist abgelaufen',
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
// action: SnackBarAction(
|
||||||
|
// label: 'Details',
|
||||||
|
// onPressed: () {
|
||||||
|
// if (context.mounted) {
|
||||||
|
// showDialog(
|
||||||
|
// context: context,
|
||||||
|
// builder: (context) => AlertDialog(
|
||||||
|
// backgroundColor: Colors.black,
|
||||||
|
// icon: Icon(
|
||||||
|
// Icons.error,
|
||||||
|
// color: CustomColors.error,
|
||||||
|
// ),
|
||||||
|
// content: Text(
|
||||||
|
// err.toString(),
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// ),
|
||||||
|
// ));
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loggedIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getAccount(BuildContext context) async {
|
||||||
|
_apiResponse = ApiResponse.loading('Lade Daten');
|
||||||
|
notifyListeners();
|
||||||
|
final messenger = ScaffoldMessenger.of(context);
|
||||||
|
try {
|
||||||
|
_apiResponse = ApiResponse.completed(await _service.getAccount());
|
||||||
|
} catch (e) {
|
||||||
|
if (e.toString().contains('session is blocked')) {
|
||||||
|
_apiResponse = ApiResponse.error('Sitzung ist abgelaufen');
|
||||||
|
messenger.showSnackBar(SnackBar(
|
||||||
|
backgroundColor: CustomColors.error,
|
||||||
|
content: const Text(
|
||||||
|
'Sitzung ist abgelaufen',
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
action: SnackBarAction(
|
||||||
|
label: 'Details',
|
||||||
|
onPressed: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
backgroundColor: Colors.black,
|
||||||
|
icon: Icon(
|
||||||
|
Icons.error,
|
||||||
|
color: CustomColors.error,
|
||||||
|
),
|
||||||
|
content: Text(
|
||||||
|
e.toString(),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
messenger.showSnackBar(SnackBar(
|
||||||
|
backgroundColor: CustomColors.error,
|
||||||
|
content: const Text(
|
||||||
|
'Sitzung ist abgelaufen',
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
action: SnackBarAction(
|
||||||
|
label: 'Details',
|
||||||
|
onPressed: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
backgroundColor: Colors.black,
|
||||||
|
icon: Icon(
|
||||||
|
Icons.error,
|
||||||
|
color: CustomColors.error,
|
||||||
|
),
|
||||||
|
content: Text(
|
||||||
|
e.toString(),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
));
|
||||||
|
_apiResponse = ApiResponse.error(e.toString());
|
||||||
|
}
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> logout() async {
|
||||||
|
_apiResponse = ApiResponse.loading('Logge aus');
|
||||||
|
notifyListeners();
|
||||||
|
try {
|
||||||
|
await BackendService.logout();
|
||||||
|
_apiResponse = ApiResponse.completed(true);
|
||||||
|
} catch (e) {
|
||||||
|
_apiResponse = ApiResponse.error(e.toString());
|
||||||
|
}
|
||||||
|
print(_apiResponse.message);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> login(BuildContext context,
|
||||||
|
{required String email, required String password}) async {
|
||||||
|
bool resp = false;
|
||||||
|
_apiResponse = ApiResponse.loading('Logge ein');
|
||||||
|
notifyListeners();
|
||||||
|
final messenger = ScaffoldMessenger.of(context);
|
||||||
|
try {
|
||||||
|
resp = await BackendService.login(email: email, password: password);
|
||||||
|
_apiResponse = ApiResponse.completed(resp);
|
||||||
|
messenger.showSnackBar(SnackBar(
|
||||||
|
backgroundColor: CustomColors.success,
|
||||||
|
content: const Text(
|
||||||
|
'Erfolgreich eingeloggt',
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
} catch (e) {
|
||||||
|
messenger.showSnackBar(SnackBar(
|
||||||
|
backgroundColor: CustomColors.error,
|
||||||
|
content: const Text(
|
||||||
|
'Login fehlgeschlagen',
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
action: SnackBarAction(
|
||||||
|
label: 'Details',
|
||||||
|
onPressed: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
backgroundColor: Colors.black,
|
||||||
|
icon: Icon(
|
||||||
|
Icons.error,
|
||||||
|
color: CustomColors.error,
|
||||||
|
),
|
||||||
|
content: Text(
|
||||||
|
e.toString(),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
));
|
||||||
|
_apiResponse = ApiResponse.error(e.toString());
|
||||||
|
}
|
||||||
|
print(_apiResponse.message);
|
||||||
|
notifyListeners();
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> createAccount(BuildContext context,
|
||||||
|
{required String email, required String password}) async {
|
||||||
|
bool resp = false;
|
||||||
|
final messenger = ScaffoldMessenger.of(context);
|
||||||
|
|
||||||
|
_apiResponse = ApiResponse.loading('Logge ein');
|
||||||
|
notifyListeners();
|
||||||
|
try {
|
||||||
|
resp =
|
||||||
|
await BackendService.createAccount(email: email, password: password);
|
||||||
|
messenger.showSnackBar(SnackBar(
|
||||||
|
backgroundColor: CustomColors.success,
|
||||||
|
content: const Text(
|
||||||
|
'Account angelegt',
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
_apiResponse = ApiResponse.completed(resp);
|
||||||
|
} catch (e) {
|
||||||
|
messenger.showSnackBar(SnackBar(
|
||||||
|
backgroundColor: CustomColors.error,
|
||||||
|
content: const Text(
|
||||||
|
'Account anlegen fehlgeschlagen',
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
action: SnackBarAction(
|
||||||
|
label: 'Details',
|
||||||
|
onPressed: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
backgroundColor: Colors.black,
|
||||||
|
icon: Icon(
|
||||||
|
Icons.error,
|
||||||
|
color: CustomColors.error,
|
||||||
|
),
|
||||||
|
content: Text(
|
||||||
|
e.toString(),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
));
|
||||||
|
_apiResponse = ApiResponse.error(e.toString());
|
||||||
|
}
|
||||||
|
print(_apiResponse.message);
|
||||||
|
notifyListeners();
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
import 'package:app/model/apis/api_response.dart';
|
import 'package:app/model/apis/api_response.dart';
|
||||||
import 'package:app/model/services/backend_service.dart';
|
import 'package:app/model/services/backend_service.dart';
|
||||||
import 'package:app/pb/account.pb.dart';
|
|
||||||
import 'package:app/pb/person.pb.dart';
|
import 'package:app/pb/person.pb.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
@ -16,14 +15,43 @@ class PersonsViewModel with ChangeNotifier {
|
|||||||
return _apiResponse;
|
return _apiResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
void listPersons() async {
|
Future<List<Person>> listPersons() async {
|
||||||
_apiResponse = ApiResponse.loading('Bereite alles vor');
|
List<Person> persons = [];
|
||||||
|
_apiResponse = ApiResponse.loading('Lade Daten');
|
||||||
try {
|
try {
|
||||||
_apiResponse =
|
persons = await _service.listPersons();
|
||||||
ApiResponse.completed(await _service.listPersons(), 'done');
|
_apiResponse = ApiResponse.completed(persons);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_apiResponse = ApiResponse.error(e.toString());
|
_apiResponse = ApiResponse.error(e.toString());
|
||||||
}
|
}
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
return persons;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Person> createPerson(BuildContext context,
|
||||||
|
{required String firstname,
|
||||||
|
required String lastname,
|
||||||
|
required String street,
|
||||||
|
required String zip,
|
||||||
|
required String city,
|
||||||
|
required String country,
|
||||||
|
required DateTime birthday}) async {
|
||||||
|
Person person = Person();
|
||||||
|
_apiResponse = ApiResponse.loading('Erstelle Person');
|
||||||
|
try {
|
||||||
|
person = await _service.createPerson(
|
||||||
|
firstname: firstname,
|
||||||
|
lastname: lastname,
|
||||||
|
street: street,
|
||||||
|
zip: zip,
|
||||||
|
city: city,
|
||||||
|
country: country,
|
||||||
|
birthday: birthday);
|
||||||
|
_apiResponse = ApiResponse.completed(person);
|
||||||
|
} catch (err) {
|
||||||
|
_apiResponse = ApiResponse.error(err.toString());
|
||||||
|
}
|
||||||
|
notifyListeners();
|
||||||
|
return person;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'package:app/model/apis/api_response.dart';
|
|
||||||
import 'package:app/model/services/backend_service.dart';
|
import 'package:app/model/services/backend_service.dart';
|
||||||
import 'package:app/model/view_model/account_vm.dart';
|
import 'package:app/model/view_model/account_vm.dart';
|
||||||
import 'package:app/pages/login_overlay.dart';
|
import 'package:app/pages/login_overlay.dart';
|
||||||
@ -11,8 +10,11 @@ import 'package:app/widgets/side_drawer_item.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
// ignore: must_be_immutable
|
||||||
class HomePage extends StatefulWidget {
|
class HomePage extends StatefulWidget {
|
||||||
const HomePage({super.key});
|
HomePage({super.key, required this.loggedOut});
|
||||||
|
|
||||||
|
bool loggedOut;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<HomePage> createState() => _HomePageState();
|
State<HomePage> createState() => _HomePageState();
|
||||||
@ -25,182 +27,192 @@ class _HomePageState extends State<HomePage> {
|
|||||||
_init();
|
_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AccountViewModel vm = AccountViewModel();
|
||||||
void _init() async {
|
void _init() async {
|
||||||
_setLoading(true);
|
// _setLoading(true);
|
||||||
_loggedin = await BackendService.isLoggedIn;
|
// _setLoading(widget.loggedOut);
|
||||||
|
// _loading = widget.loggedOut;
|
||||||
|
// _loggedin = await BackendService.isLoggedIn;
|
||||||
// if (!_loggedin) {
|
// if (!_loggedin) {
|
||||||
// await BackendService.logout();
|
// await BackendService.logout();
|
||||||
// Navigator.of(context).pushAndRemoveUntil(
|
// final navigator = Navigator.of(context);
|
||||||
// MaterialPageRoute(builder: (builder) => HomePage()),
|
// navigator.pushAndRemoveUntil(
|
||||||
|
// MaterialPageRoute(
|
||||||
|
// builder: (builder) => HomePage(
|
||||||
|
// loggedOut: true,
|
||||||
|
// )),
|
||||||
// (route) => false);
|
// (route) => false);
|
||||||
// }
|
// }
|
||||||
_setLoading(false);
|
_setLoading(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_isLoggedIn(BuildContext context) async {
|
||||||
|
bool logged = await vm.isLoggedIn(context);
|
||||||
|
_loggedin = logged;
|
||||||
|
}
|
||||||
|
|
||||||
void _setLoading(bool loading) {
|
void _setLoading(bool loading) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_loading = loading;
|
_loading = loading;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _checkResponse(ApiResponse response) async {
|
|
||||||
print('${response.message}');
|
|
||||||
if (response.status == Status.ERROR &&
|
|
||||||
response.message!.contains('unauthorized')) {
|
|
||||||
await BackendService.logout();
|
|
||||||
Navigator.of(context).pushAndRemoveUntil(
|
|
||||||
MaterialPageRoute(builder: (builder) => const HomePage()),
|
|
||||||
(route) => false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
bool _loggedin = false;
|
bool _loggedin = false;
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Background(
|
return Background(
|
||||||
child: ChangeNotifierProvider<AccountViewModel>(
|
child: Scaffold(
|
||||||
create: (context) => AccountViewModel(),
|
appBar: AppBar(
|
||||||
child: Consumer<AccountViewModel>(
|
automaticallyImplyLeading: false,
|
||||||
builder: (context, value, child) {
|
// flexibleSpace: Image.asset(
|
||||||
_checkResponse(value.response);
|
// 'lib/assets/logo_300x200.png',
|
||||||
return Scaffold(
|
// // height: 400,
|
||||||
appBar: AppBar(
|
// ),
|
||||||
automaticallyImplyLeading: false,
|
),
|
||||||
// flexibleSpace: Image.asset(
|
drawer: SideDrawer(
|
||||||
// 'lib/assets/logo_300x200.png',
|
children: [
|
||||||
// // height: 400,
|
const Spacer(
|
||||||
// ),
|
flex: 3,
|
||||||
),
|
),
|
||||||
drawer: SideDrawer(
|
SideDrawerItem(
|
||||||
children: [
|
onPressed: () {},
|
||||||
const Spacer(
|
icon: Icons.question_answer,
|
||||||
flex: 3,
|
color: Colors.white,
|
||||||
),
|
label: 'About',
|
||||||
SideDrawerItem(
|
),
|
||||||
onPressed: () {},
|
SideDrawerItem(
|
||||||
icon: Icons.question_answer,
|
onPressed: () {},
|
||||||
color: Colors.white,
|
icon: Icons.privacy_tip,
|
||||||
label: 'About',
|
color: Colors.white,
|
||||||
),
|
label: 'Datenschutz',
|
||||||
SideDrawerItem(
|
),
|
||||||
onPressed: () {},
|
SideDrawerItem(
|
||||||
icon: Icons.privacy_tip,
|
onPressed: () {},
|
||||||
color: Colors.white,
|
icon: Icons.apartment,
|
||||||
label: 'Datenschutz',
|
color: Colors.white,
|
||||||
),
|
label: 'Impressum',
|
||||||
SideDrawerItem(
|
),
|
||||||
onPressed: () {},
|
const Spacer(
|
||||||
icon: Icons.apartment,
|
flex: 1,
|
||||||
color: Colors.white,
|
),
|
||||||
label: 'Impressum',
|
if (_loggedin)
|
||||||
),
|
SideDrawerItem(
|
||||||
const Spacer(
|
onPressed: () async {
|
||||||
flex: 1,
|
setState(() {
|
||||||
),
|
_loading = true;
|
||||||
if (_loggedin && value.response.data != null)
|
});
|
||||||
SideDrawerItem(
|
await BackendService.logout();
|
||||||
onPressed: () async {
|
// ignore: use_build_context_synchronously
|
||||||
setState(() {
|
Navigator.of(context).pushAndRemoveUntil(
|
||||||
_loading = true;
|
MaterialPageRoute(
|
||||||
});
|
builder: (builder) => HomePage(
|
||||||
await BackendService.logout();
|
loggedOut: true,
|
||||||
// ignore: use_build_context_synchronously
|
)),
|
||||||
Navigator.of(context).pushAndRemoveUntil(
|
(route) => false);
|
||||||
MaterialPageRoute(
|
setState(() {
|
||||||
builder: (builder) => const HomePage()),
|
_loggedin = false;
|
||||||
(route) => false);
|
_loading = false;
|
||||||
setState(() {
|
});
|
||||||
_loggedin = false;
|
},
|
||||||
_loading = false;
|
icon: Icons.logout,
|
||||||
});
|
color: Colors.white,
|
||||||
},
|
label: 'Logout',
|
||||||
icon: Icons.logout,
|
),
|
||||||
color: Colors.white,
|
],
|
||||||
label: 'Logout',
|
),
|
||||||
),
|
bottomNavigationBar: BottomNavigation(
|
||||||
],
|
children: [
|
||||||
),
|
if (!_loggedin) ...[
|
||||||
bottomNavigationBar: BottomNavigation(
|
BottomNavigationItem(
|
||||||
children: [
|
onPressed: () async {
|
||||||
if (!_loggedin) ...[
|
final bool res = await showLogin(context, registration: true);
|
||||||
BottomNavigationItem(
|
setState(() {
|
||||||
onPressed: () async {
|
_loggedin = res;
|
||||||
final bool res =
|
});
|
||||||
await showLogin(context, registration: true);
|
},
|
||||||
setState(() {
|
icon: Icons.person_add_alt,
|
||||||
_loggedin = res;
|
color: Colors.white,
|
||||||
});
|
label: 'Registrieren',
|
||||||
},
|
),
|
||||||
icon: Icons.person_add_alt,
|
BottomNavigationItem(
|
||||||
color: Colors.white,
|
onPressed: () async {
|
||||||
label: 'Registrieren',
|
await showLogin(context);
|
||||||
),
|
setState(() {
|
||||||
BottomNavigationItem(
|
vm.isLoggedIn(context);
|
||||||
onPressed: () async {
|
});
|
||||||
final bool res = await showLogin(context);
|
},
|
||||||
setState(() {
|
icon: Icons.login,
|
||||||
_loggedin = res;
|
color: Colors.white,
|
||||||
});
|
label: 'Login',
|
||||||
},
|
),
|
||||||
icon: Icons.login,
|
] else
|
||||||
color: Colors.white,
|
BottomNavigationItem(
|
||||||
label: 'Login',
|
onPressed: () async {
|
||||||
),
|
final navigator = Navigator.of(context);
|
||||||
] else
|
if (await vm.isLoggedIn(context)) {
|
||||||
BottomNavigationItem(
|
navigator.push(MaterialPageRoute(
|
||||||
onPressed: () {
|
builder: (builder) => const PersonsPage()));
|
||||||
Navigator.of(context).push(MaterialPageRoute(
|
} else {
|
||||||
builder: (builder) => const PersonsPage()));
|
navigator.pushAndRemoveUntil(
|
||||||
},
|
MaterialPageRoute(
|
||||||
icon: Icons.person_search,
|
builder: (builder) => const PersonsPage()),
|
||||||
color: Colors.white,
|
(route) => false);
|
||||||
label: 'Personen',
|
}
|
||||||
),
|
},
|
||||||
BottomNavigationItem(
|
icon: Icons.person_search,
|
||||||
onPressed: () {},
|
color: Colors.white,
|
||||||
icon: Icons.dashboard,
|
label: 'Personen',
|
||||||
color: Colors.white,
|
),
|
||||||
label: 'Dashboard',
|
BottomNavigationItem(
|
||||||
),
|
onPressed: () {},
|
||||||
...[]
|
icon: Icons.dashboard,
|
||||||
],
|
color: Colors.white,
|
||||||
),
|
label: 'Dashboard',
|
||||||
body: Padding(
|
),
|
||||||
padding: const EdgeInsets.fromLTRB(16, 40, 16, 16),
|
...[]
|
||||||
child: Center(
|
],
|
||||||
child: _loading
|
),
|
||||||
? const CircularProgressIndicator(
|
body: Padding(
|
||||||
color: Colors.grey,
|
padding: const EdgeInsets.fromLTRB(16, 45, 16, 16),
|
||||||
)
|
child: Center(
|
||||||
: Column(
|
child: ChangeNotifierProvider<AccountViewModel>(
|
||||||
children: [
|
create: (context) => AccountViewModel(),
|
||||||
Image.asset(
|
child:
|
||||||
'lib/assets/logo_300x200.png',
|
Consumer<AccountViewModel>(builder: (context, value, child) {
|
||||||
|
// _checkResponse(value.response);
|
||||||
|
if (!widget.loggedOut) {
|
||||||
|
_isLoggedIn(context);
|
||||||
|
}
|
||||||
|
return _loading
|
||||||
|
? const CircularProgressIndicator(
|
||||||
|
color: Colors.grey,
|
||||||
|
)
|
||||||
|
: Column(
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
'lib/assets/logo_300x200.png',
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 40,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Digitale Spuren auf Knopfdruck entfernen'
|
||||||
|
.toUpperCase(),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'sans-serif',
|
||||||
|
fontSize: 24,
|
||||||
|
height: 1.6,
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
|
letterSpacing: 6,
|
||||||
),
|
),
|
||||||
const SizedBox(
|
),
|
||||||
height: 40,
|
],
|
||||||
),
|
);
|
||||||
Text(
|
})),
|
||||||
'Digitale Spuren auf Knopfdruck entfernen'
|
|
||||||
.toUpperCase(),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontFamily: 'sans-serif',
|
|
||||||
fontSize: 24,
|
|
||||||
height: 1.6,
|
|
||||||
fontWeight: FontWeight.normal,
|
|
||||||
letterSpacing: 6,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
import 'package:app/model/services/backend_service.dart';
|
import 'package:app/model/view_model/base_vm.dart';
|
||||||
import 'package:app/widgets/background.dart';
|
import 'package:app/widgets/background.dart';
|
||||||
|
import 'package:app/widgets/bottom_navigation.dart';
|
||||||
|
import 'package:app/widgets/bottom_navigation_item.dart';
|
||||||
|
import 'package:app/widgets/side_drawer.dart';
|
||||||
|
import 'package:app/widgets/side_drawer_item.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:app/util/validation.dart';
|
import 'package:app/util/validation.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
Future<bool> showLogin(BuildContext context,
|
Future<bool> showLogin(BuildContext context,
|
||||||
{bool registration = false}) async {
|
{bool registration = false}) async {
|
||||||
@ -9,15 +14,17 @@ Future<bool> showLogin(BuildContext context,
|
|||||||
final mailController = TextEditingController();
|
final mailController = TextEditingController();
|
||||||
final passwordController = TextEditingController();
|
final passwordController = TextEditingController();
|
||||||
|
|
||||||
|
BaseViewModel vm = BaseViewModel();
|
||||||
bool submitted = false;
|
bool submitted = false;
|
||||||
bool loggedin = false;
|
bool loggedin = false;
|
||||||
void login() {
|
void login(BuildContext context) {
|
||||||
if (formKey.currentState!.validate()) {
|
if (formKey.currentState!.validate()) {
|
||||||
submitted = true;
|
submitted = true;
|
||||||
BackendService.login(
|
FocusScope.of(context).unfocus();
|
||||||
email: mailController.text,
|
vm
|
||||||
password: passwordController.text,
|
.login(context,
|
||||||
).then(
|
email: mailController.text, password: passwordController.text)
|
||||||
|
.then(
|
||||||
(r) {
|
(r) {
|
||||||
if (r) {
|
if (r) {
|
||||||
loggedin = r;
|
loggedin = r;
|
||||||
@ -25,16 +32,21 @@ Future<bool> showLogin(BuildContext context,
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
passwordController.clear();
|
||||||
|
submitted = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void register() {
|
void register(BuildContext context) {
|
||||||
if (formKey.currentState!.validate()) {
|
if (formKey.currentState!.validate()) {
|
||||||
submitted = true;
|
submitted = true;
|
||||||
BackendService.createAccount(
|
vm
|
||||||
|
.createAccount(
|
||||||
|
context,
|
||||||
email: mailController.text,
|
email: mailController.text,
|
||||||
password: passwordController.text,
|
password: passwordController.text,
|
||||||
).then(
|
)
|
||||||
|
.then(
|
||||||
(r) {
|
(r) {
|
||||||
if (r) {
|
if (r) {
|
||||||
loggedin = r;
|
loggedin = r;
|
||||||
@ -52,120 +64,174 @@ Future<bool> showLogin(BuildContext context,
|
|||||||
context: context,
|
context: context,
|
||||||
builder: (builder) {
|
builder: (builder) {
|
||||||
return Background(
|
return Background(
|
||||||
child: Column(
|
child: Scaffold(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
drawer: SideDrawer(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(
|
const Spacer(
|
||||||
height: 50,
|
flex: 3,
|
||||||
),
|
|
||||||
const Image(
|
|
||||||
width: 180,
|
|
||||||
image: AssetImage(
|
|
||||||
'lib/assets/logo_300x200.png',
|
|
||||||
),
|
),
|
||||||
),
|
SideDrawerItem(
|
||||||
const SizedBox(
|
onPressed: () {},
|
||||||
height: 30,
|
icon: Icons.question_answer,
|
||||||
),
|
color: Colors.white,
|
||||||
Text(
|
label: 'About',
|
||||||
registration ? 'Registrieren' : 'Login',
|
|
||||||
style: const TextStyle(
|
|
||||||
fontFamily: 'sans-serif',
|
|
||||||
fontSize: 24,
|
|
||||||
height: 1.6,
|
|
||||||
fontWeight: FontWeight.normal,
|
|
||||||
letterSpacing: 6,
|
|
||||||
),
|
),
|
||||||
),
|
SideDrawerItem(
|
||||||
Form(
|
onPressed: () {},
|
||||||
key: formKey,
|
icon: Icons.privacy_tip,
|
||||||
child: Column(
|
color: Colors.white,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
label: 'Datenschutz',
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
),
|
||||||
children: [
|
SideDrawerItem(
|
||||||
const SizedBox(
|
onPressed: () {},
|
||||||
height: 40,
|
icon: Icons.apartment,
|
||||||
|
color: Colors.white,
|
||||||
|
label: 'Impressum',
|
||||||
|
),
|
||||||
|
const Spacer(
|
||||||
|
flex: 1,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
bottomNavigationBar: BottomNavigation(
|
||||||
|
children: [
|
||||||
|
BottomNavigationItem(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context, false);
|
||||||
|
},
|
||||||
|
icon: Icons.arrow_back,
|
||||||
|
color: Colors.white,
|
||||||
|
label: 'Zurück',
|
||||||
|
),
|
||||||
|
BottomNavigationItem(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context, false);
|
||||||
|
},
|
||||||
|
icon: Icons.home,
|
||||||
|
color: Colors.white,
|
||||||
|
label: 'Home',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const SizedBox(
|
||||||
|
height: 50,
|
||||||
|
),
|
||||||
|
const Image(
|
||||||
|
width: 180,
|
||||||
|
image: AssetImage(
|
||||||
|
'lib/assets/logo_300x200.png',
|
||||||
),
|
),
|
||||||
TextFormField(
|
),
|
||||||
autofocus: true,
|
const SizedBox(
|
||||||
// inputFormatters: [
|
height: 30,
|
||||||
// FilteringTextInputFormatter.allow(
|
),
|
||||||
// emailRegExp,
|
Text(
|
||||||
// ),
|
registration ? 'Registrieren' : 'Login',
|
||||||
// ],
|
style: const TextStyle(
|
||||||
controller: mailController,
|
fontFamily: 'sans-serif',
|
||||||
decoration: const InputDecoration(
|
fontSize: 24,
|
||||||
fillColor: Color.fromARGB(30, 255, 255, 255),
|
height: 1.6,
|
||||||
filled: true,
|
fontWeight: FontWeight.normal,
|
||||||
hintStyle: TextStyle(
|
letterSpacing: 6,
|
||||||
color: Colors.white38,
|
|
||||||
),
|
|
||||||
hintText: 'E-Mail Adresse',
|
|
||||||
),
|
|
||||||
keyboardType: TextInputType.emailAddress,
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null || !value.isValidEmail) {
|
|
||||||
return 'Bitte eine gültige E-Mail Adresse eingeben';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
TextFormField(
|
),
|
||||||
style: const TextStyle(
|
ChangeNotifierProvider<BaseViewModel>(
|
||||||
color: Colors.white,
|
create: (context) => BaseViewModel(),
|
||||||
),
|
child: Consumer<BaseViewModel>(
|
||||||
// inputFormatters: [
|
builder: (context, value, child) => Form(
|
||||||
// FilteringTextInputFormatter.allow(
|
key: formKey,
|
||||||
// passwordRegExp,
|
child: Column(
|
||||||
// ),
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
// ],
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
controller: passwordController,
|
children: [
|
||||||
decoration: const InputDecoration(
|
const SizedBox(
|
||||||
fillColor: Color.fromARGB(30, 255, 255, 255),
|
height: 40,
|
||||||
filled: true,
|
),
|
||||||
hintStyle: TextStyle(
|
TextFormField(
|
||||||
color: Colors.white38,
|
// autofocus: true,
|
||||||
),
|
// inputFormatters: [
|
||||||
hintText: 'Passwort',
|
// FilteringTextInputFormatter.allow(
|
||||||
),
|
// emailRegExp,
|
||||||
keyboardType: TextInputType.visiblePassword,
|
// ),
|
||||||
obscureText: true,
|
// ],
|
||||||
validator: (value) {
|
controller: mailController,
|
||||||
if (value == null || !value.isValidPassword) {
|
decoration: const InputDecoration(
|
||||||
return 'Bitte geben Sie Ihr Passwort ein';
|
fillColor: Color.fromARGB(30, 255, 255, 255),
|
||||||
}
|
filled: true,
|
||||||
return null;
|
hintStyle: TextStyle(
|
||||||
},
|
color: Colors.white38,
|
||||||
),
|
),
|
||||||
const SizedBox(
|
hintText: 'E-Mail Adresse',
|
||||||
height: 15,
|
),
|
||||||
),
|
keyboardType: TextInputType.emailAddress,
|
||||||
Row(
|
validator: (value) {
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
if (value == null || !value.isValidEmail) {
|
||||||
children: [
|
return 'Bitte eine gültige E-Mail Adresse eingeben';
|
||||||
ElevatedButton(
|
|
||||||
onPressed: !submitted
|
|
||||||
? () {
|
|
||||||
Navigator.pop(context);
|
|
||||||
}
|
}
|
||||||
: null,
|
return null;
|
||||||
child: const Icon(Icons.arrow_back),
|
},
|
||||||
|
),
|
||||||
|
TextFormField(
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
// inputFormatters: [
|
||||||
|
// FilteringTextInputFormatter.allow(
|
||||||
|
// passwordRegExp,
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
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.isValidPassword) {
|
||||||
|
return 'Bitte geben Sie Ihr Passwort ein';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 15,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: !submitted
|
||||||
|
? !registration
|
||||||
|
? () {
|
||||||
|
login(context);
|
||||||
|
}
|
||||||
|
: () {
|
||||||
|
register(context);
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
child: const Icon(Icons.login),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
),
|
||||||
onPressed: !submitted
|
),
|
||||||
? !registration
|
),
|
||||||
? login
|
const Spacer(),
|
||||||
: register
|
],
|
||||||
: null,
|
|
||||||
child: const Icon(Icons.login),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const Spacer(),
|
),
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -42,13 +42,23 @@ class _PersonsPageState extends State<PersonsPage> {
|
|||||||
response.message!.contains('unauthenticated')) {
|
response.message!.contains('unauthenticated')) {
|
||||||
BackendService.logout();
|
BackendService.logout();
|
||||||
Navigator.of(context).pushAndRemoveUntil(
|
Navigator.of(context).pushAndRemoveUntil(
|
||||||
MaterialPageRoute(builder: (builder) => const HomePage()),
|
MaterialPageRoute(
|
||||||
|
builder: (builder) => HomePage(
|
||||||
|
loggedOut: true,
|
||||||
|
)),
|
||||||
(route) => false);
|
(route) => false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
bool _loggedin = false;
|
bool _loggedin = false;
|
||||||
|
List<Person> persons = [];
|
||||||
|
|
||||||
|
PersonsViewModel vm = PersonsViewModel();
|
||||||
|
|
||||||
|
void listPersons(BuildContext context) async {
|
||||||
|
persons = await vm.listPersons();
|
||||||
|
}
|
||||||
|
|
||||||
List<Widget> _personsList(List<Person> persons) {
|
List<Widget> _personsList(List<Person> persons) {
|
||||||
final List<Widget> list = [];
|
final List<Widget> list = [];
|
||||||
@ -67,106 +77,106 @@ class _PersonsPageState extends State<PersonsPage> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Background(
|
return Background(
|
||||||
child: ChangeNotifierProvider<PersonsViewModel>(
|
child: Scaffold(
|
||||||
create: (context) => PersonsViewModel(),
|
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
|
||||||
child: Consumer<PersonsViewModel>(
|
floatingActionButton: FloatingActionButton(
|
||||||
builder: (context, value, child) {
|
onPressed: () {},
|
||||||
_checkResponse(value.response);
|
child: const Icon(Icons.add),
|
||||||
return Scaffold(
|
),
|
||||||
floatingActionButtonLocation:
|
appBar: AppBar(
|
||||||
FloatingActionButtonLocation.centerFloat,
|
automaticallyImplyLeading: false,
|
||||||
floatingActionButton: FloatingActionButton(
|
),
|
||||||
onPressed: () {},
|
drawer: SideDrawer(
|
||||||
child: const Icon(Icons.add),
|
children: [
|
||||||
|
const Spacer(
|
||||||
|
flex: 3,
|
||||||
|
),
|
||||||
|
SideDrawerItem(
|
||||||
|
onPressed: () {},
|
||||||
|
icon: Icons.question_answer,
|
||||||
|
color: Colors.white,
|
||||||
|
label: 'About',
|
||||||
|
),
|
||||||
|
SideDrawerItem(
|
||||||
|
onPressed: () {},
|
||||||
|
icon: Icons.privacy_tip,
|
||||||
|
color: Colors.white,
|
||||||
|
label: 'Datenschutz',
|
||||||
|
),
|
||||||
|
SideDrawerItem(
|
||||||
|
onPressed: () {},
|
||||||
|
icon: Icons.apartment,
|
||||||
|
color: Colors.white,
|
||||||
|
label: 'Impressum',
|
||||||
|
),
|
||||||
|
const Spacer(
|
||||||
|
flex: 1,
|
||||||
|
),
|
||||||
|
if (_loggedin)
|
||||||
|
SideDrawerItem(
|
||||||
|
onPressed: () async {
|
||||||
|
setState(() {
|
||||||
|
_loading = true;
|
||||||
|
});
|
||||||
|
await BackendService.logout();
|
||||||
|
// ignore: use_build_context_synchronously
|
||||||
|
Navigator.of(context).pushAndRemoveUntil(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (builder) => HomePage(
|
||||||
|
loggedOut: true,
|
||||||
|
)),
|
||||||
|
(route) => false);
|
||||||
|
setState(() {
|
||||||
|
_loggedin = false;
|
||||||
|
_loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
icon: Icons.logout,
|
||||||
|
color: Colors.white,
|
||||||
|
label: 'Logout',
|
||||||
),
|
),
|
||||||
appBar: AppBar(
|
],
|
||||||
automaticallyImplyLeading: false,
|
),
|
||||||
),
|
bottomNavigationBar: BottomNavigation(
|
||||||
drawer: SideDrawer(
|
children: [
|
||||||
children: [
|
BottomNavigationItem(
|
||||||
const Spacer(
|
onPressed: () {},
|
||||||
flex: 3,
|
icon: Icons.dashboard,
|
||||||
),
|
color: Colors.white,
|
||||||
SideDrawerItem(
|
label: 'Dashboard',
|
||||||
onPressed: () {},
|
),
|
||||||
icon: Icons.question_answer,
|
BottomNavigationItem(
|
||||||
color: Colors.white,
|
onPressed: () {
|
||||||
label: 'About',
|
Navigator.of(context).pop();
|
||||||
),
|
},
|
||||||
SideDrawerItem(
|
icon: Icons.home,
|
||||||
onPressed: () {},
|
color: Colors.white,
|
||||||
icon: Icons.privacy_tip,
|
label: 'Home',
|
||||||
color: Colors.white,
|
),
|
||||||
label: 'Datenschutz',
|
],
|
||||||
),
|
),
|
||||||
SideDrawerItem(
|
body: Padding(
|
||||||
onPressed: () {},
|
padding: const EdgeInsets.all(16),
|
||||||
icon: Icons.apartment,
|
child: Center(
|
||||||
color: Colors.white,
|
child: ChangeNotifierProvider<PersonsViewModel>(
|
||||||
label: 'Impressum',
|
create: (context) => PersonsViewModel(),
|
||||||
),
|
child: Consumer<PersonsViewModel>(
|
||||||
const Spacer(
|
builder: (context, value, child) {
|
||||||
flex: 1,
|
_checkResponse(value.response);
|
||||||
),
|
listPersons(context);
|
||||||
if (_loggedin || value.response.data != null)
|
return _loading
|
||||||
SideDrawerItem(
|
|
||||||
onPressed: () async {
|
|
||||||
setState(() {
|
|
||||||
_loading = true;
|
|
||||||
});
|
|
||||||
await BackendService.logout();
|
|
||||||
// ignore: use_build_context_synchronously
|
|
||||||
Navigator.of(context).pushAndRemoveUntil(
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (builder) => const HomePage()),
|
|
||||||
(route) => false);
|
|
||||||
setState(() {
|
|
||||||
_loggedin = false;
|
|
||||||
_loading = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
icon: Icons.logout,
|
|
||||||
color: Colors.white,
|
|
||||||
label: 'Logout',
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
bottomNavigationBar: BottomNavigation(
|
|
||||||
children: [
|
|
||||||
BottomNavigationItem(
|
|
||||||
onPressed: () {},
|
|
||||||
icon: Icons.dashboard,
|
|
||||||
color: Colors.white,
|
|
||||||
label: 'Dashboard',
|
|
||||||
),
|
|
||||||
BottomNavigationItem(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
icon: Icons.home,
|
|
||||||
color: Colors.white,
|
|
||||||
label: 'Home',
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
body: Padding(
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
child: Center(
|
|
||||||
child: _loading
|
|
||||||
? const CircularProgressIndicator(
|
? const CircularProgressIndicator(
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
)
|
)
|
||||||
: value.response.status == Status.COMPLETED
|
: value.response.status == Status.COMPLETED
|
||||||
? value.response.data.length > 0
|
? value.response.data.length > 0
|
||||||
? ListView(
|
? ListView(children: _personsList(persons))
|
||||||
children: _personsList(
|
|
||||||
(value.response.data as List<Person>)))
|
|
||||||
: const Text('Noch keine Personen angelegt')
|
: const Text('Noch keine Personen angelegt')
|
||||||
: const Text('Lade Daten...'),
|
: const Text('Lade Daten...');
|
||||||
),
|
},
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
},
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
11
frontend/app/lib/util/colors.dart
Normal file
11
frontend/app/lib/util/colors.dart
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class CustomColors {
|
||||||
|
static Color get error {
|
||||||
|
return const Color.fromARGB(200, 255, 90, 90);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Color get success {
|
||||||
|
return const Color.fromARGB(200, 55, 125, 55);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
// ignore: must_be_immutable
|
||||||
class BottomNavigation extends StatelessWidget {
|
class BottomNavigation extends StatelessWidget {
|
||||||
BottomNavigation({
|
BottomNavigation({
|
||||||
super.key,
|
super.key,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
// ignore: must_be_immutable
|
||||||
class BottomNavigationItem extends StatelessWidget {
|
class BottomNavigationItem extends StatelessWidget {
|
||||||
BottomNavigationItem({
|
BottomNavigationItem({
|
||||||
super.key,
|
super.key,
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import 'package:app/pages/home_page.dart';
|
|
||||||
import 'package:app/widgets/side_drawer_item.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
// ignore: must_be_immutable
|
||||||
class SideDrawer extends StatelessWidget {
|
class SideDrawer extends StatelessWidget {
|
||||||
SideDrawer({super.key, required this.children, this.backgroundColor}) {
|
SideDrawer({super.key, required this.children, this.backgroundColor}) {
|
||||||
backgroundColor ??= Colors.black;
|
backgroundColor ??= Colors.black;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> children;
|
final List<Widget> children;
|
||||||
Color? backgroundColor;
|
Color? backgroundColor;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:app/pages/home_page.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
// ignore: must_be_immutable
|
||||||
class SideDrawerItem extends StatelessWidget {
|
class SideDrawerItem extends StatelessWidget {
|
||||||
SideDrawerItem({
|
SideDrawerItem({
|
||||||
super.key,
|
super.key,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user