From dc3a28ba5f472c79b52e3309b267f8231f2b0152 Mon Sep 17 00:00:00 2001 From: itsscb Date: Sun, 29 Oct 2023 23:58:06 +0100 Subject: [PATCH] ft/adds persistence (partial complete) TODO: Load on start. Not working atm. --- frontend/app/lib/data/database.dart | 150 +++++++++ frontend/app/lib/gapi/client.dart | 49 ++- frontend/app/lib/main.dart | 1 - frontend/app/lib/pages/dashboard_page.dart | 76 +++-- frontend/app/lib/pages/home_page.dart | 158 --------- frontend/app/lib/pages/login_page.dart | 256 +++++++++------ frontend/app/lib/pages/start_page.dart | 361 +++++++++++++-------- frontend/app/pubspec.lock | 29 +- frontend/app/pubspec.yaml | 3 + 9 files changed, 642 insertions(+), 441 deletions(-) create mode 100644 frontend/app/lib/data/database.dart delete mode 100644 frontend/app/lib/pages/home_page.dart diff --git a/frontend/app/lib/data/database.dart b/frontend/app/lib/data/database.dart new file mode 100644 index 0000000..6d47478 --- /dev/null +++ b/frontend/app/lib/data/database.dart @@ -0,0 +1,150 @@ +import 'dart:async'; +import 'package:fixnum/fixnum.dart'; + +import 'package:app/pb/google/protobuf/timestamp.pb.dart'; +import 'package:flutter/services.dart'; +import 'package:path/path.dart'; +import 'package:sqflite/sqflite.dart'; + +class Session { + Session({ + this.sessionId, + this.accessToken, + this.accessTokenExpiresAt, + this.refreshToken, + this.refreshTokenExpiresAt, + this.accountId, + }) { + _init(); + } + + String? sessionId; + String? accessToken; + String? refreshToken; + Timestamp? accessTokenExpiresAt; + Timestamp? refreshTokenExpiresAt; + Int64? accountId; + + late Database _database; + + Future get database async => _database; + + static Future get newSession async { + final Database db = await openDatabase( + join(await getDatabasesPath(), 'df_database.db'), + onCreate: (db, version) { + return db.execute( + 'CREATE TABLE sessions(accountId INTEGER PRIMARY KEY, sessionId TEXT, accessToken TEXT, accessTokenExpiresAt TEXT, refreshToken TEXT, refreshTokenExpiresAt TEXT)', + ); + }, + version: 1, + ); + Session s = Session(); + s._database = db; + return s; + } + + void _init() { + _initDatabase(); + } + + Future _initDatabase() async { + print('DB: INITIALIZING - start'); + _database = await openDatabase( + join(await getDatabasesPath(), 'df_database.db'), + onCreate: (db, version) { + return db.execute( + 'CREATE TABLE sessions(accountId INTEGER PRIMARY KEY, sessionId TEXT, accessToken TEXT, accessTokenExpiresAt TEXT, refreshToken TEXT, refreshTokenExpiresAt TEXT)', + ); + }, + version: 1, + ); + print('DB: INITIALIZING - end'); + + return _database; + } + + Map toMap() { + return { + 'accountId': accountId?.toInt(), + 'sessionId': sessionId, + 'accessToken': accessToken, + 'accessTokenExpiresAt': accessTokenExpiresAt?.toDateTime().toString(), + 'refreshToken': refreshToken, + 'refreshTokenExpiresAt': refreshTokenExpiresAt?.toDateTime().toString(), + }; + } + + @override + String toString() { + return 'Session{accountId: $accountId, sessionId: $sessionId, accessToken: $accessToken, accessTokenExpiresAt: ${accessTokenExpiresAt.toString()}, refreshToken: $refreshToken, refreshTokenExpiresAt: ${refreshTokenExpiresAt.toString()}}'; + } + + Future insertSession(Session session) async { + print('INSERTING SESSION: ${session.sessionId}'); + final db = _database; + final result = await db.insert( + 'sessions', + session.toMap(), + conflictAlgorithm: ConflictAlgorithm.replace, + ); + print('INSERT RESULT: $result'); + } + + Future> getSessions() async { + final db = await database; + + final List> maps = await db.query('sessions'); + + final List sessions = List.generate( + maps.length, + (i) { + print('GOT MAP: ${maps[i]}'); + + return Session( + sessionId: maps[i]['sessionId'] as String, + accessToken: maps[i]['accessToken'] as String, + accessTokenExpiresAt: Timestamp.fromDateTime( + DateTime.parse(maps[i]['accessTokenExpiresAt'] as String)), + refreshToken: maps[i]['refreshToken'] as String, + refreshTokenExpiresAt: Timestamp.fromDateTime( + DateTime.parse(maps[i]['refreshTokenExpiresAt'] as String)), + accountId: Int64(maps[i]['accountId'] as int), + ); + }, + ); + + return sessions; + } + + static Future getSession(Int64 accountId) async { + final Database db = await openDatabase( + join(await getDatabasesPath(), 'df_database.db'), + onCreate: (db, version) { + return db.execute( + 'CREATE TABLE sessions(accountId INTEGER PRIMARY KEY, sessionId TEXT, accessToken TEXT, accessTokenExpiresAt TEXT, refreshToken TEXT, refreshTokenExpiresAt TEXT)', + ); + }, + version: 1, + ); + + final List> maps = await db.query('sessions', + where: 'accountId = ?', whereArgs: [accountId], limit: 1); + + final List sessions = List.generate( + maps.length, + (i) { + return Session( + sessionId: maps[i]['sessionId'] as String, + accessToken: maps[i]['accessToken'] as String, + accessTokenExpiresAt: maps[i]['accessTokenExpiresAt'] as Timestamp, + refreshToken: maps[i]['refreshToken'] as String, + refreshTokenExpiresAt: maps[i]['refreshTokenExpiresAt'] as Timestamp, + accountId: maps[i]['accountId'] as Int64, + ); + }, + ); + + return sessions[0]; + } +} diff --git a/frontend/app/lib/gapi/client.dart b/frontend/app/lib/gapi/client.dart index e4e225e..bacf512 100644 --- a/frontend/app/lib/gapi/client.dart +++ b/frontend/app/lib/gapi/client.dart @@ -1,3 +1,4 @@ +import 'package:app/data/database.dart'; import 'package:fixnum/fixnum.dart'; import 'package:app/pb/rpc_create_account.pb.dart'; import 'package:app/pb/rpc_get_account_info.pb.dart'; @@ -6,12 +7,28 @@ import 'package:app/pb/service_df.pbgrpc.dart'; import 'package:grpc/grpc.dart'; class GClient { + GClient() { + // session = Session.newSession(); + _init(); + } + String baseUrl = 'localhost'; int port = 9090; Map metadata = {'Authorization': ''}; - String accessToken = ''; - Int64 accountId = Int64(); + // String accessToken = ''; + // Int64 accountId = Int64(); + + late Session session; + + static Future get client async { + Session s = await Session.newSession; + GClient c = GClient(); + c.session = s; + final sessions = await c.session.getSessions(); + c.session = sessions[0]; + return c; + } dfClient stub = dfClient( ClientChannel('10.0.2.2', @@ -25,6 +42,19 @@ class GClient { ); Future main(List args) async {} + void _init() async { + // print('CLIENT: INITIALIZING CLIENT - start'); + + session = await Session.newSession; + // print('CLIENT: getting sessions from database'); + + final sessions = await session.getSessions(); + print('CLIENT: got sessions from database: ${sessions.toString()}'); + session = sessions[0]; + // print('CLIENT: INITIALIZING CLIENT - end'); + print(session.toString()); + } + Future createAccount( CreateAccountRequest request) async { try { @@ -47,8 +77,19 @@ class GClient { email: email, password: password, )); - accessToken = response.accessToken; - accountId = response.accountId; + print(response); + session.accessToken = response.accessToken; + session.accountId = response.accountId; + session.sessionId = response.sessionId; + session.refreshToken = response.refreshToken; + session.accessTokenExpiresAt = response.accessTokenExpiresAt; + session.refreshTokenExpiresAt = response.refreshTokenExpiresAt; + print('GOT: ${session.toString()}'); + try { + session.insertSession(session); + } catch (err) { + print('ERROR WRITING DB: $err'); + } metadata['Authorization'] = 'Bearer ${response.accessToken}'; print('auth: ${metadata['Authorization']}'); onSuccess(); diff --git a/frontend/app/lib/main.dart b/frontend/app/lib/main.dart index 4a983e1..78e9a9a 100644 --- a/frontend/app/lib/main.dart +++ b/frontend/app/lib/main.dart @@ -1,4 +1,3 @@ -import 'package:app/pages/home_page.dart'; import 'package:app/pages/start_page.dart'; import 'package:app/widgets/background.dart'; import 'package:flutter/material.dart'; diff --git a/frontend/app/lib/pages/dashboard_page.dart b/frontend/app/lib/pages/dashboard_page.dart index 012d74a..70a1ea9 100644 --- a/frontend/app/lib/pages/dashboard_page.dart +++ b/frontend/app/lib/pages/dashboard_page.dart @@ -5,29 +5,8 @@ import 'package:app/widgets/background.dart'; import 'package:app/widgets/loading_widget.dart'; import 'package:flutter/material.dart'; -GlobalKey scaffolKey = GlobalKey(); - -List bottomBarButtons = const [ - BottomNavigationBarItem( - label: 'Zurueck', - backgroundColor: Colors.white, - icon: Icon( - Icons.arrow_back, - color: Colors.white, - ), - ), - BottomNavigationBarItem( - backgroundColor: Colors.white, - label: 'AccountInf', - icon: Icon( - Icons.person, - color: Colors.white, - ), - ), -]; - class DashboardPage extends StatefulWidget { - DashboardPage({super.key, required this.client}); + const DashboardPage({super.key, required this.client}); final GClient client; @@ -48,15 +27,15 @@ class _DashboardPageState extends State { @override void initState() { super.initState(); - if (widget.client.accessToken == '') { - Navigator.of(context).pop(); - return; - } + // if (widget.client.session.accessToken == '') { + // Navigator.of(context).pop(); + // return; + // } _setLoading(true); widget.client.getAccountInfo( GetAccountInfoRequest( - accountId: widget.client.accountId, + accountId: widget.client.session?.accountId, ), onError: () { ScaffoldMessenger.of(context).showSnackBar(const SnackBar( @@ -73,7 +52,6 @@ class _DashboardPageState extends State { Widget build(BuildContext context) { return Background( child: Scaffold( - key: scaffolKey, appBar: AppBar( automaticallyImplyLeading: false, flexibleSpace: Image.asset( @@ -81,10 +59,7 @@ class _DashboardPageState extends State { height: 80, ), ), - bottomNavigationBar: BottomNavigationBar( - items: bottomBarButtons, - backgroundColor: Colors.black, - ), + bottomNavigationBar: BottomBar(), body: !_loading ? Background( child: Center( @@ -108,3 +83,40 @@ class _DashboardPageState extends State { ); } } + +class BottomBar extends StatelessWidget { + const BottomBar({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return BottomNavigationBar( + items: [ + BottomNavigationBarItem( + label: 'back', + backgroundColor: Colors.white, + icon: IconButton( + onPressed: () => Navigator.of(context).pop(), + icon: const Icon( + Icons.arrow_back, + color: Colors.white, + ), + ), + ), + BottomNavigationBarItem( + backgroundColor: Colors.white, + label: 'Menu', + icon: IconButton( + onPressed: () => Scaffold.of(context).openDrawer(), + icon: const Icon( + Icons.person, + color: Colors.white, + ), + ), + ), + ], + backgroundColor: Colors.black, + ); + } +} diff --git a/frontend/app/lib/pages/home_page.dart b/frontend/app/lib/pages/home_page.dart deleted file mode 100644 index 6b544e8..0000000 --- a/frontend/app/lib/pages/home_page.dart +++ /dev/null @@ -1,158 +0,0 @@ -import 'package:app/gapi/client.dart'; -import 'package:app/pages/login_page.dart'; -import 'package:app/pages/start_page.dart'; -import 'package:flutter/material.dart'; -import 'package:app/pages/pages.dart'; - -Map> bottomBarButtons = { - Pages.start: const [ - BottomNavigationBarItem( - label: 'Zurueck', - backgroundColor: Colors.white, - icon: Icon( - Icons.arrow_back, - color: Colors.white, - ), - ), - BottomNavigationBarItem( - backgroundColor: Colors.white, - label: 'AccountInf', - icon: Icon( - Icons.person, - color: Colors.white, - ), - ), - ], - Pages.persons: const [ - BottomNavigationBarItem( - label: 'Zurueck', - backgroundColor: Colors.white, - icon: Icon( - Icons.arrow_back, - color: Colors.white, - ), - ), - BottomNavigationBarItem( - backgroundColor: Colors.white, - label: 'AccountInf', - icon: Icon( - Icons.person, - color: Colors.white, - ), - ), - ], - Pages.about: const [ - BottomNavigationBarItem( - label: 'Zurueck', - backgroundColor: Colors.white, - icon: Icon( - Icons.arrow_back, - color: Colors.white, - ), - ), - BottomNavigationBarItem( - backgroundColor: Colors.white, - label: 'AccountInf', - icon: Icon( - Icons.person, - color: Colors.white, - ), - ), - ], - Pages.login: const [ - BottomNavigationBarItem( - label: 'Zurueck', - backgroundColor: Colors.white, - icon: Icon( - Icons.arrow_back, - color: Colors.white, - ), - ), - BottomNavigationBarItem( - backgroundColor: Colors.white, - label: 'AccountInf', - icon: Icon( - Icons.person, - color: Colors.white, - ), - ), - ] -}; - -class HomePage extends StatefulWidget { - const HomePage({super.key}); - - @override - State createState() => _HomePageState(); -} - -class _HomePageState extends State { - bool _loading = false; - - Pages _selectedPage = Pages.start; - - Widget _selectPage(Pages page) { - switch (page) { - case Pages.login: - return LoginPage( - // onChangePage: changePage, - ); - default: - return StartPage( - // onChangePage: changePage, - ); - } - } - - Future _onWillPop() async { - changePage(Pages.start); - return false; - } - - void changePage(Pages page) { - if (!Pages.values.contains(page)) { - page = _selectedPage; - } - setState(() { - _selectedPage = page; - }); - } - - void _setLoading(bool loading) { - setState(() { - _loading = loading; - }); - } - - final GClient client = GClient(); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: _selectedPage == Pages.start - ? AppBar( - automaticallyImplyLeading: false, - ) - : AppBar( - automaticallyImplyLeading: false, - flexibleSpace: Image.asset( - 'lib/assets/logo_300x200.png', - height: 80, - ), - ), - bottomNavigationBar: BottomNavigationBar( - items: bottomBarButtons[_selectedPage]!.toList(), - backgroundColor: Colors.black, - ), - body: Container( - padding: const EdgeInsets.fromLTRB(16, 32, 16, 32), - child: Center( - child: WillPopScope( - child: _selectPage(_selectedPage), - onWillPop: () => _onWillPop(), - ), - ), - ), - ); - } -} diff --git a/frontend/app/lib/pages/login_page.dart b/frontend/app/lib/pages/login_page.dart index 9daad16..334911e 100644 --- a/frontend/app/lib/pages/login_page.dart +++ b/frontend/app/lib/pages/login_page.dart @@ -5,29 +5,7 @@ import 'package:app/widgets/loading_widget.dart'; import 'package:flutter/material.dart'; import 'package:grpc/grpc.dart'; -GlobalKey scaffoldKey = GlobalKey(); - -List bottomBarButtons = [ - const BottomNavigationBarItem( - label: 'back', - backgroundColor: Colors.white, - icon: Icon( - Icons.arrow_back, - color: Colors.white, - ), - ), - BottomNavigationBarItem( - backgroundColor: Colors.white, - label: 'Menu', - icon: IconButton( - onPressed: () => scaffoldKey.currentState!.openDrawer(), - icon: const Icon( - Icons.menu, - color: Colors.white, - ), - ), - ), -]; +// GlobalKey scaffoldKey = GlobalKey(); class LoginPage extends StatefulWidget { LoginPage({ @@ -43,16 +21,46 @@ class LoginPage extends StatefulWidget { class _LoginPageState extends State { bool _loading = false; + final List bottombarButtons = []; - List _selectedBottomBarButtons = bottomBarButtons; + // List _selectedBottomBarButtons = bottomBarButtons; + @override + void initState() { + super.initState(); + _addBottomBarButtons(); + } void _bottomBarAction(int index) { - switch (_selectedBottomBarButtons[index].label?.toLowerCase()) { + switch (bottombarButtons[index].label?.toLowerCase()) { case 'back': Navigator.of(context).pop(); } } + void _addBottomBarButtons() { + bottombarButtons.addAll([ + const BottomNavigationBarItem( + label: 'back', + backgroundColor: Colors.white, + icon: Icon( + Icons.arrow_back, + color: Colors.white, + ), + ), + BottomNavigationBarItem( + backgroundColor: Colors.white, + label: 'Menu', + icon: IconButton( + onPressed: () => Scaffold.of(context).openDrawer(), + icon: const Icon( + Icons.menu, + color: Colors.white, + ), + ), + ), + ]); + } + void _setLoading(bool loading) { setState(() { _loading = loading; @@ -69,7 +77,6 @@ class _LoginPageState extends State { Widget build(BuildContext context) { return Background( child: Scaffold( - key: scaffoldKey, appBar: AppBar( automaticallyImplyLeading: false, // flexibleSpace: Image.asset( @@ -77,81 +84,8 @@ class _LoginPageState extends State { // height: 80, // ), ), - bottomNavigationBar: BottomNavigationBar( - items: bottomBarButtons, - backgroundColor: Colors.black, - fixedColor: Colors.black, - onTap: (value) => _bottomBarAction(value), - ), - drawer: Drawer( - backgroundColor: Colors.black, - child: Padding( - padding: const EdgeInsets.all(40.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Spacer(), - TextButton( - onPressed: () { - scaffoldKey.currentState!.closeDrawer(); - }, - child: const Row( - children: [ - Text( - 'About', - style: TextStyle(fontSize: 20), - ), - Spacer(), - Icon( - Icons.question_answer, - color: Colors.white, - ), - ], - ), - ), - TextButton( - onPressed: () { - scaffoldKey.currentState!.closeDrawer(); - }, - child: const Row( - children: [ - Text( - 'Datenschutz', - style: TextStyle(fontSize: 20), - ), - Spacer(), - Icon( - Icons.privacy_tip, - color: Colors.white, - ), - ], - ), - ), - TextButton( - onPressed: () { - scaffoldKey.currentState!.closeDrawer(); - }, - child: const Row( - children: [ - Text( - 'Impressum', - style: TextStyle(fontSize: 20), - ), - Spacer(), - Icon( - Icons.apartment, - color: Colors.white, - ), - ], - ), - ), - const SizedBox( - height: 250, - ) - ], - ), - ), - ), + bottomNavigationBar: const BottomBar(), + drawer: const SideDrawer(), body: !_loading ? Form( key: _formKey, @@ -227,7 +161,7 @@ class _LoginPageState extends State { return null; }, ), - SizedBox( + const SizedBox( height: 15, ), ElevatedButton( @@ -322,3 +256,121 @@ class _LoginPageState extends State { ); } } + +class SideDrawer extends StatelessWidget { + const SideDrawer({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return Drawer( + backgroundColor: Colors.black, + child: Padding( + padding: const EdgeInsets.all(40.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Spacer(), + TextButton( + onPressed: () { + Scaffold.of(context).closeDrawer(); + }, + child: const Row( + children: [ + Text( + 'About', + style: TextStyle(fontSize: 20), + ), + Spacer(), + Icon( + Icons.question_answer, + color: Colors.white, + ), + ], + ), + ), + TextButton( + onPressed: () { + Scaffold.of(context).closeDrawer(); + }, + child: const Row( + children: [ + Text( + 'Datenschutz', + style: TextStyle(fontSize: 20), + ), + Spacer(), + Icon( + Icons.privacy_tip, + color: Colors.white, + ), + ], + ), + ), + TextButton( + onPressed: () { + Scaffold.of(context).closeDrawer(); + }, + child: const Row( + children: [ + Text( + 'Impressum', + style: TextStyle(fontSize: 20), + ), + Spacer(), + Icon( + Icons.apartment, + color: Colors.white, + ), + ], + ), + ), + const SizedBox( + height: 250, + ) + ], + ), + ), + ); + } +} + +class BottomBar extends StatelessWidget { + const BottomBar({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return BottomNavigationBar( + items: [ + BottomNavigationBarItem( + label: 'back', + backgroundColor: Colors.white, + icon: IconButton( + onPressed: () => Navigator.of(context).pop(), + icon: const Icon( + Icons.arrow_back, + color: Colors.white, + ), + ), + ), + BottomNavigationBarItem( + backgroundColor: Colors.white, + label: 'Menu', + icon: IconButton( + onPressed: () => Scaffold.of(context).openDrawer(), + icon: const Icon( + Icons.menu, + color: Colors.white, + ), + ), + ), + ], + backgroundColor: Colors.black, + fixedColor: Colors.black, + // onTap: (value) => _bottomBarAction(value), + ); + } +} diff --git a/frontend/app/lib/pages/start_page.dart b/frontend/app/lib/pages/start_page.dart index c1a6d59..308619a 100644 --- a/frontend/app/lib/pages/start_page.dart +++ b/frontend/app/lib/pages/start_page.dart @@ -4,170 +4,41 @@ import 'package:app/widgets/background.dart'; import 'package:flutter/material.dart'; import 'dart:core'; -GlobalKey scaffoldKey = GlobalKey(); - -List bottomBarButtons = [ - const BottomNavigationBarItem( - label: 'register', - backgroundColor: Colors.white, - icon: Column( - children: [ - Icon( - Icons.person_add, - color: Colors.white, - ), - Text( - 'Registrieren', - style: TextStyle( - color: Colors.white, - fontSize: 16, - ), - ) - ], - ), - ), - const BottomNavigationBarItem( - label: 'login', - backgroundColor: Colors.white, - icon: Column( - children: [ - Icon( - Icons.login, - color: Colors.white, - ), - Text( - 'Login', - style: TextStyle( - color: Colors.white, - fontSize: 16, - ), - ) - ], - ), - ), - BottomNavigationBarItem( - backgroundColor: Colors.white, - label: 'Menu', - icon: IconButton( - onPressed: () => scaffoldKey.currentState!.openDrawer(), - icon: const Icon( - Icons.menu, - color: Colors.white, - ), - ), - ), -]; - class StartPage extends StatefulWidget { StartPage({ super.key, this.client, }); - final GClient? client; + GClient? client; @override State createState() => _StartPageState(); } class _StartPageState extends State { - List _selectedBottomBarButtons = bottomBarButtons; + // List _selectedBottomBarButtons = bottomBarButtons; + final List bottombarButtons = []; - void _bottomBarAction(int index) { - switch (_selectedBottomBarButtons[index].label?.toLowerCase()) { - case 'login': - Navigator.of(context) - .push(MaterialPageRoute(builder: (context) => LoginPage())); - } + void _init() async { + widget.client ??= await GClient.client; + } + + @override + void initState() { + _init(); + super.initState(); } @override Widget build(BuildContext context) { return Background( child: Scaffold( - key: scaffoldKey, appBar: AppBar( automaticallyImplyLeading: false, - // flexibleSpace: Image.asset( - // 'lib/assets/logo_300x200.png', - // height: 80, - // ), - ), - drawer: Drawer( - backgroundColor: Colors.black, - child: Padding( - padding: const EdgeInsets.all(40.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Spacer(), - TextButton( - onPressed: () { - scaffoldKey.currentState!.closeDrawer(); - }, - child: const Row( - children: [ - Text( - 'About', - style: TextStyle(fontSize: 20), - ), - Spacer(), - Icon( - Icons.question_answer, - color: Colors.white, - ), - ], - ), - ), - TextButton( - onPressed: () { - scaffoldKey.currentState!.closeDrawer(); - }, - child: const Row( - children: [ - Text( - 'Datenschutz', - style: TextStyle(fontSize: 20), - ), - Spacer(), - Icon( - Icons.privacy_tip, - color: Colors.white, - ), - ], - ), - ), - TextButton( - onPressed: () { - scaffoldKey.currentState!.closeDrawer(); - }, - child: const Row( - children: [ - Text( - 'Impressum', - style: TextStyle(fontSize: 20), - ), - Spacer(), - Icon( - Icons.apartment, - color: Colors.white, - ), - ], - ), - ), - const SizedBox( - height: 250, - ) - ], - ), - ), - ), - bottomNavigationBar: BottomNavigationBar( - onTap: (value) => _bottomBarAction(value), - items: bottomBarButtons, - backgroundColor: Colors.black, - fixedColor: Colors.black, ), + drawer: const SideDrawer(), + bottomNavigationBar: BottomBar(widget: widget), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( @@ -192,6 +63,16 @@ class _StartPageState extends State { letterSpacing: 6, ), ), + TextButton( + onPressed: () { + final s = widget.client?.session.getSessions(); + print(s); + print(widget.client?.session.accessToken); + }, + child: const Text( + "GET SESSIONS", + ), + ), // const Spacer(), // Row( // mainAxisAlignment: MainAxisAlignment.spaceEvenly, @@ -238,3 +119,199 @@ class _StartPageState extends State { ); } } + +class SideDrawer extends StatelessWidget { + const SideDrawer({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return Drawer( + backgroundColor: Colors.black, + child: Padding( + padding: const EdgeInsets.all(40.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Spacer(), + TextButton( + onPressed: () { + Scaffold.of(context).closeDrawer(); + }, + child: const Row( + children: [ + Text( + 'About', + style: TextStyle(fontSize: 20), + ), + Spacer(), + Icon( + Icons.question_answer, + color: Colors.white, + ), + ], + ), + ), + TextButton( + onPressed: () { + Scaffold.of(context).closeDrawer(); + }, + child: const Row( + children: [ + Text( + 'Datenschutz', + style: TextStyle(fontSize: 20), + ), + Spacer(), + Icon( + Icons.privacy_tip, + color: Colors.white, + ), + ], + ), + ), + TextButton( + onPressed: () { + Scaffold.of(context).closeDrawer(); + }, + child: const Row( + children: [ + Text( + 'Impressum', + style: TextStyle(fontSize: 20), + ), + Spacer(), + Icon( + Icons.apartment, + color: Colors.white, + ), + ], + ), + ), + const SizedBox( + height: 250, + ) + ], + ), + ), + ); + } +} + +class BottomBar extends StatelessWidget { + const BottomBar({ + super.key, + required this.widget, + }); + + final StartPage widget; + + @override + Widget build(BuildContext context) { + return BottomNavigationBar( + // onTap: (value) => _bottomBarAction(value), + items: widget.client?.session.accessToken != null + ? [ + BottomNavigationBarItem( + backgroundColor: Colors.white, + label: 'Personen', + icon: Column( + children: [ + IconButton( + onPressed: () => Scaffold.of(context).openDrawer(), + icon: const Icon( + Icons.group, + color: Colors.white, + ), + ), + const Text( + 'Personen', + style: TextStyle( + color: Colors.white, + fontSize: 16, + ), + ) + ], + ), + ), + BottomNavigationBarItem( + backgroundColor: Colors.white, + label: 'Menu', + icon: IconButton( + onPressed: () => Scaffold.of(context).openDrawer(), + icon: const Icon( + Icons.menu, + color: Colors.white, + ), + ), + ) + ] + : [ + BottomNavigationBarItem( + label: 'register', + backgroundColor: Colors.white, + icon: Column( + children: [ + IconButton( + onPressed: () { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => LoginPage())); + }, + icon: const Icon( + Icons.login, + color: Colors.white, + ), + ), + const Text( + 'Registrieren', + style: TextStyle( + color: Colors.white, + fontSize: 16, + ), + ) + ], + ), + ), + BottomNavigationBarItem( + label: 'login', + backgroundColor: Colors.white, + icon: Column( + children: [ + IconButton( + onPressed: () { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => LoginPage())); + }, + icon: const Icon( + Icons.login, + color: Colors.white, + ), + ), + const Text( + 'Login', + style: TextStyle( + color: Colors.white, + fontSize: 16, + ), + ) + ], + ), + ), + BottomNavigationBarItem( + backgroundColor: Colors.white, + label: 'Menu', + icon: IconButton( + onPressed: () => Scaffold.of(context).openDrawer(), + icon: const Icon( + Icons.menu, + color: Colors.white, + ), + ), + ), + ], + backgroundColor: Colors.black, + fixedColor: Colors.black, + ); + } +} diff --git a/frontend/app/pubspec.lock b/frontend/app/pubspec.lock index 687c22e..9323a01 100644 --- a/frontend/app/pubspec.lock +++ b/frontend/app/pubspec.lock @@ -90,7 +90,7 @@ packages: source: hosted version: "1.3.1" fixnum: - dependency: transitive + dependency: "direct main" description: name: fixnum sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" @@ -196,7 +196,7 @@ packages: source: hosted version: "1.9.1" path: - dependency: transitive + dependency: "direct main" description: name: path sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" @@ -232,6 +232,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.10.0" + sqflite: + dependency: "direct main" + description: + name: sqflite + sha256: "591f1602816e9c31377d5f008c2d9ef7b8aca8941c3f89cc5fd9d84da0c38a9a" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "1b92f368f44b0dee2425bb861cfa17b6f6cf3961f762ff6f941d20b33355660a" + url: "https://pub.dev" + source: hosted + version: "2.5.0" stack_trace: dependency: transitive description: @@ -256,6 +272,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60" + url: "https://pub.dev" + source: hosted + version: "3.1.0" term_glyph: dependency: transitive description: @@ -298,3 +322,4 @@ packages: version: "0.1.4-beta" sdks: dart: ">=3.1.4 <4.0.0" + flutter: ">=3.3.0" diff --git a/frontend/app/pubspec.yaml b/frontend/app/pubspec.yaml index 07e48bb..f28d267 100644 --- a/frontend/app/pubspec.yaml +++ b/frontend/app/pubspec.yaml @@ -39,6 +39,9 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 grpc: ^3.2.4 + sqflite: ^2.3.0 + path: ^1.8.3 + fixnum: ^1.1.0 dev_dependencies: lints: ^2.0.0