From c7fe414bc6745c976dd7da8de16a8481c53570f3 Mon Sep 17 00:00:00 2001 From: Nicolas Gruber Date: Fri, 19 May 2023 14:26:09 +0200 Subject: [PATCH 1/5] first aut --- android/build.gradle | 2 +- lib/AddPage.dart | 53 +++++++++++--------- lib/UserDefinedList.dart | 102 +++++++++++++++++++++++++++++---------- lib/anonym_aut.dart | 45 +++++++++++++++++ lib/home.dart | 3 +- lib/main.dart | 11 ++++- pubspec.lock | 56 +++++++++++++-------- pubspec.yaml | 1 + 8 files changed, 200 insertions(+), 73 deletions(-) create mode 100644 lib/anonym_aut.dart diff --git a/android/build.gradle b/android/build.gradle index 9192654..2139d26 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -29,6 +29,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/lib/AddPage.dart b/lib/AddPage.dart index b717bb4..f5977be 100644 --- a/lib/AddPage.dart +++ b/lib/AddPage.dart @@ -1,5 +1,6 @@ import 'dart:io'; import 'dart:math'; +import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; @@ -10,7 +11,7 @@ import 'package:image/image.dart' as img; class AddScreen extends StatefulWidget { final int initialIndex; - const AddScreen({super.key, required this.initialIndex}); + const AddScreen({Key? key, required this.initialIndex}) : super(key: key); @override _AddScreenState createState() => _AddScreenState(); @@ -71,18 +72,22 @@ class _AddScreenState extends State { if (originalImage != null) { if (originalImage.width == originalImage.height) { // Wenn das Bild bereits im 1:1-Format ist, überspringen Sie das Zuschneiden - setState(() { - _imageFile = tempFile; - print("1:1"); - }); + if(mounted) { + setState(() { + _imageFile = tempFile; + print("1:1"); + }); + } } else { // Wenn das Bild nicht im 1:1-Format ist, schneiden Sie es zu File croppedFile = await _cropImage(tempFile); - setState(() { - _imageFile = croppedFile; - }); - print("decode"); + if(mounted) { + setState(() { + _imageFile = croppedFile; + }); + print("decode"); + } } } else { throw Exception('Unable to decode image file.'); @@ -108,23 +113,23 @@ class _AddScreenState extends State { } String imageUrl = await uploadImageToFirebaseStorage(imageFile, collectionName); - try - { + String? userId = FirebaseAuth.instance.currentUser?.uid; // get the user ID + + try { await FirebaseFirestore.instance.collection(collectionName).add({ "title": title, "description": description, "imageUrl": imageUrl, "createdDate": DateTime.now(), + "userId": userId, // add the user ID to the document }); onComplete(true); - } - catch(e) - { + } catch(e) { onComplete(false); } - } + Future uploadImageToFirebaseStorage(File imageFile, String collectionName) async { Reference ref = FirebaseStorage.instance.ref().child("$collectionName/${DateTime.now().toString()}"); UploadTask uploadTask = ref.putFile(imageFile); @@ -172,14 +177,16 @@ class _AddScreenState extends State { }); Navigator.pop(context); // Fenster direkt schließen, nachdem der Upload-Button gedrückt wurde. await addNewElementToFirestore(_titleController.text, _descriptionController.text, _imageFile!, onComplete: (bool success) { - setState(() { - _uploading = false; - }); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(success ? 'Upload erfolgreich.' : 'Upload fehlgeschlagen.'), - ), - ); + if(mounted) { + setState(() { + _uploading = false; + }); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(success ? 'Upload erfolgreich.' : 'Upload fehlgeschlagen.'), + ), + ); + } }); } }, diff --git a/lib/UserDefinedList.dart b/lib/UserDefinedList.dart index 336a2a0..b314b1a 100644 --- a/lib/UserDefinedList.dart +++ b/lib/UserDefinedList.dart @@ -1,9 +1,11 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:printing/printing.dart'; +import 'package:provider/provider.dart'; import 'AddPage.dart'; import 'DetailPage.dart'; import 'package:intl/intl.dart'; @@ -11,6 +13,8 @@ import 'package:pdf/widgets.dart' as pdfWidgets; import 'package:http/http.dart' as http; import 'package:image/image.dart' as img; +import 'anonym_aut.dart'; + class UserDefinedItem extends StatelessWidget { final String title; final String datum; @@ -208,23 +212,59 @@ class _GenericListState extends State { final DateTime createdDate = data['createdDate'].toDate(); final formattedDate = DateFormat('dd.MM.yyyy').format(createdDate); - return Dismissible( - key: UniqueKey(), - direction: DismissDirection.endToStart, - onDismissed: (direction) { - _deleteDocument(documentId, data['imageUrl']); - }, - background: Container( - color: Colors.red, - child: const Align( - alignment: Alignment.centerRight, - child: Padding( - padding: EdgeInsets.only(right: 16), - child: Icon(Icons.delete, color: Colors.white), + final currentUser = FirebaseAuth.instance.currentUser; + + if (currentUser != null && data['userId'] == currentUser.uid) { + return Dismissible( + key: UniqueKey(), + direction: DismissDirection.endToStart, + onDismissed: (direction) { + _deleteDocument(documentId, data['imageUrl']); + }, + background: Container( + color: Colors.red, + child: const Align( + alignment: Alignment.centerRight, + child: Padding( + padding: EdgeInsets.only(right: 16), + child: Icon(Icons.delete, color: Colors.white), + ), ), ), - ), - child: UserDefinedItem( + child: UserDefinedItem( + title: data['title'] ?? '', + datum: formattedDate, + description: data['description'] ?? '', + imageUrl: data['imageUrl'] ?? '', + isSelected: selectedItems.containsKey(documentId), + onTap: () { + clearSelectedItems(); + // Open a new screen when the user taps on the list item + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => DetailPage( + title: data['title'], + datum: formattedDate, + description: data['description'], + imageUrl: data['imageUrl'], + ), + ), + ); + }, + onLongPress: () { + setState(() { + if (selectedItems.containsKey(documentId)) { + selectedItems.remove(documentId); + } else { + selectedItems[documentId] = data; + } + }); + }, + ), + ); + } else { + return UserDefinedItem( title: data['title'] ?? '', datum: formattedDate, description: data['description'] ?? '', @@ -254,8 +294,9 @@ class _GenericListState extends State { } }); }, - ), - ); + ); + } + }, ); } @@ -295,17 +336,26 @@ class _GenericListState extends State { ], ), - floatingActionButton: FloatingActionButton( - onPressed: () { - clearSelectedItems(); - Navigator.push( - context, - MaterialPageRoute(builder: (context) => AddScreen(initialIndex: widget.selectedIndex)), - ); + floatingActionButton: Consumer( + builder: (context, authState, child) { + if (authState.isSignedIn) { + return FloatingActionButton( + onPressed: () { + clearSelectedItems(); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => AddScreen(initialIndex: widget.selectedIndex)), + ); + }, + tooltip: "Neues Element hinzufügen", + child: const Icon(Icons.add), + ); + } else { + return Container(); // Return an empty container when the user is not signed in + } }, - tooltip: "Neues Element hinzufügen", - child: const Icon(Icons.add), ), + ); } diff --git a/lib/anonym_aut.dart b/lib/anonym_aut.dart new file mode 100644 index 0000000..dba2e1a --- /dev/null +++ b/lib/anonym_aut.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:provider/provider.dart'; + +class AuthState extends ChangeNotifier { + FirebaseAuth auth = FirebaseAuth.instance; + bool _isSignedIn = false; + + bool get isSignedIn => _isSignedIn; + + Future signInAnonymously() async { + try { + await auth.signInAnonymously(); + _isSignedIn = true; + notifyListeners(); + } catch (e) { + print(e); + } + } + + Future signOut() async { + await auth.signOut(); + _isSignedIn = false; + notifyListeners(); + } +} +class AnonymAuthScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Consumer( + builder: (context, authState, child) { + return ElevatedButton( + onPressed: authState.isSignedIn + ? authState.signOut + : authState.signInAnonymously, + child: Text(authState.isSignedIn ? 'Abmelden' : 'Anonym anmelden'), + ); + }, + ), + ), + ); + } +} diff --git a/lib/home.dart b/lib/home.dart index 44367e4..f4997e8 100644 --- a/lib/home.dart +++ b/lib/home.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:oggauergemeindetrommler/LoginPage.dart'; import 'UserDefinedList.dart'; +import 'anonym_aut.dart'; class MyHomePage extends StatefulWidget { const MyHomePage({Key? key, required this.title}); @@ -23,7 +24,7 @@ class _MyHomePageState extends State { const GenericList(collectionName: 'CitizensForum', selectedIndex: 0,), const GenericList(collectionName: 'News', selectedIndex: 1,), const GenericList(collectionName: 'Issues', selectedIndex: 2,), - LoginPage() + AnonymAuthScreen() ]; return Scaffold( diff --git a/lib/main.dart b/lib/main.dart index 5374ad6..b7b7e22 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'anonym_aut.dart'; import 'home.dart'; import 'package:firebase_core/firebase_core.dart'; import 'firebase_options.dart'; @@ -8,10 +10,15 @@ void main() async { await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); - runApp(const MyApp()); - + runApp( + ChangeNotifierProvider( + create: (context) => AuthState(), + child: const MyApp(), + ), + ); } + class MyApp extends StatelessWidget { const MyApp({super.key}); diff --git a/pubspec.lock b/pubspec.lock index c82e205..637e761 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.0" barcode: dependency: transitive description: @@ -85,10 +85,10 @@ packages: dependency: transitive description: name: characters - sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" clock: dependency: transitive description: @@ -125,10 +125,10 @@ packages: dependency: transitive description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.17.1" convert: dependency: transitive description: @@ -404,10 +404,10 @@ packages: dependency: transitive description: name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.7" lints: dependency: transitive description: @@ -428,10 +428,10 @@ packages: dependency: transitive description: name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted - version: "0.12.13" + version: "0.12.15" material_color_utilities: dependency: transitive description: @@ -444,10 +444,18 @@ packages: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" octo_image: dependency: transitive description: @@ -460,10 +468,10 @@ packages: dependency: transitive description: name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.8.3" path_parsing: dependency: transitive description: @@ -532,10 +540,10 @@ packages: dependency: transitive description: name: pdf_widget_wrapper - sha256: "754867bf32c4683da29ccc6bf31250905431fb0818a7258c153e21cd627b3212" + sha256: e9d31fd7782ce28ae346b127ea7d1cd748d799bddee379f31191693610e23749 url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.1" pedantic: dependency: transitive description: @@ -592,6 +600,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.2.4" + provider: + dependency: "direct main" + description: + name: provider + sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f + url: "https://pub.dev" + source: hosted + version: "6.0.5" qr: dependency: transitive description: @@ -681,10 +697,10 @@ packages: dependency: transitive description: name: test_api - sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb url: "https://pub.dev" source: hosted - version: "0.4.16" + version: "0.5.1" typed_data: dependency: transitive description: @@ -734,5 +750,5 @@ packages: source: hosted version: "6.2.2" sdks: - dart: ">=2.19.0 <3.0.0" - flutter: ">=3.7.0" + dart: ">=3.0.0-0 <4.0.0" + flutter: ">=3.9.0" diff --git a/pubspec.yaml b/pubspec.yaml index 31a2529..d2bbe54 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -51,6 +51,7 @@ dependencies: printing: ^5.10.4 image_cropper: ^3.0.3 logging: ^1.1.1 + provider: ^6.0.5 dev_dependencies: From 9d41a5f5f1bc864f72de43ca9ac5ed387bf8f72d Mon Sep 17 00:00:00 2001 From: Nicolas Gruber Date: Fri, 19 May 2023 17:06:12 +0200 Subject: [PATCH 2/5] changed name from ui to author_id and reduced Resolution from images on pdf list to reduce pdf size --- lib/AddPage.dart | 232 +++++++++++++++++++++------------------ lib/UserDefinedList.dart | 4 +- pubspec.lock | 40 +++---- 3 files changed, 146 insertions(+), 130 deletions(-) diff --git a/lib/AddPage.dart b/lib/AddPage.dart index f5977be..1ca45dc 100644 --- a/lib/AddPage.dart +++ b/lib/AddPage.dart @@ -7,14 +7,13 @@ import 'package:image_picker/image_picker.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:image/image.dart' as img; - class AddScreen extends StatefulWidget { final int initialIndex; const AddScreen({Key? key, required this.initialIndex}) : super(key: key); + @override _AddScreenState createState() => _AddScreenState(); - } class _AddScreenState extends State { @@ -25,7 +24,6 @@ class _AddScreenState extends State { bool _uploading = false; int _selectedIndex = 0; - @override void initState() { super.initState(); @@ -43,14 +41,13 @@ class _AddScreenState extends State { if (originalImage != null) { int originSize = min(originalImage.width, originalImage.height); - final croppedImage = img.copyCrop( - originalImage, - x: (originalImage.width - originSize)~/2, - y: (originalImage.height - originSize)~/2, + final croppedImage = img.copyCrop(originalImage, + x: (originalImage.width - originSize) ~/ 2, + y: (originalImage.height - originSize) ~/ 2, width: originSize, - height: originSize - ); - final newPath = imageFile.path.substring(0, imageFile.path.lastIndexOf('/')); + height: originSize); + final newPath = + imageFile.path.substring(0, imageFile.path.lastIndexOf('/')); final newFile = File('$newPath/cropped.jpg'); await newFile.writeAsBytes(img.encodePng(croppedImage)); return newFile; @@ -72,17 +69,16 @@ class _AddScreenState extends State { if (originalImage != null) { if (originalImage.width == originalImage.height) { // Wenn das Bild bereits im 1:1-Format ist, überspringen Sie das Zuschneiden - if(mounted) { + if (mounted) { setState(() { _imageFile = tempFile; print("1:1"); }); } - } else { // Wenn das Bild nicht im 1:1-Format ist, schneiden Sie es zu File croppedFile = await _cropImage(tempFile); - if(mounted) { + if (mounted) { setState(() { _imageFile = croppedFile; }); @@ -94,15 +90,16 @@ class _AddScreenState extends State { } } else { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Die Dateigröße darf maximal 10 MB betragen.')), + const SnackBar( + content: Text('Die Dateigröße darf maximal 10 MB betragen.')), ); } } } - - - Future addNewElementToFirestore(String title, String description, File imageFile, {required Function(bool) onComplete}) async { + Future addNewElementToFirestore( + String title, String description, File imageFile, + {required Function(bool) onComplete}) async { String collectionName; if (_selectedIndex == 0) { collectionName = "CitizensForum"; @@ -112,8 +109,9 @@ class _AddScreenState extends State { collectionName = "Issues"; } - String imageUrl = await uploadImageToFirebaseStorage(imageFile, collectionName); - String? userId = FirebaseAuth.instance.currentUser?.uid; // get the user ID + String imageUrl = + await uploadImageToFirebaseStorage(imageFile, collectionName); + String? userId = FirebaseAuth.instance.currentUser?.uid; // get the user ID try { await FirebaseFirestore.instance.collection(collectionName).add({ @@ -121,27 +119,29 @@ class _AddScreenState extends State { "description": description, "imageUrl": imageUrl, "createdDate": DateTime.now(), - "userId": userId, // add the user ID to the document + "author_uid": userId, // add the user ID to the document }); onComplete(true); - } catch(e) { + } catch (e) { onComplete(false); } } - - Future uploadImageToFirebaseStorage(File imageFile, String collectionName) async { - Reference ref = FirebaseStorage.instance.ref().child("$collectionName/${DateTime.now().toString()}"); + Future uploadImageToFirebaseStorage( + File imageFile, String collectionName) async { + Reference ref = FirebaseStorage.instance + .ref() + .child("$collectionName/${DateTime.now().toString()}"); UploadTask uploadTask = ref.putFile(imageFile); return await (await uploadTask).ref.getDownloadURL(); } - - @override Widget build(BuildContext context) { String appBarTitle = ''; + double keyboardHeight = MediaQuery.of(context).viewInsets.bottom; + if (_selectedIndex == 0) { appBarTitle = 'Neue BürgerForum Information'; } else if (_selectedIndex == 1) { @@ -171,19 +171,27 @@ class _AddScreenState extends State { child: IconButton( icon: const Icon(Icons.check), onPressed: () async { - if (_formKey.currentState!.validate() && _imageFile != null && !_uploading) { + if (_formKey.currentState!.validate() && + _imageFile != null && + !_uploading) { setState(() { _uploading = true; }); - Navigator.pop(context); // Fenster direkt schließen, nachdem der Upload-Button gedrückt wurde. - await addNewElementToFirestore(_titleController.text, _descriptionController.text, _imageFile!, onComplete: (bool success) { - if(mounted) { + Navigator.pop( + context); // Fenster direkt schließen, nachdem der Upload-Button gedrückt wurde. + await addNewElementToFirestore( + _titleController.text, + _descriptionController.text, + _imageFile!, onComplete: (bool success) { + if (mounted) { setState(() { _uploading = false; }); ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text(success ? 'Upload erfolgreich.' : 'Upload fehlgeschlagen.'), + content: Text(success + ? 'Upload erfolgreich.' + : 'Upload fehlgeschlagen.'), ), ); } @@ -237,96 +245,104 @@ class _AddScreenState extends State { ), const SizedBox(height: 16.0), _imageFile != null - ? Image.file(_imageFile!) - : Container( - height: 200.0, - decoration: BoxDecoration( - color: Colors.grey[200], - borderRadius: BorderRadius.circular(16.0), + ? Expanded( + child: LayoutBuilder( + builder: (context, constraints) { + double imageHeight = max(0, constraints.maxHeight - keyboardHeight); + return Container( + height: imageHeight, + child: Image.file(_imageFile!), + ); + }, ), - child: Center( - child: TextButton( - onPressed: () { - showModalBottomSheet( - context: context, - builder: (context) => - Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - height: 60, - padding: const EdgeInsets.symmetric( - horizontal: 16), - child: Row( - mainAxisAlignment: MainAxisAlignment - .spaceBetween, - children: [ - const Text( - 'Bild hinzufügen', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, + ) + + : Container( + height: 200.0, + decoration: BoxDecoration( + color: Colors.grey[200], + borderRadius: BorderRadius.circular(16.0), + ), + child: Center( + child: TextButton( + onPressed: () { + showModalBottomSheet( + context: context, + builder: (context) => Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + height: 60, + padding: const EdgeInsets.symmetric( + horizontal: 16), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Bild hinzufügen', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), ), - ), - IconButton( - icon: const Icon(Icons.close), - onPressed: () { + IconButton( + icon: const Icon(Icons.close), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ), + ), + Center( + child: SizedBox( + height: 80, + child: ListTile( + leading: const Icon(Icons.photo_library, + size: 40), + title: const Text( + 'Galerie auswählen', + style: TextStyle(fontSize: 20), + ), + onTap: () { Navigator.pop(context); + _getImage(ImageSource.gallery); }, ), - ], - ), - ), - Center( - child: SizedBox( - height: 80, - child: ListTile( - leading: const Icon( - Icons.photo_library, size: 40), - title: const Text( - 'Galerie auswählen', - style: TextStyle(fontSize: 20), - ), - onTap: () { - Navigator.pop(context); - _getImage(ImageSource.gallery); - }, ), ), - ), - Center( - child: SizedBox( - height: 80, - child: ListTile( - leading: const Icon( - Icons.camera_alt, size: 40), - title: const Text( - 'Kamera verwenden', - style: TextStyle(fontSize: 20), + Center( + child: SizedBox( + height: 80, + child: ListTile( + leading: const Icon(Icons.camera_alt, + size: 40), + title: const Text( + 'Kamera verwenden', + style: TextStyle(fontSize: 20), + ), + onTap: () { + Navigator.pop(context); + _getImage(ImageSource.camera); + }, ), - onTap: () { - Navigator.pop(context); - _getImage(ImageSource.camera); - }, ), ), - ), - ], + ], + ), + ); + }, + child: Text( + 'Bild hinzufügen', + style: TextStyle( + color: Theme.of(context).primaryColor, + fontWeight: FontWeight.bold, ), - ); - }, - child: Text( - 'Bild hinzufügen', - style: TextStyle( - color: Theme - .of(context) - .primaryColor, - fontWeight: FontWeight.bold, + ), + ), ), ), - ), - ), - ), ], ), ), diff --git a/lib/UserDefinedList.dart b/lib/UserDefinedList.dart index b314b1a..5ebb932 100644 --- a/lib/UserDefinedList.dart +++ b/lib/UserDefinedList.dart @@ -214,7 +214,7 @@ class _GenericListState extends State { DateFormat('dd.MM.yyyy').format(createdDate); final currentUser = FirebaseAuth.instance.currentUser; - if (currentUser != null && data['userId'] == currentUser.uid) { + if (currentUser != null && data['author_uid'] == currentUser.uid) { return Dismissible( key: UniqueKey(), direction: DismissDirection.endToStart, @@ -368,7 +368,7 @@ class _GenericListState extends State { final Uint8List bytes = response.bodyBytes; final img.Image? image = img.decodeImage(bytes); - final img.Image resizedImage = img.copyResize(image!, width: 500); // Beispielwert für die Breite + final img.Image resizedImage = img.copyResize(image!, width: 290); // Beispielwert für die Breite final Uint8List resizedBytes = Uint8List.fromList(img.encodeJpg(resizedImage)); final imageProvider = pdfWidgets.MemoryImage(resizedBytes); diff --git a/pubspec.lock b/pubspec.lock index 637e761..c87b753 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.10.0" barcode: dependency: transitive description: @@ -85,10 +85,10 @@ packages: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.2.1" clock: dependency: transitive description: @@ -125,10 +125,10 @@ packages: dependency: transitive description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.17.0" convert: dependency: transitive description: @@ -404,10 +404,10 @@ packages: dependency: transitive description: name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" url: "https://pub.dev" source: hosted - version: "0.6.7" + version: "0.6.5" lints: dependency: transitive description: @@ -428,10 +428,10 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.13" material_color_utilities: dependency: transitive description: @@ -444,10 +444,10 @@ packages: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.8.0" nested: dependency: transitive description: @@ -468,10 +468,10 @@ packages: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.8.2" path_parsing: dependency: transitive description: @@ -540,10 +540,10 @@ packages: dependency: transitive description: name: pdf_widget_wrapper - sha256: e9d31fd7782ce28ae346b127ea7d1cd748d799bddee379f31191693610e23749 + sha256: "754867bf32c4683da29ccc6bf31250905431fb0818a7258c153e21cd627b3212" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.0.0" pedantic: dependency: transitive description: @@ -697,10 +697,10 @@ packages: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.4.16" typed_data: dependency: transitive description: @@ -750,5 +750,5 @@ packages: source: hosted version: "6.2.2" sdks: - dart: ">=3.0.0-0 <4.0.0" - flutter: ">=3.9.0" + dart: ">=2.19.0 <3.0.0" + flutter: ">=3.7.0" From 3f43a016db6bc2f4d78b7b4dfd3d453aba19fe04 Mon Sep 17 00:00:00 2001 From: Nicolas Gruber Date: Fri, 19 May 2023 17:27:40 +0200 Subject: [PATCH 3/5] addet register site --- lib/LoginPage.dart | 7 +++- lib/register.dart | 98 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 lib/register.dart diff --git a/lib/LoginPage.dart b/lib/LoginPage.dart index fdca8a1..4f60ad4 100644 --- a/lib/LoginPage.dart +++ b/lib/LoginPage.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:oggauergemeindetrommler/register.dart'; class LoginPage extends StatefulWidget { LoginPage({Key? key}) : super(key: key); @@ -79,6 +80,11 @@ class _LoginPageState extends State { TextButton( onPressed: () { // Navigiere zur Registrierungsseite + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const RegisterPage()), + ); }, child: const Text('Registrieren'), ), @@ -92,4 +98,3 @@ class _LoginPageState extends State { ); } } - diff --git a/lib/register.dart b/lib/register.dart new file mode 100644 index 0000000..2c6e122 --- /dev/null +++ b/lib/register.dart @@ -0,0 +1,98 @@ +import 'package:flutter/material.dart'; + +class RegisterPage extends StatefulWidget { + const RegisterPage({Key? key}) : super(key: key); + + @override + _RegisterPageState createState() => _RegisterPageState(); +} + +class _RegisterPageState extends State { + final _emailController = TextEditingController(); + final _passwordController = TextEditingController(); + final _confirmPasswordController = TextEditingController(); + + @override + void dispose() { + _emailController.dispose(); + _passwordController.dispose(); + _confirmPasswordController.dispose(); + super.dispose(); + } + + bool isValidEmail(String email) { + // Die gleiche Validierung wie in Ihrer LoginPage + return RegExp(r'^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$').hasMatch(email); + } + + bool arePasswordsMatching(String password, String confirmPassword) { + return password == confirmPassword; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(height: 16), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: Column( + children: [ + TextFormField( + controller: _emailController, + decoration: const InputDecoration( + labelText: 'E-Mail', + ), + validator: (value) { + if (value!.isEmpty) { + return 'Bitte geben Sie eine E-Mail-Adresse ein.'; + } else if (!isValidEmail(value)) { + return 'Bitte geben Sie eine gültige E-Mail-Adresse ein.'; + } + return null; + }, + ), + const SizedBox(height: 16), + TextFormField( + controller: _passwordController, + obscureText: true, + decoration: const InputDecoration( + labelText: 'Passwort', + ), + ), + const SizedBox(height: 16), + TextFormField( + controller: _confirmPasswordController, + obscureText: true, + decoration: const InputDecoration( + labelText: 'Passwort bestätigen', + ), + ), + ElevatedButton( + onPressed: () { + String email = _emailController.text; + String password = _passwordController.text; + String confirmPassword = _confirmPasswordController.text; + if (isValidEmail(email) && arePasswordsMatching(password, confirmPassword)) { + // E-Mail und Passwörter sind gültig, führe die entsprechende Aktion aus + } else { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Ungültige Eingaben'), + duration: Duration(seconds: 2), + ), + ); + } + }, + child: const Text('Registrieren'), + ), + ], + ), + ), + ], + ), + ); + } +} From fe4f1d52aeb763121dbec1e5051ff2af15c0e454 Mon Sep 17 00:00:00 2001 From: Nicolas Gruber Date: Fri, 19 May 2023 17:57:50 +0200 Subject: [PATCH 4/5] changed firebase storage folder name. now includes uid's --- lib/AddPage.dart | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/lib/AddPage.dart b/lib/AddPage.dart index 1ca45dc..1ab9519 100644 --- a/lib/AddPage.dart +++ b/lib/AddPage.dart @@ -129,13 +129,19 @@ class _AddScreenState extends State { Future uploadImageToFirebaseStorage( File imageFile, String collectionName) async { - Reference ref = FirebaseStorage.instance - .ref() - .child("$collectionName/${DateTime.now().toString()}"); - UploadTask uploadTask = ref.putFile(imageFile); - return await (await uploadTask).ref.getDownloadURL(); + String? userId = FirebaseAuth.instance.currentUser?.uid; + if (userId != null) { + Reference ref = FirebaseStorage.instance + .ref() + .child("$collectionName/$userId/${DateTime.now().toString()}"); + UploadTask uploadTask = ref.putFile(imageFile); + return await (await uploadTask).ref.getDownloadURL(); + } else { + throw Exception('Cannot upload without user ID'); + } } + @override Widget build(BuildContext context) { String appBarTitle = ''; @@ -246,18 +252,18 @@ class _AddScreenState extends State { const SizedBox(height: 16.0), _imageFile != null ? Expanded( - child: LayoutBuilder( - builder: (context, constraints) { - double imageHeight = max(0, constraints.maxHeight - keyboardHeight); - return Container( - height: imageHeight, - child: Image.file(_imageFile!), - ); - }, - ), - ) - - : Container( + child: LayoutBuilder( + builder: (context, constraints) { + double imageHeight = + max(0, constraints.maxHeight - keyboardHeight); + return Container( + height: imageHeight, + child: Image.file(_imageFile!), + ); + }, + ), + ) + : Container( height: 200.0, decoration: BoxDecoration( color: Colors.grey[200], From 4c548b030ce032065ff5de9c06dc11520c2277fc Mon Sep 17 00:00:00 2001 From: Nicolas Gruber Date: Tue, 30 May 2023 17:01:40 +0200 Subject: [PATCH 5/5] gui login state stays right after closing and reopening the app --- lib/UserDefinedList.dart | 2 +- lib/anonym_aut.dart | 30 ++++++++++++++++++++---------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/lib/UserDefinedList.dart b/lib/UserDefinedList.dart index 5ebb932..5ae02e9 100644 --- a/lib/UserDefinedList.dart +++ b/lib/UserDefinedList.dart @@ -338,7 +338,7 @@ class _GenericListState extends State { ), floatingActionButton: Consumer( builder: (context, authState, child) { - if (authState.isSignedIn) { + if (authState.user != null) { return FloatingActionButton( onPressed: () { clearSelectedItems(); diff --git a/lib/anonym_aut.dart b/lib/anonym_aut.dart index dba2e1a..1d764cd 100644 --- a/lib/anonym_aut.dart +++ b/lib/anonym_aut.dart @@ -4,15 +4,26 @@ import 'package:provider/provider.dart'; class AuthState extends ChangeNotifier { FirebaseAuth auth = FirebaseAuth.instance; - bool _isSignedIn = false; + User? _user; - bool get isSignedIn => _isSignedIn; + User? get user => _user; + + AuthState() { + auth.authStateChanges().listen((User? user) { + if (user == null) { + print('User is currently signed out!'); + _user = null; + } else { + print('User is signed in!'); + _user = user; + } + notifyListeners(); + }); + } Future signInAnonymously() async { try { await auth.signInAnonymously(); - _isSignedIn = true; - notifyListeners(); } catch (e) { print(e); } @@ -20,10 +31,9 @@ class AuthState extends ChangeNotifier { Future signOut() async { await auth.signOut(); - _isSignedIn = false; - notifyListeners(); } } + class AnonymAuthScreen extends StatelessWidget { @override Widget build(BuildContext context) { @@ -32,10 +42,10 @@ class AnonymAuthScreen extends StatelessWidget { child: Consumer( builder: (context, authState, child) { return ElevatedButton( - onPressed: authState.isSignedIn - ? authState.signOut - : authState.signInAnonymously, - child: Text(authState.isSignedIn ? 'Abmelden' : 'Anonym anmelden'), + onPressed: authState.user == null + ? authState.signInAnonymously + : authState.signOut, + child: Text(authState.user == null ? 'Anonym anmelden' : 'Abmelden'), ); }, ),