ft/restart due to new layout from marketing
@ -1,4 +1,6 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||
<!-- <uses-permission android:name="android.permission.USE_FINGERPRINT"/> -->
|
||||
<application
|
||||
android:label="app"
|
||||
android:name="${applicationName}"
|
||||
|
@ -1,6 +1,11 @@
|
||||
package com.example.app
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.embedding.android.FlutterFragmentActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugins.GeneratedPluginRegistrant
|
||||
|
||||
class MainActivity: FlutterActivity() {
|
||||
class MainActivity: FlutterFragmentActivity() {
|
||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||
GeneratedPluginRegistrant.registerWith(flutterEngine)
|
||||
}
|
||||
}
|
||||
|
BIN
frontend/app/assets/JPEG.jpg
Normal file
After Width: | Height: | Size: 178 KiB |
BIN
frontend/app/assets/Mockup.jpg
Normal file
After Width: | Height: | Size: 1.1 MiB |
BIN
frontend/app/assets/chat_bubbles.jpg
Normal file
After Width: | Height: | Size: 290 KiB |
BIN
frontend/app/assets/chat_bubbles.png
Normal file
After Width: | Height: | Size: 332 KiB |
BIN
frontend/app/assets/icons/chair_magnifier.png
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
frontend/app/assets/icons/conversation.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
frontend/app/assets/icons/financial_growth.png
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
frontend/app/assets/icons/map_search.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
frontend/app/assets/icons/message_lookout.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
frontend/app/assets/icons/office.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
frontend/app/assets/icons/people_cheering.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
frontend/app/assets/vector-EPS.eps
Normal file
69
frontend/app/assets/vector-SVG.svg
Normal file
@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 3000 2000" style="enable-background:new 0 0 3000 2000;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<rect x="0" y="0" width="3000" height="2000"/>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M1643.8,246.59l-62.38,104.92l57.67,47.96l46.96-78.8h471.2l44.11-74.08H1643.8z"/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<polygon class="st0" points="2039.49,518.38 1995.24,592.61 1524.04,592.61 1285.51,993.15 1199.15,993.15 1507.91,474.13
|
||||
1507.63,473.84 1323.2,320.82 929.22,320.82 1212,795.3 1168.89,867.68 798.75,246.59 1350.04,246.59 1604.26,457.85
|
||||
1568.29,518.38 "/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M462.6,1250.09h-89.07v220.83h89.07c72.8,0,126.61-42.97,126.61-110.63
|
||||
C589.21,1292.91,535.4,1250.09,462.6,1250.09z M462.6,1446.22h-60.38v-171.58h60.38c58.81,0,97.07,34.12,97.07,85.65
|
||||
C559.67,1412.11,521.41,1446.22,462.6,1446.22z"/>
|
||||
<path class="st0" d="M701.13,1250.09v220.83h28.55v-220.83H701.13z"/>
|
||||
<path class="st0" d="M1092.68,1354.01H967.63v23.84l94.64,0.43c-2.28,10.56-6,20.13-11.13,29.26c-3,5.57-7.28,10.56-11.7,15.27
|
||||
l-0.57,0.57c-15.27,14.85-36.54,24.55-62.24,26.55c-3,0.43-6.28,0.43-9.56,0.43h-3.71c-35.83-1.14-64.38-16.99-79.65-42.25
|
||||
h-0.43c-7.85-13.56-12.56-29.55-12.56-47.82c0-52.82,39.54-89.64,96.35-89.64c37.83,0,68.38,15.99,84.08,42.82l32.12-0.43
|
||||
c-18.56-41.11-62.09-67.09-116.19-67.09c-72.37,0-125.9,46.96-125.9,114.34c0,66.8,51.82,113.63,122.91,114.62h9.56
|
||||
c3.71-0.28,7.71-0.71,11.42-0.71l6.28-1c11.85-2,23.55-5.28,33.55-9.56c13.27-5.71,25.12-13.28,34.83-22.55
|
||||
c0.29-0.43,0.71-0.71,0.71-1.14c4.85-4.71,9.56-9.85,13.27-15.56l0.86-1c11.42-16.56,17.7-36.11,18.7-58.1
|
||||
C1093.25,1358.72,1092.82,1356.72,1092.68,1354.01z"/>
|
||||
<path class="st0" d="M1201.16,1250.09v220.83h28.41v-220.83H1201.16z"/>
|
||||
<path class="st0" d="M1329.49,1250.09v24.27h83.65v196.56h28.55v-196.56h84.08v-24.27H1329.49z"/>
|
||||
<path class="st0" d="M1704.2,1250.09h-32.97l-101.21,220.83h31.83l25.98-55.53h120.76l25.27,55.53h31.55L1704.2,1250.09z
|
||||
M1639.11,1391.55l48.82-112.91l49.82,112.91H1639.11z"/>
|
||||
<path class="st0" d="M1934.3,1446.65v-196.56h-28.41v220.83h158.31v-24.27H1934.3z"/>
|
||||
<path class="st0" d="M2193.24,1446.65v-75.37h119.76v-23.98h-119.76v-72.94h139.18v-24.27h-167.73v220.83h170.72v-24.27
|
||||
H2193.24z"/>
|
||||
<path class="st0" d="M2547.39,1368.28h3c45.82,0,73.8-25.27,73.8-59.52c0-34.4-27.98-58.38-73.8-58.38h-108.63v220.83h28.26
|
||||
l0.29-102.92h44.11l75.51,102.63h36.54L2547.39,1368.28z M2470.31,1343.59v-69.23h80.08c28.55,0,44.11,12.42,44.11,34.12
|
||||
c0,21.27-15.56,35.12-44.11,35.12H2470.31z"/>
|
||||
<g>
|
||||
<polygon class="st0" points="817.17,1753.32 831.98,1753.32 831.98,1696.16 903.01,1696.16 903.01,1682.67 831.98,1682.67
|
||||
831.98,1635.82 911.43,1635.82 911.43,1622.14 817.17,1622.14 "/>
|
||||
<path class="st0" d="M1097.67,1699.74c20.56-3.85,35.54-16.56,35.54-38.4c0-23.7-18.7-39.11-47.39-39.11h-56.39v131.18h14.7
|
||||
v-50.96h37.54l37.97,50.96h18.27L1097.67,1699.74z M1044.14,1689.03v-53.24h40.54c21.13,0,33.55,9.85,33.55,25.98
|
||||
c0,17.13-14.13,27.26-33.69,27.26H1044.14z"/>
|
||||
<rect x="1257.67" y="1622.14" class="st0" width="14.81" height="131.18"/>
|
||||
<polygon class="st0" points="1417.74,1693.91 1489.32,1693.91 1489.32,1680.42 1417.74,1680.42 1417.74,1635.63
|
||||
1497.76,1635.63 1497.76,1622.14 1402.93,1622.14 1402.93,1753.32 1498.7,1753.32 1498.7,1739.83 1417.74,1739.83 "/>
|
||||
<path class="st0" d="M1663.8,1622.23h-45.54v131.18h45.54c41.11,0,69.66-28.83,69.66-65.81
|
||||
C1733.46,1650.49,1704.91,1622.23,1663.8,1622.23z M1663.8,1739.56h-30.83v-103.78h30.83c33.12,0,54.24,22.98,54.24,52.1
|
||||
C1718.04,1717.15,1696.92,1739.56,1663.8,1739.56z"/>
|
||||
<polygon class="st0" points="1871.52,1693.91 1943.11,1693.91 1943.11,1680.42 1871.52,1680.42 1871.52,1635.63
|
||||
1951.54,1635.63 1951.54,1622.14 1856.72,1622.14 1856.72,1753.32 1952.47,1753.32 1952.47,1739.83 1871.52,1739.83 "/>
|
||||
<polygon class="st0" points="2168.59,1622.14 2168.59,1727.27 2085.95,1622.14 2072.09,1622.14 2072.09,1753.32
|
||||
2086.52,1753.32 2086.52,1645.76 2171.22,1753.32 2183.04,1753.32 2183.04,1622.14 "/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.4 KiB |
@ -1,4 +1,5 @@
|
||||
import 'package:app/pages/home_page.dart';
|
||||
import 'package:app/pages/start_page.dart';
|
||||
import 'package:app/pages_draft/home_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart'
|
||||
show GlobalMaterialLocalizations;
|
||||
@ -11,6 +12,7 @@ void main() async {
|
||||
localizationsDelegates: const [GlobalMaterialLocalizations.delegate],
|
||||
supportedLocales: const [Locale('en'), Locale('de')],
|
||||
theme: ThemeData().copyWith(
|
||||
canvasColor: Colors.black,
|
||||
colorScheme: const ColorScheme(
|
||||
brightness: Brightness.dark,
|
||||
primary: Colors.white,
|
||||
@ -45,9 +47,7 @@ void main() async {
|
||||
backgroundColor: Colors.black,
|
||||
foregroundColor: Colors.white,
|
||||
)),
|
||||
home: HomePage(
|
||||
loggedOut: false,
|
||||
),
|
||||
home: StartPage(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
43
frontend/app/lib/model/services/auth_service.dart
Normal file
@ -0,0 +1,43 @@
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:local_auth/local_auth.dart';
|
||||
|
||||
class AuthService {
|
||||
static Future<bool> authenticateWithBiometrics() async {
|
||||
//initialize Local Authentication plugin.
|
||||
final LocalAuthentication localAuthentication = LocalAuthentication();
|
||||
//status of authentication.
|
||||
bool isAuthenticated = false;
|
||||
//check if device supports biometrics authentication.
|
||||
bool isBiometricSupported = await localAuthentication.isDeviceSupported();
|
||||
//check if user has enabled biometrics.
|
||||
//check
|
||||
bool canCheckBiometrics = await localAuthentication.canCheckBiometrics;
|
||||
|
||||
//if device supports biometrics and user has enabled biometrics, then authenticate.
|
||||
if (isBiometricSupported && canCheckBiometrics) {
|
||||
// ignore: use_build_context_synchronously
|
||||
// final messenger = ScaffoldMessenger.of(context);
|
||||
try {
|
||||
isAuthenticated = await localAuthentication.authenticate(
|
||||
localizedReason: 'Scan your fingerprint to authenticate',
|
||||
options: const AuthenticationOptions(
|
||||
biometricOnly: false,
|
||||
useErrorDialogs: true,
|
||||
stickyAuth: true,
|
||||
),
|
||||
);
|
||||
} on PlatformException catch (err) {
|
||||
print(err);
|
||||
// messenger.showSnackBar(SnackBar(
|
||||
// backgroundColor: CustomColors.error,
|
||||
// content: Text(
|
||||
// 'Fehler beim Einrichten der Biometrie: $err',
|
||||
// style: const TextStyle(color: Colors.white),
|
||||
// ),
|
||||
// ));
|
||||
}
|
||||
}
|
||||
print(isAuthenticated);
|
||||
return isAuthenticated;
|
||||
}
|
||||
}
|
@ -22,7 +22,7 @@ class AccountViewModel extends BaseViewModel {
|
||||
}
|
||||
|
||||
void _init() async {
|
||||
super.init();
|
||||
// super.init();
|
||||
// try {
|
||||
// _apiResponse = ApiResponse.completed(await _service.getAccount());
|
||||
// } catch (e) {
|
||||
|
@ -1,12 +1,12 @@
|
||||
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/pages_draft/home_page.dart';
|
||||
import 'package:app/util/colors.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BaseViewModel with ChangeNotifier {
|
||||
BaseViewModel() {
|
||||
init();
|
||||
// init();
|
||||
}
|
||||
ApiResponse _apiResponse = ApiResponse.initial('Keine Daten');
|
||||
|
||||
@ -16,16 +16,16 @@ class BaseViewModel with ChangeNotifier {
|
||||
return _apiResponse;
|
||||
}
|
||||
|
||||
void init() async {
|
||||
// if (await BackendService.isLoggedIn) {
|
||||
try {
|
||||
_apiResponse = ApiResponse.completed(await _service.getAccount());
|
||||
} catch (e) {
|
||||
_apiResponse = ApiResponse.error(e.toString());
|
||||
}
|
||||
notifyListeners();
|
||||
// }
|
||||
}
|
||||
// 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);
|
||||
|
25
frontend/app/lib/pages/agb_page.dart
Normal file
@ -0,0 +1,25 @@
|
||||
import 'package:app/util/colors.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AgbPage extends StatelessWidget {
|
||||
AgbPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
iconTheme: IconThemeData(color: CustomColors.primary),
|
||||
),
|
||||
backgroundColor: Colors.black,
|
||||
body: const Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'TODO: insert AGBs',
|
||||
textAlign: TextAlign.center,
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
106
frontend/app/lib/pages/notifications_page.dart
Normal file
@ -0,0 +1,106 @@
|
||||
import 'package:app/pages/registration_page.dart';
|
||||
import 'package:app/util/colors.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class NotificationsPage extends StatelessWidget {
|
||||
const NotificationsPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SafeArea(
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
iconTheme: IconThemeData(
|
||||
color: CustomColors.primary,
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 20, 20, 16),
|
||||
child: Column(
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 80,
|
||||
),
|
||||
Image.asset('assets/chat_bubbles.png'),
|
||||
const SizedBox(
|
||||
height: 60,
|
||||
),
|
||||
const Text(
|
||||
'Erhalte Mitteilungen',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontFamily: 'sans-serif',
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 2.0,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
const Text(
|
||||
'Du erhältst z. B. eine Mitteilung sobald wir eine Digitale Spur gefunden haben.',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
const Text(
|
||||
'Du kannst die Mitteilungen jederzeit wieder deaktivieren.',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const Spacer(
|
||||
flex: 2,
|
||||
),
|
||||
Hero(
|
||||
tag: 'flow-button',
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: CustomColors.primary,
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (builder) => const RegistrationPage(),
|
||||
// builder: (builder) => SecurityPage(),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const SizedBox(
|
||||
height: 60,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'Mitteilungen erhalten',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {},
|
||||
child: Text(
|
||||
'Später',
|
||||
style: TextStyle(color: CustomColors.primary),
|
||||
),
|
||||
),
|
||||
const Spacer(
|
||||
flex: 1,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
102
frontend/app/lib/pages/registration_page.dart
Normal file
@ -0,0 +1,102 @@
|
||||
import 'package:app/pages_old/start_page.dart';
|
||||
import 'package:app/util/colors.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class RegistrationPage extends StatelessWidget {
|
||||
const RegistrationPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SafeArea(
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
iconTheme: IconThemeData(
|
||||
color: CustomColors.primary,
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 20, 20, 16),
|
||||
child: Column(
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
const Text(
|
||||
'Jetzt Registrieren',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontFamily: 'sans-serif',
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 2.0,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
const Text(
|
||||
'Gib deine E-Mail Adresse ein.',
|
||||
// textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
const Text(
|
||||
'Du kannst die Mitteilungen jederzeit wieder deaktivieren.',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const Spacer(
|
||||
flex: 2,
|
||||
),
|
||||
Hero(
|
||||
tag: 'flow-button',
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: CustomColors.primary,
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (builder) => StartPage(),
|
||||
// builder: (builder) => SecurityPage(),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const SizedBox(
|
||||
height: 60,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'Mitteilungen erhalten',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {},
|
||||
child: Text(
|
||||
'Später',
|
||||
style: TextStyle(color: CustomColors.primary),
|
||||
),
|
||||
),
|
||||
const Spacer(
|
||||
flex: 1,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
126
frontend/app/lib/pages/security_page.dart
Normal file
@ -0,0 +1,126 @@
|
||||
import 'package:app/model/services/auth_service.dart';
|
||||
import 'package:app/pages/notifications_page.dart';
|
||||
import 'package:app/util/colors.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SecurityPage extends StatelessWidget {
|
||||
const SecurityPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SafeArea(
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
iconTheme: IconThemeData(color: CustomColors.primary),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 20, 16, 16),
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
const Spacer(),
|
||||
const Hero(
|
||||
tag: 'flow-icon',
|
||||
child: Icon(
|
||||
Icons.fingerprint,
|
||||
color: Colors.white,
|
||||
size: 200,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
const Text(
|
||||
'Deine Sicherheit kommt an erster Stelle',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontFamily: 'sans-serif',
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 30,
|
||||
),
|
||||
const Text(
|
||||
'Schütze dein Konto mit der biometrischen Erkennung deines Geräts oder lege einen Code fest.',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontFamily: 'sans-serif',
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
const Spacer(),
|
||||
Hero(
|
||||
tag: 'flow-button',
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: CustomColors.primary,
|
||||
),
|
||||
onPressed: () async {
|
||||
bool isAuthenticated =
|
||||
await AuthService.authenticateWithBiometrics();
|
||||
if (isAuthenticated) {
|
||||
// ignore: use_build_context_synchronously
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => NotificationsPage()),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: const SizedBox(
|
||||
height: 60,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'App absichern',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// const SizedBox(
|
||||
// height: 10,
|
||||
// ),
|
||||
// ElevatedButton(
|
||||
// style: ElevatedButton.styleFrom(
|
||||
// backgroundColor: CustomColors.secondary,
|
||||
// ),
|
||||
// onPressed: () {
|
||||
// Navigator.push(
|
||||
// context,
|
||||
// MaterialPageRoute(
|
||||
// builder: (builder) => SecurityPage(),
|
||||
// ),
|
||||
// );
|
||||
// },
|
||||
// child: const SizedBox(
|
||||
// height: 60,
|
||||
// child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
// children: [
|
||||
// Text(
|
||||
// 'Eigenen Code festlegen',
|
||||
// style: TextStyle(
|
||||
// color: Colors.white,
|
||||
// fontSize: 22,
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
const Spacer(
|
||||
flex: 2,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
112
frontend/app/lib/pages/start_page.dart
Normal file
@ -0,0 +1,112 @@
|
||||
import 'package:app/pages/agb_page.dart';
|
||||
import 'package:app/pages/security_page.dart';
|
||||
import 'package:app/util/colors.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class StartPage extends StatelessWidget {
|
||||
const StartPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SafeArea(
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
iconTheme: IconThemeData(color: CustomColors.primary),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 20, 16, 16),
|
||||
child: Column(
|
||||
children: [
|
||||
Hero(
|
||||
tag: 'flow-icon',
|
||||
child: Image.asset(
|
||||
'assets/JPEG.jpg',
|
||||
height: 180,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 30,
|
||||
),
|
||||
const Text(
|
||||
'Hallo. Digitale Spuren\nentfernen\nper Knopfdruck.',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontFamily: 'sans-serif',
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 2.0,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
const Text(
|
||||
'Mit uns finden Sie Ihre Digitalen Spuren und können diese entfernen.',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontFamily: 'sans-serif',
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
const Spacer(
|
||||
flex: 1,
|
||||
),
|
||||
Hero(
|
||||
tag: 'flow-button',
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: CustomColors.primary,
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (builder) => SecurityPage(),
|
||||
// builder: (builder) => SecurityPage(),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const SizedBox(
|
||||
height: 60,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'Weiter',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const Spacer(
|
||||
flex: 1,
|
||||
),
|
||||
const Text(
|
||||
'Mit der weiteren Nutzung stimmst du den folgenden Bedingungen zu:',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontFamily: 'sans-serif',
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context, builder: (builder) => AgbPage());
|
||||
},
|
||||
child: Text(
|
||||
'AGB - Datenschutzerklärung',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(color: CustomColors.primary),
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
import 'package:app/model/services/backend_service.dart';
|
||||
import 'package:app/model/view_model/account_vm.dart';
|
||||
import 'package:app/pages/login_overlay.dart';
|
||||
import 'package:app/pages/persons_page.dart';
|
||||
import 'package:app/model/view_model/base_vm.dart';
|
||||
import 'package:app/pages_draft/login_overlay.dart';
|
||||
import 'package:app/pages_draft/persons_page.dart';
|
||||
import 'package:app/widgets/background.dart';
|
||||
import 'package:app/widgets/bottom_navigation.dart';
|
||||
import 'package:app/widgets/bottom_navigation_item.dart';
|
||||
@ -153,7 +154,7 @@ class _HomePageState extends State<HomePage> {
|
||||
BottomNavigationItem(
|
||||
onPressed: () async {
|
||||
final navigator = Navigator.of(context);
|
||||
if (await vm.isLoggedIn(context)) {
|
||||
if (_loggedin) {
|
||||
navigator.push(MaterialPageRoute(
|
||||
builder: (builder) => const PersonsPage()));
|
||||
} else {
|
||||
@ -179,10 +180,9 @@ class _HomePageState extends State<HomePage> {
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 45, 16, 16),
|
||||
child: Center(
|
||||
child: ChangeNotifierProvider<AccountViewModel>(
|
||||
create: (context) => AccountViewModel(),
|
||||
child:
|
||||
Consumer<AccountViewModel>(builder: (context, value, child) {
|
||||
child: ChangeNotifierProvider<BaseViewModel>(
|
||||
create: (context) => BaseViewModel(),
|
||||
child: Consumer<BaseViewModel>(builder: (context, value, child) {
|
||||
// _checkResponse(value.response);
|
||||
if (!widget.loggedOut) {
|
||||
_isLoggedIn(context);
|
@ -1,8 +1,8 @@
|
||||
import 'package:app/model/apis/api_response.dart';
|
||||
import 'package:app/model/services/backend_service.dart';
|
||||
import 'package:app/model/view_model/persons_vm.dart';
|
||||
import 'package:app/pages/home_page.dart';
|
||||
import 'package:app/pages/person_details_page.dart';
|
||||
import 'package:app/pages_draft/home_page.dart';
|
||||
import 'package:app/pages_draft/person_details_page.dart';
|
||||
import 'package:app/pb/person.pb.dart';
|
||||
import 'package:app/util/validation.dart';
|
||||
import 'package:app/widgets/background.dart';
|
||||
@ -24,24 +24,25 @@ class _PersonsPageState extends State<PersonsPage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_init();
|
||||
// _init();
|
||||
}
|
||||
|
||||
void _init() async {
|
||||
_setLoading(true);
|
||||
_loggedin = await BackendService.isLoggedIn;
|
||||
_setLoading(false);
|
||||
}
|
||||
// void _init() async {
|
||||
// _setLoading(true);
|
||||
// _loggedin = await BackendService.isLoggedIn;
|
||||
// _setLoading(false);
|
||||
// }
|
||||
|
||||
void _setLoading(bool loading) {
|
||||
setState(() {
|
||||
_loading = loading;
|
||||
});
|
||||
}
|
||||
// void _setLoading(bool loading) {
|
||||
// setState(() {
|
||||
// _loading = loading;
|
||||
// });
|
||||
// }
|
||||
|
||||
void _checkResponse(ApiResponse response) {
|
||||
if (response.status == Status.ERROR &&
|
||||
response.message!.contains('unauthenticated')) {
|
||||
(response.message!.contains('unauthenticated') ||
|
||||
response.message!.contains('blocked'))) {
|
||||
BackendService.logout();
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
MaterialPageRoute(
|
||||
@ -52,7 +53,7 @@ class _PersonsPageState extends State<PersonsPage> {
|
||||
}
|
||||
}
|
||||
|
||||
bool _loading = true;
|
||||
bool _loading = false;
|
||||
bool _loggedin = false;
|
||||
List<Person> persons = [];
|
||||
|
||||
@ -75,9 +76,11 @@ class _PersonsPageState extends State<PersonsPage> {
|
||||
list.add(TextButton(
|
||||
onPressed: () async {
|
||||
final Person per = await showPerson(context, person: p);
|
||||
setState(() {
|
||||
this.persons.add(per);
|
||||
});
|
||||
if (!per.id.isZero && !persons.contains(per)) {
|
||||
setState(() {
|
||||
this.persons.add(per);
|
||||
});
|
||||
}
|
||||
},
|
||||
child: Card(
|
||||
shape:
|
||||
@ -87,7 +90,7 @@ class _PersonsPageState extends State<PersonsPage> {
|
||||
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 14),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
SizedBox(
|
||||
height: 40,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@ -127,7 +130,7 @@ class _PersonsPageState extends State<PersonsPage> {
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () async {
|
||||
final p = await showPerson(context);
|
||||
if (!p.id.isZero) {
|
||||
if (!p.id.isZero && !persons.contains(p)) {
|
||||
setState(() {
|
||||
persons.add(p);
|
||||
});
|
||||
@ -215,7 +218,9 @@ class _PersonsPageState extends State<PersonsPage> {
|
||||
child: Consumer<PersonsViewModel>(
|
||||
builder: (context, value, child) {
|
||||
_checkResponse(value.response);
|
||||
listPersons(context);
|
||||
if (persons.isEmpty) {
|
||||
listPersons(context);
|
||||
}
|
||||
return _loading
|
||||
? const CircularProgressIndicator(
|
||||
color: Colors.grey,
|
@ -8,4 +8,12 @@ class CustomColors {
|
||||
static Color get success {
|
||||
return const Color.fromARGB(200, 55, 125, 55);
|
||||
}
|
||||
|
||||
static Color get primary {
|
||||
return const Color.fromARGB(255, 51, 217, 178);
|
||||
}
|
||||
|
||||
static Color get secondary {
|
||||
return const Color.fromARGB(255, 52, 172, 224);
|
||||
}
|
||||
}
|
||||
|
@ -115,6 +115,14 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_plugin_android_lifecycle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_plugin_android_lifecycle
|
||||
sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.17"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
@ -184,6 +192,46 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
local_auth:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: local_auth
|
||||
sha256: "7e6c63082e399b61e4af71266b012e767a5d4525dd6e9ba41e174fd42d76e115"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.7"
|
||||
local_auth_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: local_auth_android
|
||||
sha256: df4ccb3193525b8a60c78a5ca7bf188a47705bcf77bcc837a6b2cf6da64ae0e2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.35"
|
||||
local_auth_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: local_auth_ios
|
||||
sha256: "8293faf72ef0ac4710f209edd03916c2d4c1eeab0483bdcf9b2e659c2f7d737b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.5"
|
||||
local_auth_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: local_auth_platform_interface
|
||||
sha256: fc5bd537970a324260fda506cfb61b33ad7426f37a8ea5c461cf612161ebba54
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.8"
|
||||
local_auth_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: local_auth_windows
|
||||
sha256: "505ba3367ca781efb1c50d3132e44a2446bccc4163427bc203b9b4d8994d97ea"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.10"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -224,6 +272,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.8.3"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.6"
|
||||
pointycastle:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -351,4 +407,4 @@ packages:
|
||||
version: "0.1.4-beta"
|
||||
sdks:
|
||||
dart: ">=3.1.4 <4.0.0"
|
||||
flutter: ">=3.3.0"
|
||||
flutter: ">=3.10.0"
|
||||
|
@ -28,6 +28,7 @@ environment:
|
||||
# the latest version available on pub.dev. To see which dependencies have newer
|
||||
# versions available, run `flutter pub outdated`.
|
||||
dependencies:
|
||||
local_auth: ^2.1.7
|
||||
async: ^2.2.0
|
||||
protobuf: ^3.0.0
|
||||
collection: ^1.15.0-nullsafety.4
|
||||
@ -72,6 +73,8 @@ flutter:
|
||||
|
||||
# To add assets to your application, add an assets section, like this:
|
||||
assets:
|
||||
- assets/chat_bubbles.png
|
||||
- assets/JPEG.jpg
|
||||
- lib/assets/logo_300x200.png
|
||||
- lib/assets/hero-pattern-300x200.png
|
||||
# - images/a_dot_burr.jpeg
|
||||
|
@ -6,6 +6,9 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <local_auth_windows/local_auth_plugin.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
LocalAuthPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("LocalAuthPlugin"));
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
local_auth_windows
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|