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: