ft/adds persistent app state up to mail verification

This commit is contained in:
itsscb 2023-11-12 23:55:20 +01:00
parent d0b93581b2
commit df74e8e12f
9 changed files with 1004 additions and 710 deletions

View File

@ -1,9 +1,6 @@
import 'package:app/model/services/auth_service.dart'; import 'package:app/model/services/auth_service.dart';
import 'package:app/model/services/storage_service.dart'; import 'package:app/model/services/storage_service.dart';
import 'package:app/pages/notifications_page.dart';
import 'package:app/pages/start_page.dart'; import 'package:app/pages/start_page.dart';
import 'package:app/pages/verify_email_page.dart';
import 'package:app/pages/registration_page.dart';
import 'package:app/util/colors.dart'; import 'package:app/util/colors.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart' import 'package:flutter_localizations/flutter_localizations.dart'
@ -77,53 +74,39 @@ class _DigitalerFriedenState extends State<DigitalerFrieden> {
void _init() async { void _init() async {
accountLevel = await _storageService.accountLevel; accountLevel = await _storageService.accountLevel;
print(accountLevel!);
if (accountLevel! > 0) { if (accountLevel! > 0) {
authenticated = await AuthService.authenticateWithBiometrics(); authenticated = await AuthService.authenticateWithBiometrics();
} }
setState(() {
_loading = false; _loading = false;
setState(() {}); });
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (_loading) { if (_loading) {
return Center( return SafeArea(
child: Center(
child: Column( child: Column(
children: [ children: [
Image.asset( const SizedBox(
height: 150,
),
Hero(
tag: 'logo',
child: Image.asset(
'assets/JPEG.jpg', 'assets/JPEG.jpg',
height: 180, height: 180,
), ),
),
CircularProgressIndicator( CircularProgressIndicator(
color: CustomColors.primary, color: CustomColors.primary,
), ),
], ],
), ),
),
); );
} }
if (accountLevel == null || accountLevel == 0) {
return const StartPage();
}
// else if (authenticated == null) {
// AuthService.authenticateWithBiometrics().then((value) {
// setState(() {
// authenticated = value;
// });
// });
// }
switch (accountLevel) {
case null:
return const StartPage();
case < 1:
return NotificationsPage();
case 1:
return const RegistrationPage();
case 2:
return VerifyEmailPage();
default:
return const StartPage(); return const StartPage();
} }
} }
}

View File

@ -57,9 +57,9 @@ class StorageService {
Future<int> get accountLevel async { Future<int> get accountLevel async {
int? level; int? level;
final l = await readData('account_level'); final lev = await readData('account_level');
if (l != null) { if (lev != null) {
level = int.tryParse(l); level = int.tryParse(lev);
} }
return level ?? 0; return level ?? 0;
} }

View File

@ -3,25 +3,77 @@ import 'package:app/pages/registration_page.dart';
import 'package:app/util/colors.dart'; import 'package:app/util/colors.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class NotificationsPage extends StatelessWidget { class NotificationsPage extends StatefulWidget {
NotificationsPage({super.key}); const NotificationsPage({super.key});
@override
State<NotificationsPage> createState() => _NotificationsPageState();
}
class _NotificationsPageState extends State<NotificationsPage> {
final StorageService _storageService = StorageService(); final StorageService _storageService = StorageService();
bool _loading = true;
void _setNotificationSetting(bool enabled) { Future<void> _setNotificationSetting(bool enabled) async {
_storageService.addAccountLevel(); await _storageService.setNotificationSetting(enabled);
_storageService.setNotificationSetting(enabled).then( }
(x) => _storageService.notificationSetting.then(
(value) => print('notifications: $value'), @override
), void initState() {
); _init();
super.initState();
}
void _init() async {
final accountLevel = await _storageService.accountLevel;
if (accountLevel > 2 && mounted) {
await Navigator.push(context,
MaterialPageRoute(builder: (builder) => const RegistrationPage()));
setState(() {
_loading = false;
});
} else {
setState(() {
_loading = false;
});
}
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SafeArea( return SafeArea(
child: Scaffold( child: _loading
? Center(
child: Column(
children: [
const SizedBox(
height: 150,
),
Hero(
tag: 'logo',
child: Image.asset(
'assets/JPEG.jpg',
height: 180,
),
),
CircularProgressIndicator(
color: CustomColors.primary,
),
],
),
)
: Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar( appBar: AppBar(
leading: BackButton(
color: CustomColors.primary,
onPressed: () async {
await _storageService.setAccountLevel(1);
if (mounted) {
Navigator.pop(context);
}
},
),
iconTheme: IconThemeData( iconTheme: IconThemeData(
color: CustomColors.primary, color: CustomColors.primary,
), ),
@ -71,8 +123,10 @@ class NotificationsPage extends StatelessWidget {
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: CustomColors.primary, backgroundColor: CustomColors.primary,
), ),
onPressed: () { onPressed: () async {
_setNotificationSetting(true); await _setNotificationSetting(true);
await _storageService.setAccountLevel(3);
if (mounted) {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
@ -80,18 +134,24 @@ class NotificationsPage extends StatelessWidget {
// builder: (builder) => SecurityPage(), // builder: (builder) => SecurityPage(),
), ),
); );
}
}, },
child: const SizedBox( child: const SizedBox(
height: 60, height: 60,
child: Row( child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text( Expanded(
flex: 1,
child: Text(
'Mitteilungen erhalten', 'Mitteilungen erhalten',
textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 20, fontSize: 20,
), ),
), ),
),
], ],
), ),
), ),
@ -101,8 +161,18 @@ class NotificationsPage extends StatelessWidget {
height: 10, height: 10,
), ),
TextButton( TextButton(
onPressed: () { onPressed: () async {
_setNotificationSetting(false); await _setNotificationSetting(false);
await _storageService.setAccountLevel(3);
if (mounted) {
Navigator.push(
context,
MaterialPageRoute(
builder: (builder) => const RegistrationPage(),
// builder: (builder) => SecurityPage(),
),
);
}
}, },
child: Text( child: Text(
'Später', 'Später',

View File

@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
import 'package:app/util/validation.dart'; import 'package:app/util/validation.dart';
class PasswordPage extends StatefulWidget { class PasswordPage extends StatefulWidget {
PasswordPage({super.key, required this.email, required this.register}); const PasswordPage({super.key, required this.email, required this.register});
final String email; final String email;
final bool register; final bool register;
@ -47,15 +47,18 @@ class _PasswordPageState extends State<PasswordPage> {
), ),
body: Padding( body: Padding(
padding: const EdgeInsets.all(20.0), padding: const EdgeInsets.all(20.0),
child: SingleChildScrollView(
child: Form( child: Form(
key: _formKey, key: _formKey,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
const Text( Text(
'Sichere dein Konto mit einem Passwort', widget.register
? 'Sichere dein Konto mit einem Passwort'
: 'Login',
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: const TextStyle(
fontFamily: 'sans-serif', fontFamily: 'sans-serif',
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
letterSpacing: 2.0, letterSpacing: 2.0,
@ -90,6 +93,9 @@ class _PasswordPageState extends State<PasswordPage> {
_validPassword = false; _validPassword = false;
return 'Mindestens 12 Zeichen, Zahlen, Sonderzeichen (-_?!=.,*+), Groß- & Kleinbuchstaben'; return 'Mindestens 12 Zeichen, Zahlen, Sonderzeichen (-_?!=.,*+), Groß- & Kleinbuchstaben';
} else { } else {
if (!widget.register) {
_passwordsFilled = true;
}
_validPassword = true; _validPassword = true;
return null; return null;
} }
@ -102,6 +108,9 @@ class _PasswordPageState extends State<PasswordPage> {
}); });
} else { } else {
setState(() { setState(() {
if (!widget.register) {
_passwordsFilled = true;
}
_validPassword = true; _validPassword = true;
}); });
} }
@ -112,7 +121,7 @@ class _PasswordPageState extends State<PasswordPage> {
), ),
AnimatedSwitcher( AnimatedSwitcher(
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
child: !_validPassword child: !widget.register || !_validPassword
? null ? null
: TextFormField( : TextFormField(
controller: _passwordController2, controller: _passwordController2,
@ -167,7 +176,9 @@ class _PasswordPageState extends State<PasswordPage> {
AnimatedSwitcher( AnimatedSwitcher(
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
child: !_passwordsFilled || child: !_passwordsFilled ||
_passwordController1.text != _passwordController2.text (widget.register &&
_passwordController1.text !=
_passwordController2.text)
? null ? null
: ElevatedButton( : ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
@ -176,32 +187,45 @@ class _PasswordPageState extends State<PasswordPage> {
onPressed: _validPassword && _passwordsFilled onPressed: _validPassword && _passwordsFilled
? () async { ? () async {
if (_formKey.currentState!.validate()) { if (_formKey.currentState!.validate()) {
FocusScope.of(context).unfocus();
final navigator = Navigator.of(context); final navigator = Navigator.of(context);
final loggedin = await _vm.createAccount( bool loggedin = false;
if (widget.register) {
loggedin = await _vm.createAccount(
context, context,
email: widget.email, email: widget.email,
password: _passwordController1.text, password: _passwordController1.text,
); );
} else {
loggedin = await _vm.login(
context,
email: widget.email,
password: _passwordController1.text,
);
}
if (loggedin && mounted) { if (loggedin && mounted) {
_storageService.addAccountLevel(); await _storageService.setAccountLevel(4);
navigator.push( navigator.push(
MaterialPageRoute( MaterialPageRoute(
builder: (builder) => VerifyEmailPage(), builder: (builder) =>
const VerifyEmailPage(),
), ),
); );
} }
} }
} }
: null, : null,
child: const SizedBox( child: SizedBox(
height: 50, height: 50,
child: Row( child: Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text( Text(
'Registrierung abschließen', widget.register
style: TextStyle( ? 'Registrierung abschließen'
: 'Einloggen',
style: const TextStyle(
fontSize: 20, fontSize: 20,
), ),
), ),
@ -214,6 +238,7 @@ class _PasswordPageState extends State<PasswordPage> {
), ),
), ),
), ),
),
); );
} }
} }

View File

@ -1,4 +1,6 @@
import 'package:app/model/services/storage_service.dart';
import 'package:app/pages/password_page.dart'; import 'package:app/pages/password_page.dart';
import 'package:app/pages/verify_email_page.dart';
import 'package:app/util/colors.dart'; import 'package:app/util/colors.dart';
import 'package:app/util/validation.dart'; import 'package:app/util/validation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -13,6 +15,30 @@ class RegistrationPage extends StatefulWidget {
class _RegistrationPageState extends State<RegistrationPage> { class _RegistrationPageState extends State<RegistrationPage> {
final formKey = GlobalKey<FormState>(); final formKey = GlobalKey<FormState>();
final mailController = TextEditingController(); final mailController = TextEditingController();
bool _loading = true;
final StorageService _storageService = StorageService();
@override
void initState() {
_init();
super.initState();
}
void _init() async {
final accountLevel = await _storageService.accountLevel;
if (accountLevel > 3 && mounted) {
await Navigator.push(context,
MaterialPageRoute(builder: (builder) => const VerifyEmailPage()));
setState(() {
_loading = false;
});
} else {
setState(() {
_loading = false;
});
}
}
@override @override
void dispose() { void dispose() {
@ -23,8 +49,37 @@ class _RegistrationPageState extends State<RegistrationPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SafeArea( return SafeArea(
child: Scaffold( child: _loading
? Center(
child: Column(
children: [
const SizedBox(
height: 150,
),
Hero(
tag: 'logo',
child: Image.asset(
'assets/JPEG.jpg',
height: 180,
),
),
CircularProgressIndicator(
color: CustomColors.primary,
),
],
),
)
: Scaffold(
appBar: AppBar( appBar: AppBar(
leading: BackButton(
color: CustomColors.primary,
onPressed: () async {
await _storageService.setAccountLevel(2);
if (mounted) {
Navigator.pop(context);
}
},
),
iconTheme: IconThemeData( iconTheme: IconThemeData(
color: CustomColors.primary, color: CustomColors.primary,
), ),

View File

@ -1,16 +1,75 @@
import 'package:app/model/services/auth_service.dart'; import 'package:app/model/services/auth_service.dart';
import 'package:app/model/services/storage_service.dart';
import 'package:app/pages/notifications_page.dart'; import 'package:app/pages/notifications_page.dart';
import 'package:app/util/colors.dart'; import 'package:app/util/colors.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class SecurityPage extends StatelessWidget { class SecurityPage extends StatefulWidget {
const SecurityPage({super.key}); const SecurityPage({super.key});
@override
State<SecurityPage> createState() => _SecurityPageState();
}
class _SecurityPageState extends State<SecurityPage> {
final StorageService _storageService = StorageService();
bool _loading = true;
@override
void initState() {
_init();
super.initState();
}
void _init() async {
final accountLevel = await _storageService.accountLevel;
if (accountLevel > 1 && mounted) {
await Navigator.push(context,
MaterialPageRoute(builder: (builder) => const NotificationsPage()));
setState(() {
_loading = false;
});
} else {
setState(() {
_loading = false;
});
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SafeArea( return SafeArea(
child: Scaffold( child: _loading
? Center(
child: Column(
children: [
const SizedBox(
height: 150,
),
Hero(
tag: 'logo',
child: Image.asset(
'assets/JPEG.jpg',
height: 180,
),
),
CircularProgressIndicator(
color: CustomColors.primary,
),
],
),
)
: Scaffold(
appBar: AppBar( appBar: AppBar(
leading: BackButton(
color: CustomColors.primary,
onPressed: () async {
await _storageService.setAccountLevel(0);
if (mounted) {
Navigator.pop(context);
}
},
),
iconTheme: IconThemeData(color: CustomColors.primary), iconTheme: IconThemeData(color: CustomColors.primary),
), ),
body: Padding( body: Padding(
@ -58,11 +117,13 @@ class SecurityPage extends StatelessWidget {
bool isAuthenticated = bool isAuthenticated =
await AuthService.authenticateWithBiometrics(); await AuthService.authenticateWithBiometrics();
if (isAuthenticated) { if (isAuthenticated) {
await _storageService.setAccountLevel(2);
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => NotificationsPage()), builder: (context) =>
const NotificationsPage()),
); );
} }
}, },

View File

@ -1,15 +1,65 @@
import 'package:app/model/services/storage_service.dart';
import 'package:app/pages/agb_page.dart'; import 'package:app/pages/agb_page.dart';
import 'package:app/pages/security_page.dart'; import 'package:app/pages/security_page.dart';
import 'package:app/util/colors.dart'; import 'package:app/util/colors.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class StartPage extends StatelessWidget { class StartPage extends StatefulWidget {
const StartPage({super.key}); const StartPage({super.key});
@override
State<StartPage> createState() => _StartPageState();
}
class _StartPageState extends State<StartPage> {
final StorageService _storageService = StorageService();
bool _loading = true;
@override
void initState() {
_init();
super.initState();
}
void _init() async {
int accountLevel = await _storageService.accountLevel;
if (accountLevel > 0 && mounted) {
await Navigator.push(context,
MaterialPageRoute(builder: (builder) => const SecurityPage()));
setState(() {
_loading = false;
});
} else {
setState(() {
_loading = false;
});
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SafeArea( return SafeArea(
child: Scaffold( child: _loading
? Center(
child: Column(
children: [
const SizedBox(
height: 150,
),
Hero(
tag: 'logo',
child: Image.asset(
'assets/JPEG.jpg',
height: 180,
),
),
CircularProgressIndicator(
color: CustomColors.primary,
),
],
),
)
: Scaffold(
appBar: AppBar( appBar: AppBar(
iconTheme: IconThemeData(color: CustomColors.primary), iconTheme: IconThemeData(color: CustomColors.primary),
), ),
@ -57,14 +107,17 @@ class StartPage extends StatelessWidget {
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: CustomColors.primary, backgroundColor: CustomColors.primary,
), ),
onPressed: () { onPressed: () async {
await _storageService.setAccountLevel(1);
if (mounted) {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (builder) => SecurityPage(), builder: (builder) => const SecurityPage(),
// builder: (builder) => SecurityPage(), // builder: (builder) => SecurityPage(),
), ),
); );
}
}, },
child: const SizedBox( child: const SizedBox(
height: 60, height: 60,
@ -96,7 +149,8 @@ class StartPage extends StatelessWidget {
TextButton( TextButton(
onPressed: () { onPressed: () {
showDialog( showDialog(
context: context, builder: (builder) => AgbPage()); context: context,
builder: (builder) => AgbPage());
}, },
child: Text( child: Text(
'AGB - Datenschutzerklärung', 'AGB - Datenschutzerklärung',

View File

@ -1,14 +1,60 @@
import 'package:app/model/services/storage_service.dart';
import 'package:app/util/colors.dart'; import 'package:app/util/colors.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class VerifyEmailPage extends StatelessWidget { class VerifyEmailPage extends StatefulWidget {
VerifyEmailPage({super.key}); const VerifyEmailPage({super.key});
@override
State<VerifyEmailPage> createState() => _VerifyEmailPageState();
}
class _VerifyEmailPageState extends State<VerifyEmailPage> {
final StorageService _storageService = StorageService();
bool _loading = true;
@override
void initState() {
super.initState();
setState(() {
_loading = false;
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SafeArea( return SafeArea(
child: Scaffold( child: _loading
? Center(
child: Column(
children: [
const SizedBox(
height: 150,
),
Hero(
tag: 'logo',
child: Image.asset(
'assets/JPEG.jpg',
height: 180,
),
),
CircularProgressIndicator(
color: CustomColors.primary,
),
],
),
)
: Scaffold(
appBar: AppBar( appBar: AppBar(
leading: BackButton(
color: CustomColors.primary,
onPressed: () async {
await _storageService.setAccountLevel(3);
if (mounted) {
Navigator.pop(context);
}
},
),
iconTheme: IconThemeData( iconTheme: IconThemeData(
color: CustomColors.primary, color: CustomColors.primary,
), ),

View File

@ -6,7 +6,7 @@ class CustomColors {
} }
static Color get success { static Color get success {
return const Color.fromARGB(200, 55, 125, 55); return const Color.fromARGB(255, 51, 217, 178);
} }
static Color get primary { static Color get primary {