diff --git a/assets/bilder/profilbild.png b/assets/bilder/profilbild.png deleted file mode 100644 index 5477225..0000000 Binary files a/assets/bilder/profilbild.png and /dev/null differ diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 1871ec5..891d223 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -58,6 +58,7 @@ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 816DF0922C199A33002C6E7D /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -155,6 +156,7 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( + 816DF0922C199A33002C6E7D /* Runner.entitlements */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, @@ -474,6 +476,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; @@ -485,7 +488,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.appPrototyo; + PRODUCT_BUNDLE_IDENTIFIER = com.globyteam.globy; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -666,6 +669,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; @@ -677,7 +681,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.appPrototyo; + PRODUCT_BUNDLE_IDENTIFIER = com.globyteam.globy; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -693,6 +697,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; @@ -704,7 +709,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.appPrototyo; + PRODUCT_BUNDLE_IDENTIFIER = com.globyteam.globy; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard index f3c2851..9fdd188 100644 --- a/ios/Runner/Base.lproj/Main.storyboard +++ b/ios/Runner/Base.lproj/Main.storyboard @@ -1,8 +1,10 @@ - - + + + - + + @@ -14,13 +16,14 @@ - + - + + diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index f893e30..46f7d41 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -2,7 +2,6 @@ - CADisableMinimumFrameDurationOnPhone CFBundleDevelopmentRegion diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements new file mode 100644 index 0000000..a812db5 --- /dev/null +++ b/ios/Runner/Runner.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.developer.applesignin + + Default + + + diff --git a/lib/Klassen/allgemein.dart b/lib/Klassen/allgemein.dart index d439b85..5e7f756 100644 --- a/lib/Klassen/allgemein.dart +++ b/lib/Klassen/allgemein.dart @@ -13,10 +13,10 @@ class Question { text: "My perfect day at the beach starts with...", ), Question( - text: "I never travel without....", + text: "I never travel without...", ), Question( - text: "My best travel memory is....", + text: "My best travel memory is...", ), Question( text: @@ -34,13 +34,13 @@ class Question { ), Question( text: - "If I had a week to do only one thing in a new country, I would..", + "If I had a week to do only one thing in a new country, I would...", ), Question( - text: "A place I could visit over and over again is…", + text: "A place I could visit over and over again is...", ), Question( - text: "When I get homesick, I like to listen to…", + text: "When I get homesick, I like to listen to...", ), ]; } diff --git a/lib/Plans/buzzwordactivityscreen.dart b/lib/Plans/buzzwordactivityscreen.dart index 0221746..a999369 100644 --- a/lib/Plans/buzzwordactivityscreen.dart +++ b/lib/Plans/buzzwordactivityscreen.dart @@ -85,17 +85,18 @@ class _ActivityScreenState extends State { .name); // Füge das Interesse zur Liste der ausgewählten Interessen hinzu } plansProvider.updatePlansData(PlansData( - kind: plansProvider.plansData.kind, - title: plansProvider.plansData.title, - startdate: plansProvider.plansData.startdate, - enddate: plansProvider.plansData.enddate, - location: plansProvider.plansData.location, - imageurl: plansProvider.plansData.imageurl, - discription: plansProvider.plansData.discription, - peoplelist: plansProvider.plansData.peoplelist, - buzzwordlist: selectedActivities, - // Aktualisiere die Interessen im Provider - )); + kind: plansProvider.plansData.kind, + title: plansProvider.plansData.title, + startdate: plansProvider.plansData.startdate, + enddate: plansProvider.plansData.enddate, + location: plansProvider.plansData.location, + imageurl: plansProvider.plansData.imageurl, + discription: plansProvider.plansData.discription, + peoplelist: plansProvider.plansData.peoplelist, + buzzwordlist: selectedActivities, + maxpeople: plansProvider.plansData.maxpeople + // Aktualisiere die Interessen im Provider + )); }); }, style: ElevatedButton.styleFrom( diff --git a/lib/Plans/buzzwordtripscreen.dart b/lib/Plans/buzzwordtripscreen.dart index f5ca7b1..cc1ae3c 100644 --- a/lib/Plans/buzzwordtripscreen.dart +++ b/lib/Plans/buzzwordtripscreen.dart @@ -83,17 +83,18 @@ class _TripScreenState extends State { .name); // Füge das Interesse zur Liste der ausgewählten Interessen hinzu } plansProvider.updatePlansData(PlansData( - kind: plansProvider.plansData.kind, - title: plansProvider.plansData.title, - startdate: plansProvider.plansData.startdate, - enddate: plansProvider.plansData.enddate, - location: plansProvider.plansData.location, - imageurl: plansProvider.plansData.imageurl, - discription: plansProvider.plansData.discription, - peoplelist: plansProvider.plansData.peoplelist, - buzzwordlist: selectedTrips, - // Aktualisiere die Interessen im Provider - )); + kind: plansProvider.plansData.kind, + title: plansProvider.plansData.title, + startdate: plansProvider.plansData.startdate, + enddate: plansProvider.plansData.enddate, + location: plansProvider.plansData.location, + imageurl: plansProvider.plansData.imageurl, + discription: plansProvider.plansData.discription, + peoplelist: plansProvider.plansData.peoplelist, + buzzwordlist: selectedTrips, + maxpeople: plansProvider.plansData.maxpeople + // Aktualisiere die Interessen im Provider + )); }); }, style: ElevatedButton.styleFrom( diff --git a/lib/Plans/editactivity.dart b/lib/Plans/editactivity.dart index 0878a77..61b05bc 100644 --- a/lib/Plans/editactivity.dart +++ b/lib/Plans/editactivity.dart @@ -12,6 +12,7 @@ import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; @@ -96,20 +97,20 @@ class _EditActivityScreenState extends State // Aktualisieren Sie den Provider mit dem neuen Datum final plansProvider = Provider.of(context, listen: false); plansProvider.updatePlansData(PlansData( - kind: plansProvider.plansData.kind, - title: plansProvider.plansData.title, - startdate: isStartDate - ? picked.toIso8601String() - : plansProvider.plansData.startdate, - enddate: !isStartDate - ? picked.toIso8601String() - : plansProvider.plansData.enddate, - location: plansProvider.plansData.location, - imageurl: plansProvider.plansData.imageurl, - discription: plansProvider.plansData.discription, - peoplelist: plansProvider.plansData.peoplelist, - buzzwordlist: plansProvider.plansData.buzzwordlist, - )); + kind: plansProvider.plansData.kind, + title: plansProvider.plansData.title, + startdate: isStartDate + ? picked.toIso8601String() + : plansProvider.plansData.startdate, + enddate: !isStartDate + ? picked.toIso8601String() + : plansProvider.plansData.enddate, + location: plansProvider.plansData.location, + imageurl: plansProvider.plansData.imageurl, + discription: plansProvider.plansData.discription, + peoplelist: plansProvider.plansData.peoplelist, + buzzwordlist: plansProvider.plansData.buzzwordlist, + maxpeople: plansProvider.plansData.maxpeople)); } } @@ -119,12 +120,26 @@ class _EditActivityScreenState extends State appBar: AppBar( centerTitle: true, leading: IconButton( - icon: const Icon(Icons.arrow_back), + icon: const Icon( + Icons.arrow_back, + size: 30, + ), onPressed: () { Navigator.pop(context); - updateDocument(context); }, ), + actions: [ + IconButton( + onPressed: () { + updateDocument(context); + Navigator.pop(context); + }, + icon: Icon( + Icons.done, + size: 30, + )) + ], + backgroundColor: const Color.fromRGBO(75, 173, 193, 1.0), ), body: SingleChildScrollView( child: Container( @@ -132,38 +147,46 @@ class _EditActivityScreenState extends State child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - children: [ - TextButton( - onPressed: () { - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) => EditTripScreen()), - ); - }, - child: Text( - 'Trip', - style: TextStyle(fontSize: 30, color: Colors.black), + Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextButton( + onPressed: () { + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => EditTripScreen()), + ); + }, + child: Text( + 'Trip', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.grey, + ), + ), ), - ), - Text( - '|', - style: TextStyle(fontSize: 40), - ), - TextButton( - onPressed: () {}, - child: Text( - 'Activity', - style: TextStyle(fontSize: 30, color: Colors.black), + Text( + '|', + style: TextStyle(fontSize: 30, color: Colors.grey), ), - ) - ], - mainAxisAlignment: MainAxisAlignment.center, - ), - SizedBox( - height: 16, + TextButton( + onPressed: () {}, + child: Text( + 'Activity', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ), + ], + ), ), + SizedBox(height: 20), ProfilImagePicker( hoehe: 230, weite: 356, @@ -178,26 +201,26 @@ class _EditActivityScreenState extends State // Startdaten aktualisieren, um die neue Hauptbild-URL einzubeziehen plansProvider.updatePlansData(PlansData( - kind: plansProvider.plansData.kind, - title: plansProvider.plansData.title, - startdate: plansProvider.plansData.startdate, - enddate: plansProvider.plansData.enddate, - location: plansProvider.plansData.location, - imageurl: imageUrl, - discription: plansProvider.plansData.discription, - peoplelist: plansProvider.plansData.peoplelist, - buzzwordlist: plansProvider.plansData.buzzwordlist, - // Aktualisiere die Interessen im Provider - )); + kind: plansProvider.plansData.kind, + title: plansProvider.plansData.title, + startdate: plansProvider.plansData.startdate, + enddate: plansProvider.plansData.enddate, + location: plansProvider.plansData.location, + imageurl: imageUrl, + discription: plansProvider.plansData.discription, + peoplelist: plansProvider.plansData.peoplelist, + buzzwordlist: plansProvider.plansData.buzzwordlist, + maxpeople: plansProvider.plansData.maxpeople + // Aktualisiere die Interessen im Provider + )); }, ), - SizedBox( - height: 16, - ), + SizedBox(height: 20), const Text( 'Title', - style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), + SizedBox(height: 10), TextField( maxLength: 50, maxLines: 1, @@ -212,26 +235,26 @@ class _EditActivityScreenState extends State // Startdaten aktualisieren, um die neue Hauptbild-URL einzubeziehen plansProvider.updatePlansData(PlansData( - kind: plansProvider.plansData.kind, - title: value, - startdate: plansProvider.plansData.startdate, - enddate: plansProvider.plansData.enddate, - location: plansProvider.plansData.location, - imageurl: plansProvider.plansData.imageurl, - discription: plansProvider.plansData.discription, - peoplelist: plansProvider.plansData.peoplelist, - buzzwordlist: plansProvider.plansData.buzzwordlist, - // Aktualisiere die Interessen im Provider - )); + kind: plansProvider.plansData.kind, + title: value, + startdate: plansProvider.plansData.startdate, + enddate: plansProvider.plansData.enddate, + location: plansProvider.plansData.location, + imageurl: plansProvider.plansData.imageurl, + discription: plansProvider.plansData.discription, + peoplelist: plansProvider.plansData.peoplelist, + buzzwordlist: plansProvider.plansData.buzzwordlist, + maxpeople: plansProvider.plansData.maxpeople + // Aktualisiere die Interessen im Provider + )); }, ), + SizedBox(height: 20), const Text( 'Buzzwords', - style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), - ), - const SizedBox( - height: 6, + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), + SizedBox(height: 10), GestureDetector( onTap: () { Navigator.push( @@ -241,65 +264,59 @@ class _EditActivityScreenState extends State ); }, child: Container( + padding: EdgeInsets.all(12.0), decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), border: Border.all( style: BorderStyle.solid, color: Colors.black, - width: 0.10, + width: 0.5, ), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( - child: Container( - padding: EdgeInsets.all(8.0), - child: Wrap( - spacing: 8.0, - runSpacing: 8.0, - children: Provider.of(context, - listen: false) - .startData - .interestlist - .map((interestName) { - return Chip( - side: BorderSide( - color: Colors.white, - ), - padding: const EdgeInsets.all(8.0), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(20.0)), - backgroundColor: - Color.fromARGB(255, 224, 226, 228), - label: Text( - interestName, - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.bold, - color: Colors.black, - ), + child: Wrap( + spacing: 8.0, + runSpacing: 8.0, + children: Provider.of(context) + .plansData + .buzzwordlist + .map((buzzword) { + return Chip( + side: BorderSide(color: Colors.white), + padding: const EdgeInsets.all(8.0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20.0)), + backgroundColor: + Color.fromARGB(255, 224, 226, 228), + label: Text( + buzzword, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.bold, + color: Colors.black, ), - ); - }).toList(), - ), + ), + ); + }).toList(), ), ), - Container( - padding: EdgeInsets.all(8.0), - child: Icon( - Icons.keyboard_arrow_right, - size: 30, - ), + Icon( + Icons.keyboard_arrow_right, + size: 30, ) ], ), ), ), + SizedBox(height: 20), const Text( 'Description', - style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), + SizedBox(height: 10), TextField( maxLength: 800, maxLines: 5, @@ -314,26 +331,26 @@ class _EditActivityScreenState extends State // Startdaten aktualisieren, um die neue Hauptbild-URL einzubeziehen plansProvider.updatePlansData(PlansData( - kind: plansProvider.plansData.kind, - title: plansProvider.plansData.title, - startdate: plansProvider.plansData.startdate, - enddate: plansProvider.plansData.enddate, - location: plansProvider.plansData.location, - imageurl: plansProvider.plansData.imageurl, - discription: value, - peoplelist: plansProvider.plansData.peoplelist, - buzzwordlist: plansProvider.plansData.buzzwordlist, - // Aktualisiere die Interessen im Provider - )); + kind: plansProvider.plansData.kind, + title: plansProvider.plansData.title, + startdate: plansProvider.plansData.startdate, + enddate: plansProvider.plansData.enddate, + location: plansProvider.plansData.location, + imageurl: plansProvider.plansData.imageurl, + discription: value, + peoplelist: plansProvider.plansData.peoplelist, + buzzwordlist: plansProvider.plansData.buzzwordlist, + maxpeople: plansProvider.plansData.maxpeople + // Aktualisiere die Interessen im Provider + )); }, ), + SizedBox(height: 20), const Text( 'Date', - style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), - ), - SizedBox( - height: 16, + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), + SizedBox(height: 10), GestureDetector( onTap: () { _selectDate(context, true); @@ -351,14 +368,12 @@ class _EditActivityScreenState extends State ), ), ), - SizedBox(height: 16), + SizedBox(height: 20), const Text( 'Location', - style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), - ), - SizedBox( - height: 16, + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), + SizedBox(height: 10), GestureDetector( onTap: () async { var result = await Navigator.push( @@ -373,26 +388,26 @@ class _EditActivityScreenState extends State // Startdaten aktualisieren, um die neue Hauptbild-URL einzubeziehen plansProvider.updatePlansData(PlansData( - kind: plansProvider.plansData.kind, - title: plansProvider.plansData.title, - startdate: plansProvider.plansData.startdate, - enddate: plansProvider.plansData.enddate, - location: result, - imageurl: plansProvider.plansData.imageurl, - discription: plansProvider.plansData.discription, - peoplelist: plansProvider.plansData.peoplelist, - buzzwordlist: plansProvider.plansData.buzzwordlist, - // Aktualisiere die Interessen im Provider - )); + kind: plansProvider.plansData.kind, + title: plansProvider.plansData.title, + startdate: plansProvider.plansData.startdate, + enddate: plansProvider.plansData.enddate, + location: result, + imageurl: plansProvider.plansData.imageurl, + discription: plansProvider.plansData.discription, + peoplelist: plansProvider.plansData.peoplelist, + buzzwordlist: plansProvider.plansData.buzzwordlist, + maxpeople: plansProvider.plansData.maxpeople + // Aktualisiere die Interessen im Provider + )); } }, child: AbsorbPointer( child: TextField( decoration: InputDecoration( hintText: Provider.of(context) - .plansData - .location ?? - 'Search City', + .plansData + .location, border: OutlineInputBorder( borderSide: BorderSide(color: Colors.black), ), @@ -400,6 +415,43 @@ class _EditActivityScreenState extends State ), ), ), + SizedBox(height: 20), + const Text( + 'Max. People', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + SizedBox(height: 10), + TextField( + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly + ], // This ensures only digits are allowed + decoration: const InputDecoration( + border: OutlineInputBorder( + borderSide: BorderSide(color: Colors.black), + ), + hintText: 'Enter a number', + ), + onChanged: (value) { + final plansProvider = + Provider.of(context, listen: false); + + // Startdaten aktualisieren, um die neue Hauptbild-URL einzubeziehen + plansProvider.updatePlansData(PlansData( + kind: plansProvider.plansData.kind, + title: plansProvider.plansData.title, + startdate: plansProvider.plansData.startdate, + enddate: plansProvider.plansData.enddate, + location: plansProvider.plansData.location, + imageurl: plansProvider.plansData.imageurl, + discription: plansProvider.plansData.discription, + peoplelist: plansProvider.plansData.peoplelist, + buzzwordlist: plansProvider.plansData.buzzwordlist, + maxpeople: value + // Aktualisiere die Interessen im Provider + )); + }, + ), ], ), ), @@ -435,6 +487,7 @@ void updateDocument(BuildContext context) async { 'discription': plansProvider.plansData.discription, 'peoplelist': [currentUserUid], 'buzzwordlist': plansProvider.plansData.buzzwordlist, + 'maxpeople': plansProvider.plansData.maxpeople }); await FirebaseFirestore.instance diff --git a/lib/Plans/edittrip.dart b/lib/Plans/edittrip.dart index a06eaff..4472f36 100644 --- a/lib/Plans/edittrip.dart +++ b/lib/Plans/edittrip.dart @@ -1,7 +1,8 @@ import 'dart:io'; -import 'package:app_prototyo/Plans/buzzwordtripscreen.dart'; +import 'package:app_prototyo/Plans/buzzwordactivityscreen.dart'; import 'package:app_prototyo/Plans/editactivity.dart'; + import 'package:app_prototyo/Provider/plans_provider.dart'; import 'package:app_prototyo/Provider/user_provider.dart'; import 'package:app_prototyo/Plans/stadtsuche.dart'; @@ -12,11 +13,11 @@ import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; -//Hier passt man sein Profil an - +//Hier passt man seinen Trip an class EditTripScreen extends StatefulWidget { const EditTripScreen({super.key}); @@ -30,6 +31,7 @@ class _EditTripScreenState extends State with RouteAware { late PageRoute _modalRoute; DateTime? _selectedStartDate; DateTime? _selectedEndDate; + String? _dateError; Future uploadImageToFirebaseStorage(File imageFile) async { try { @@ -86,190 +88,220 @@ class _EditTripScreenState extends State with RouteAware { if (picked != null) { setState(() { if (isStartDate) { - _selectedStartDate = picked; + if (_selectedEndDate != null && picked.isAfter(_selectedEndDate!)) { + _dateError = 'Start date must be before end date'; + } else { + _selectedStartDate = picked; + _dateError = null; + } } else { - _selectedEndDate = picked; + if (_selectedStartDate != null && + picked.isBefore(_selectedStartDate!)) { + _dateError = 'End date must be after start date'; + } else { + _selectedEndDate = picked; + _dateError = null; + } } }); - // Aktualisieren Sie den Provider mit dem neuen Datum - final plansProvider = Provider.of(context, listen: false); - plansProvider.updatePlansData(PlansData( - kind: plansProvider.plansData.kind, - title: plansProvider.plansData.title, - startdate: isStartDate - ? picked.toIso8601String() - : plansProvider.plansData.startdate, - enddate: !isStartDate - ? picked.toIso8601String() - : plansProvider.plansData.enddate, - location: plansProvider.plansData.location, - imageurl: plansProvider.plansData.imageurl, - discription: plansProvider.plansData.discription, - peoplelist: plansProvider.plansData.peoplelist, - buzzwordlist: plansProvider.plansData.buzzwordlist, - )); + if (_dateError == null) { + final plansProvider = + Provider.of(context, listen: false); + plansProvider.updatePlansData(PlansData( + kind: plansProvider.plansData.kind, + title: plansProvider.plansData.title, + startdate: isStartDate + ? picked.toIso8601String() + : plansProvider.plansData.startdate, + enddate: !isStartDate + ? picked.toIso8601String() + : plansProvider.plansData.enddate, + location: plansProvider.plansData.location, + imageurl: plansProvider.plansData.imageurl, + discription: plansProvider.plansData.discription, + peoplelist: plansProvider.plansData.peoplelist, + buzzwordlist: plansProvider.plansData.buzzwordlist, + maxpeople: plansProvider.plansData.maxpeople, + )); + } } } @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - centerTitle: true, - leading: IconButton( - icon: const Icon(Icons.arrow_back), + appBar: AppBar( + leading: IconButton( + icon: const Icon( + Icons.arrow_back, + size: 30, + ), + onPressed: () { + Navigator.pop(context); + }, + ), + centerTitle: true, + actions: [ + IconButton( onPressed: () { updateDocument(context); Navigator.pop(context); }, + icon: const Icon( + Icons.done, + size: 30, + ), ), - ), - body: SingleChildScrollView( - child: Container( + ], + backgroundColor: const Color.fromRGBO(75, 173, 193, 1.0), + ), + body: SingleChildScrollView( + child: Container( padding: const EdgeInsets.all(16.0), - child: - Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - children: [ - TextButton( - onPressed: () {}, - child: Text( - 'Trip', - style: TextStyle(fontSize: 30, color: Colors.black), - ), - ), - Text( - '|', - style: TextStyle(fontSize: 40), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextButton( + onPressed: () {}, + child: Text( + 'Trip', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ), + Text( + '|', + style: TextStyle(fontSize: 30, color: Colors.grey), + ), + TextButton( + onPressed: () { + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => EditActivityScreen(), + ), + ); + }, + child: Text( + 'Activity', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.grey, + ), + ), + ), + ], ), - TextButton( - onPressed: () { - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) => EditActivityScreen()), - ); - }, - child: Text( - 'Activity', - style: TextStyle(fontSize: 30, color: Colors.black), + ), + SizedBox(height: 20), + ProfilImagePicker( + hoehe: 230, + weite: 356, + onPickImage: (imageurl) async { + String imageUrl = + await uploadImageToFirebaseStorage(imageurl); + final plansProvider = + Provider.of(context, listen: false); + plansProvider.updatePlansData(PlansData( + kind: plansProvider.plansData.kind, + title: plansProvider.plansData.title, + startdate: plansProvider.plansData.startdate, + enddate: plansProvider.plansData.enddate, + location: plansProvider.plansData.location, + imageurl: imageUrl, + discription: plansProvider.plansData.discription, + peoplelist: plansProvider.plansData.peoplelist, + buzzwordlist: plansProvider.plansData.buzzwordlist, + maxpeople: plansProvider.plansData.maxpeople, + )); + }, + ), + SizedBox(height: 20), + const Text( + 'Title', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + SizedBox(height: 10), + TextField( + maxLength: 50, + maxLines: 1, + decoration: const InputDecoration( + border: OutlineInputBorder( + borderSide: BorderSide(color: Colors.black), ), - ) - ], - mainAxisAlignment: MainAxisAlignment.center, - ), - SizedBox( - height: 16, - ), - ProfilImagePicker( - hoehe: 230, - weite: 356, - onPickImage: (imageurl) async { - // Bild hochladen und URL erhalten - String imageUrl = await uploadImageToFirebaseStorage(imageurl); - - // StartProvider abrufen - final plansProvider = - Provider.of(context, listen: false); - - // Startdaten aktualisieren, um die neue Hauptbild-URL einzubeziehen - plansProvider.updatePlansData(PlansData( - kind: plansProvider.plansData.kind, - title: plansProvider.plansData.title, - startdate: plansProvider.plansData.startdate, - enddate: plansProvider.plansData.enddate, - location: plansProvider.plansData.location, - imageurl: imageUrl, - discription: plansProvider.plansData.discription, - peoplelist: plansProvider.plansData.peoplelist, - buzzwordlist: plansProvider.plansData.buzzwordlist, - // Aktualisiere die Interessen im Provider - )); - }, - ), - SizedBox( - height: 16, - ), - const Text( - 'Title', - style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), - ), - TextField( - maxLength: 50, - maxLines: 1, - decoration: const InputDecoration( - border: OutlineInputBorder( - borderSide: BorderSide(color: Colors.black), ), + onChanged: (value) { + final plansProvider = + Provider.of(context, listen: false); + plansProvider.updatePlansData(PlansData( + kind: plansProvider.plansData.kind, + title: value, + startdate: plansProvider.plansData.startdate, + enddate: plansProvider.plansData.enddate, + location: plansProvider.plansData.location, + imageurl: plansProvider.plansData.imageurl, + discription: plansProvider.plansData.discription, + peoplelist: plansProvider.plansData.peoplelist, + buzzwordlist: plansProvider.plansData.buzzwordlist, + maxpeople: plansProvider.plansData.maxpeople, + )); + }, ), - onChanged: (value) { - final plansProvider = - Provider.of(context, listen: false); - - // Startdaten aktualisieren, um die neue Hauptbild-URL einzubeziehen - plansProvider.updatePlansData(PlansData( - kind: plansProvider.plansData.kind, - title: value, - startdate: plansProvider.plansData.startdate, - enddate: plansProvider.plansData.enddate, - location: plansProvider.plansData.location, - imageurl: plansProvider.plansData.imageurl, - discription: plansProvider.plansData.discription, - peoplelist: plansProvider.plansData.peoplelist, - buzzwordlist: plansProvider.plansData.buzzwordlist, - // Aktualisiere die Interessen im Provider - )); - }, - ), - const Text( - 'Buzzwords', - style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), - ), - const SizedBox( - height: 6, - ), - GestureDetector( - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => const TripScreen()), - ); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - border: Border.all( - style: BorderStyle.solid, - color: Colors.black, - width: 0.10, + SizedBox(height: 20), + const Text( + 'Buzzwords', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + SizedBox(height: 10), + GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const ActivityScreen(), + ), + ); + }, + child: Container( + padding: EdgeInsets.all(12.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: Border.all( + style: BorderStyle.solid, + color: Colors.black, + width: 0.5, + ), ), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Container( - padding: EdgeInsets.all(8.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( child: Wrap( spacing: 8.0, runSpacing: 8.0, - children: - Provider.of(context, listen: false) - .startData - .interestlist - .map((interestName) { + children: Provider.of(context) + .plansData + .buzzwordlist + .map((buzzword) { return Chip( - side: BorderSide( - color: Colors.white, - ), + side: BorderSide(color: Colors.white), padding: const EdgeInsets.all(8.0), shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(20.0)), + borderRadius: BorderRadius.circular(20.0), + ), backgroundColor: Color.fromARGB(255, 224, 226, 228), label: Text( - interestName, + buzzword, style: TextStyle( fontSize: 16.0, fontWeight: FontWeight.bold, @@ -280,176 +312,186 @@ class _EditTripScreenState extends State with RouteAware { }).toList(), ), ), - ), - Container( - padding: EdgeInsets.all(8.0), - child: Icon( + Icon( Icons.keyboard_arrow_right, size: 30, ), - ) - ], + ], + ), ), ), - ), - const Text( - 'Description', - style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), - ), - TextField( - maxLength: 800, - maxLines: 5, - decoration: const InputDecoration( - border: OutlineInputBorder( - borderSide: BorderSide(color: Colors.black), - ), + SizedBox(height: 20), + const Text( + 'Description', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), - onChanged: (value) { - final plansProvider = - Provider.of(context, listen: false); - - // Startdaten aktualisieren, um die neue Hauptbild-URL einzubeziehen - plansProvider.updatePlansData(PlansData( - kind: plansProvider.plansData.kind, - title: plansProvider.plansData.title, - startdate: plansProvider.plansData.startdate, - enddate: plansProvider.plansData.enddate, - location: plansProvider.plansData.location, - imageurl: plansProvider.plansData.imageurl, - discription: value, - peoplelist: plansProvider.plansData.peoplelist, - buzzwordlist: plansProvider.plansData.buzzwordlist, - // Aktualisiere die Interessen im Provider - )); - }, - ), - const Text( - 'Dates', - style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), - ), - SizedBox( - height: 8, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - decoration: BoxDecoration( - border: Border.all(), - borderRadius: BorderRadius.circular(15), + SizedBox(height: 10), + TextField( + maxLength: 800, + maxLines: 5, + decoration: const InputDecoration( + border: OutlineInputBorder( + borderSide: BorderSide(color: Colors.black), ), - child: Column( - children: [ - const Text( - 'Start', - style: TextStyle( - fontSize: 20, - ), - ), - GestureDetector( - onTap: () => _selectDate(context, true), - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12.0), - ), - child: Padding( - padding: const EdgeInsets.all(10), - child: Text( - _selectedStartDate != null - ? '${_selectedStartDate!.day}.${_selectedStartDate!.month}.${_selectedStartDate!.year}' - : 'Select Date', - style: - TextStyle(color: Colors.grey, fontSize: 23), - ), - ), - ), + ), + onChanged: (value) { + final plansProvider = + Provider.of(context, listen: false); + plansProvider.updatePlansData(PlansData( + kind: plansProvider.plansData.kind, + title: plansProvider.plansData.title, + startdate: plansProvider.plansData.startdate, + enddate: plansProvider.plansData.enddate, + location: plansProvider.plansData.location, + imageurl: plansProvider.plansData.imageurl, + discription: value, + peoplelist: plansProvider.plansData.peoplelist, + buzzwordlist: plansProvider.plansData.buzzwordlist, + maxpeople: plansProvider.plansData.maxpeople, + )); + }, + ), + SizedBox(height: 20), + const Text( + 'Date', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + SizedBox(height: 10), + GestureDetector( + onTap: () { + _selectDate(context, true); + }, + child: AbsorbPointer( + child: TextField( + decoration: InputDecoration( + hintText: _selectedStartDate != null + ? '${_selectedStartDate!.day}.${_selectedStartDate!.month}.${_selectedStartDate!.year}' + : 'Select Startdate', + border: OutlineInputBorder( + borderSide: BorderSide(color: Colors.black), ), - ], + ), ), ), - SizedBox( - width: 60, - ), - Container( - decoration: BoxDecoration( - border: Border.all(), - borderRadius: BorderRadius.circular(15), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + '-', + style: TextStyle(fontSize: 46, fontWeight: FontWeight.bold), ), - child: Column( - children: [ - const Text( - 'End', - style: TextStyle( - fontSize: 20, - ), - ), - GestureDetector( - onTap: () => _selectDate(context, false), - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12.0), - ), - child: Padding( - padding: const EdgeInsets.all(10), - child: Text( - _selectedEndDate != null - ? '${_selectedEndDate!.day}.${_selectedEndDate!.month}.${_selectedEndDate!.year}' - : 'Select Date', - style: - TextStyle(color: Colors.grey, fontSize: 23), - ), - ), - ), + ], + ), + GestureDetector( + onTap: () { + _selectDate(context, false); + }, + child: AbsorbPointer( + child: TextField( + decoration: InputDecoration( + hintText: _selectedEndDate != null + ? '${_selectedEndDate!.day}.${_selectedEndDate!.month}.${_selectedEndDate!.year}' + : 'Select Enddate', + border: OutlineInputBorder( + borderSide: BorderSide(color: Colors.black), ), - ], + ), ), - ) - ], - ), - SizedBox( - height: 15, - ), - const Text( - 'Location', - style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), - ), - GestureDetector( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => CountryStateCityScreen(), + ), + ), + if (_dateError != null) + Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Text( + _dateError!, + style: TextStyle(color: Colors.red, fontSize: 16), ), - ); - }, - child: Container( - height: 50, - decoration: BoxDecoration( - border: Border.all(), - borderRadius: BorderRadius.circular(15), ), - child: Row(children: [ - SizedBox( - width: 6, + SizedBox(height: 20), + const Text( + 'Location', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + SizedBox(height: 10), + GestureDetector( + onTap: () async { + var result = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => CountryStateCityScreen(), + ), + ); + + if (result != null && result is String) { + final plansProvider = + Provider.of(context, listen: false); + plansProvider.updatePlansData(PlansData( + kind: plansProvider.plansData.kind, + title: plansProvider.plansData.title, + startdate: plansProvider.plansData.startdate, + enddate: plansProvider.plansData.enddate, + location: result, + imageurl: plansProvider.plansData.imageurl, + discription: plansProvider.plansData.discription, + peoplelist: plansProvider.plansData.peoplelist, + buzzwordlist: plansProvider.plansData.buzzwordlist, + maxpeople: plansProvider.plansData.maxpeople, + )); + } + }, + child: AbsorbPointer( + child: TextField( + decoration: InputDecoration( + hintText: Provider.of(context) + .plansData + .location, + border: OutlineInputBorder( + borderSide: BorderSide(color: Colors.black), + ), + ), ), - Icon( - Icons.place, - size: 35, + ), + ), + SizedBox(height: 20), + const Text( + 'Max. People', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + SizedBox(height: 10), + TextField( + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly + ], + decoration: const InputDecoration( + border: OutlineInputBorder( + borderSide: BorderSide(color: Colors.black), ), - Text( - ' Baltmannsweiler, Germany', - style: TextStyle(fontSize: 20), - ) - ]), + hintText: 'Enter a number', + ), + onChanged: (value) { + final plansProvider = + Provider.of(context, listen: false); + plansProvider.updatePlansData(PlansData( + kind: plansProvider.plansData.kind, + title: plansProvider.plansData.title, + startdate: plansProvider.plansData.startdate, + enddate: plansProvider.plansData.enddate, + location: plansProvider.plansData.location, + imageurl: plansProvider.plansData.imageurl, + discription: plansProvider.plansData.discription, + peoplelist: plansProvider.plansData.peoplelist, + buzzwordlist: plansProvider.plansData.buzzwordlist, + maxpeople: value, + )); + }, ), - ), - SizedBox( - height: 15, - ), - ]), - ))); + ], + ), + ), + ), + ); } } @@ -458,18 +500,12 @@ void updateDocument(BuildContext context) async { final currentUser = FirebaseAuth.instance.currentUser; if (currentUser != null) { String currentUserUid = currentUser.uid; - - // Daten direkt aus dem übergebenen PlansProvider abrufen PlansProvider plansProvider = Provider.of(context, listen: false); - StartProvider startProvider = Provider.of(context, listen: false); - - // Zufällig generierte Dokument-ID verwenden DocumentReference newDocRef = FirebaseFirestore.instance.collection('plans').doc(); - await newDocRef.set({ 'kind': 'trip', 'title': plansProvider.plansData.title, @@ -480,15 +516,14 @@ void updateDocument(BuildContext context) async { 'discription': plansProvider.plansData.discription, 'peoplelist': [currentUserUid], 'buzzwordlist': plansProvider.plansData.buzzwordlist, + 'maxpeople': plansProvider.plansData.maxpeople, }); - await FirebaseFirestore.instance .collection('user') .doc(currentUserUid) .update({ 'Plans': FieldValue.arrayUnion([newDocRef.id]) }); - print('Dokument erfolgreich erstellt mit ID: ${newDocRef.id}'); } else { print('Benutzer nicht angemeldet.'); diff --git a/lib/Plans/planscreen.dart b/lib/Plans/planscreen.dart new file mode 100644 index 0000000..a0f677b --- /dev/null +++ b/lib/Plans/planscreen.dart @@ -0,0 +1,206 @@ +import 'package:app_prototyo/Plans/edittrip.dart'; +import 'package:flutter/material.dart'; + +import 'package:flutter/rendering.dart'; + +class PlanScreen extends StatefulWidget { + const PlanScreen({Key? key}) : super(key: key); + + @override + _PlanScreenState createState() => _PlanScreenState(); +} + +class _PlanScreenState extends State { + final ScrollController _scrollController = ScrollController(); + bool _showFilters = true; + + @override + void initState() { + super.initState(); + _scrollController.addListener(_handleScroll); + } + + @override + void dispose() { + _scrollController.removeListener(_handleScroll); + _scrollController.dispose(); + super.dispose(); + } + + void _handleScroll() { + if (_scrollController.position.userScrollDirection == + ScrollDirection.reverse) { + if (_showFilters) { + setState(() { + _showFilters = false; + }); + } + } else { + if (!_showFilters) { + setState(() { + _showFilters = true; + }); + } + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + centerTitle: true, + title: Image.asset('assets/bilder/Schriftzug.png', width: 100), + automaticallyImplyLeading: false, + leading: IconButton( + icon: const Icon( + Icons.list, + color: Colors.grey, + size: 35, + ), + onPressed: () {}), + actions: [ + IconButton( + icon: const Icon( + Icons.add, + color: Colors.grey, + size: 35, + ), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const EditTripScreen(), + ), + ); + }, + ), + ], + ), + body: Column( + children: [ + AnimatedContainer( + duration: const Duration(milliseconds: 200), + height: _showFilters ? kToolbarHeight : 0, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: [ + IconButton( + onPressed: () { + // Aktion für das Filter-Icon + }, + icon: const Icon( + Icons.filter_list), // Filter-Icon hinzugefügt + ), + FilterButton( + filterName: 'Filter 1', + onPressed: () { + // Aktion für den ersten Filter + }, + ), + const SizedBox( + width: 16), // Platz zwischen Filter 1 und Filter 2 + FilterButton( + filterName: 'Filter 2', + onPressed: () { + // Aktion für den zweiten Filter + }, + ), + const SizedBox( + width: 16), // Platz zwischen Filter 2 und Filter 3 + FilterButton( + filterName: 'Filter 3', + onPressed: () { + // Aktion für den dritten Filter + }, + ), + const SizedBox( + width: 16), // Platz zwischen Filter 3 und Filter 4 + FilterButton( + filterName: 'Filter 4', + onPressed: () { + // Aktion für den vierten Filter + }, + ), + const SizedBox( + width: 16), // Platz zwischen Filter 4 und Filter 5 + FilterButton( + filterName: 'Filter 5', + onPressed: () { + // Aktion für den fünften Filter + }, + ), + const SizedBox( + width: 16), // Platz zwischen Filter 5 und Filter 6 + FilterButton( + filterName: 'Filter 6', + onPressed: () { + // Aktion für den sechsten Filter + }, + ), + const SizedBox( + width: 16), // Platz zwischen Filter 6 und Filter 7 + FilterButton( + filterName: 'Filter 7', + onPressed: () { + // Aktion für den siebten Filter + }, + ), + const SizedBox( + width: 16), // Platz zwischen Filter 7 und Filter 8 + FilterButton( + filterName: 'Filter 8', + onPressed: () {}, + // Aktion für den achten Filter + ), + ], + ), + ), + ), + Expanded( + child: SingleChildScrollView( + controller: _scrollController, + physics: const AlwaysScrollableScrollPhysics(), + child: Column( + children: [], + ), + ), + ), + ], + ), + ); + } +} + +class FilterButton extends StatelessWidget { + final String filterName; + final VoidCallback onPressed; + + const FilterButton({ + Key? key, + required this.filterName, + required this.onPressed, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return ElevatedButton( + onPressed: onPressed, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric( + horizontal: 15, vertical: 5), // Anpassung Padding + backgroundColor: const Color.fromARGB(255, 243, 243, 243), + side: const BorderSide( + color: Color.fromARGB(255, 132, 132, 132), width: 0.5), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(30.0), // Anpassung Radius + ), + ), + child: Text( + filterName, + style: const TextStyle( + fontSize: 15, color: Colors.black), //Schriftanpassung der Filter + ), + ); + } +} diff --git a/lib/Plans/stadtsuche.dart b/lib/Plans/stadtsuche.dart index 5af8843..9efd978 100644 --- a/lib/Plans/stadtsuche.dart +++ b/lib/Plans/stadtsuche.dart @@ -1,8 +1,12 @@ +import 'dart:async'; + import 'package:app_prototyo/Provider/plans_provider.dart'; import 'package:flutter/material.dart'; import 'package:country_state_city/country_state_city.dart' as csc; import 'package:provider/provider.dart'; +// Replace with your actual import + class CountryStateCityScreen extends StatefulWidget { @override _CountryStateCityScreenState createState() => _CountryStateCityScreenState(); @@ -10,44 +14,67 @@ class CountryStateCityScreen extends StatefulWidget { class _CountryStateCityScreenState extends State { late List _countries = []; - late List _allCities = []; List _filteredCities = []; String _searchQuery = ''; + final TextEditingController _searchController = TextEditingController(); + bool _isLoading = true; + bool _isSearching = false; + Timer? _debounce; @override void initState() { super.initState(); - _loadAllData(); + _loadCountries(); + } + + @override + void dispose() { + _debounce?.cancel(); + super.dispose(); } - Future _loadAllData() async { + Future _loadCountries() async { final countries = await csc.getAllCountries(); setState(() { _countries = countries; + _isLoading = false; + }); + } + + Future _searchCities(String query) async { + setState(() { + _isSearching = true; }); - for (var country in countries) { - final cities = await csc.getCountryCities(country.isoCode); - _allCities.addAll(cities); + List cities = []; + for (var country in _countries) { + if (country.name.toLowerCase().contains(query) || + country.isoCode.toLowerCase().contains(query)) { + final countryCities = await csc.getCountryCities(country.isoCode); + cities.addAll(countryCities); + } } setState(() { - _filteredCities = _allCities; + _filteredCities = cities; + _isSearching = false; }); } void _filterCities(String query) { - setState(() { - _searchQuery = query.toLowerCase(); - _filteredCities = _allCities.where((city) { - final cityName = city.name.toLowerCase(); - final countryName = _countries - .firstWhere((country) => country.isoCode == city.countryCode) - .name - .toLowerCase(); - return cityName.contains(_searchQuery) || - countryName.contains(_searchQuery); - }).toList(); + if (_debounce?.isActive ?? false) _debounce!.cancel(); + _debounce = Timer(const Duration(milliseconds: 500), () { + setState(() { + _searchQuery = query.toLowerCase(); + }); + + if (_searchQuery.isNotEmpty) { + _searchCities(_searchQuery); + } else { + setState(() { + _filteredCities = []; + }); + } }); } @@ -56,31 +83,19 @@ class _CountryStateCityScreenState extends State { plansProvider.updatePlansData( PlansData( - kind: plansProvider.plansData.kind, - title: plansProvider.plansData.title, - startdate: plansProvider.plansData.startdate, - enddate: plansProvider.plansData.enddate, - location: name, - imageurl: plansProvider.plansData.imageurl, - discription: plansProvider.plansData.discription, - peoplelist: plansProvider.plansData.peoplelist, - buzzwordlist: plansProvider.plansData.buzzwordlist, - ), + kind: plansProvider.plansData.kind, + title: plansProvider.plansData.title, + startdate: plansProvider.plansData.startdate, + enddate: plansProvider.plansData.enddate, + location: name, + imageurl: plansProvider.plansData.imageurl, + discription: plansProvider.plansData.discription, + peoplelist: plansProvider.plansData.peoplelist, + buzzwordlist: plansProvider.plansData.buzzwordlist, + maxpeople: plansProvider.plansData.maxpeople), ); - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text('Selected Item'), - content: Text(name), - actions: [ - TextButton( - onPressed: () => Navigator.of(context).pop(), - child: Text('OK'), - ), - ], - ), - ); + _searchController.text = name; } @override @@ -94,120 +109,106 @@ class _CountryStateCityScreenState extends State { }, ), ), - body: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Center( - child: Column( - mainAxisSize: MainAxisSize.min, + body: _isLoading + ? Center(child: CircularProgressIndicator()) + : Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.center, children: [ - Container( - decoration: BoxDecoration( - color: Colors.grey[300], // Hellgrauer Hintergrund - shape: BoxShape.circle, - ), - child: IconButton( - onPressed: () {}, - icon: Icon( - color: Color.fromRGBO(75, 173, 193, 1), - Icons.place, - size: 60, - ), + Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + decoration: BoxDecoration( + color: Colors.grey[300], // Light gray background + shape: BoxShape.circle, + ), + child: IconButton( + onPressed: () {}, + icon: Icon( + color: Color.fromRGBO(75, 173, 193, 1), + Icons.place, + size: 60, + ), + ), + ), + SizedBox( + height: 5, + ), + Text( + 'Current Location', + style: TextStyle(fontSize: 18), + ), + SizedBox( + height: 23, + ), + Text( + 'or', + style: TextStyle( + fontSize: 23, fontWeight: FontWeight.bold), + ), + ], ), ), - SizedBox( - height: 5, - ), - Text( - 'Current Location', - style: TextStyle(fontSize: 18), - ), SizedBox( height: 23, ), - Text( - 'or', - style: TextStyle(fontSize: 23, fontWeight: FontWeight.bold), - ), - ], - ), - ), - SizedBox( - height: 23, - ), - Padding( - padding: EdgeInsets.all(8.0), - child: TextField( - decoration: InputDecoration( - labelText: 'Search for a city or country', - prefixIcon: Icon(Icons.search), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12.0), - borderSide: BorderSide( - color: Colors.grey, - width: 1.0, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12.0), - borderSide: BorderSide( - color: Colors.grey, - width: 1.0, - ), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12.0), - borderSide: BorderSide( - color: Colors.grey, - width: 1.0, + Padding( + padding: EdgeInsets.all(8.0), + child: TextField( + controller: _searchController, + decoration: InputDecoration( + labelText: 'Search for a city or country', + prefixIcon: Icon(Icons.search), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12.0), + borderSide: BorderSide( + color: Colors.grey, + width: 1.0, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12.0), + borderSide: BorderSide( + color: Colors.grey, + width: 1.0, + ), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12.0), + borderSide: BorderSide( + color: Colors.grey, + width: 1.0, + ), + ), + filled: true, + fillColor: Colors.grey[200], + contentPadding: EdgeInsets.symmetric( + vertical: 15.0, horizontal: 10.0), + ), + onChanged: _filterCities, ), ), - filled: true, - fillColor: Colors.grey[200], - contentPadding: - EdgeInsets.symmetric(vertical: 15.0, horizontal: 10.0), - ), - onChanged: _filterCities, - ), - ), - Expanded( - child: ListView.builder( - itemCount: - _filteredCities.length + (_searchQuery.isNotEmpty ? 1 : 0), - itemBuilder: (context, index) { - if (index == 0 && _searchQuery.isNotEmpty) { - final filteredCountry = _countries.firstWhereOrNull( - (country) => - country.name.toLowerCase().contains(_searchQuery)); - if (filteredCountry != null) { - return ListTile( - title: Text( - filteredCountry.name, - style: TextStyle( - fontSize: 18, + Expanded( + child: _isSearching + ? Center(child: CircularProgressIndicator()) + : ListView.builder( + itemCount: _filteredCities.length, + itemBuilder: (context, index) { + final city = _filteredCities[index]; + final country = _countries.firstWhere((country) => + country.isoCode == city.countryCode); + return ListTile( + title: Text('${city.name}, ${country.name}'), + onTap: () => _onSelectItem( + '${city.name}, ${country.name}'), + ); + }, ), - ), - onTap: () => _onSelectItem(filteredCountry.name), - ); - } - } - if (index >= (_searchQuery.isNotEmpty ? 1 : 0)) { - final city = _filteredCities[ - index - (_searchQuery.isNotEmpty ? 1 : 0)]; - final country = _countries.firstWhere( - (country) => country.isoCode == city.countryCode); - return ListTile( - title: Text('${city.name}, ${country.name}'), - onTap: () => _onSelectItem('${city.name}, ${country.name}'), - ); - } - return SizedBox.shrink(); // This prevents the RangeError - }, + ), + ], ), - ), - ], - ), ); } } diff --git a/lib/Provider/plans_provider.dart b/lib/Provider/plans_provider.dart index 683c635..f5b24bb 100644 --- a/lib/Provider/plans_provider.dart +++ b/lib/Provider/plans_provider.dart @@ -14,32 +14,33 @@ class PlansData { final String discription; final List buzzwordlist; final List peoplelist; + final String maxpeople; - PlansData({ - required this.kind, - required this.title, - required this.startdate, - required this.enddate, - required this.location, - required this.imageurl, - required this.discription, - required this.peoplelist, - required this.buzzwordlist, - }); + PlansData( + {required this.kind, + required this.title, + required this.startdate, + required this.enddate, + required this.location, + required this.imageurl, + required this.discription, + required this.peoplelist, + required this.buzzwordlist, + required this.maxpeople}); } class PlansProvider extends ChangeNotifier { PlansData _plansData = PlansData( - kind: '', - title: '', - startdate: '', - enddate: '', - location: '', - imageurl: '', - discription: '', - peoplelist: [], - buzzwordlist: [], - ); + kind: '', + title: '', + startdate: '', + enddate: '', + location: '', + imageurl: '', + discription: '', + peoplelist: [], + buzzwordlist: [], + maxpeople: ''); PlansData get plansData => _plansData; @@ -56,16 +57,16 @@ class PlansProvider extends ChangeNotifier { void clearData() { _plansData = PlansData( - kind: '', - title: '', - startdate: '', - enddate: '', - location: '', - imageurl: '', - discription: '', - peoplelist: [], - buzzwordlist: [], - ); // Setze den Inhalt zurück + kind: '', + title: '', + startdate: '', + enddate: '', + location: '', + imageurl: '', + discription: '', + peoplelist: [], + buzzwordlist: [], + maxpeople: ''); // Setze den Inhalt zurück notifyListeners(); // Informiere alle Listeners über die Änderung } diff --git a/lib/Provider/user_provider.dart b/lib/Provider/user_provider.dart index a971a1d..2680a71 100644 --- a/lib/Provider/user_provider.dart +++ b/lib/Provider/user_provider.dart @@ -12,9 +12,12 @@ class StartData { final String image1url; final String image2url; final String aboutme; - final List countrylist; + final String instagram; + final String tiktok; + final List visitedcountrylist; + final List wannavisitcountrylist; final List interestlist; - final List qalist; + late final List qalist; final List languagelist; final List transportlist; final List sleepingplacelist; @@ -23,30 +26,157 @@ class StartData { final double relaxpartynumber; final bool globynomad; - StartData( - {required this.name, - required this.birthdate, - required this.gender, - required this.mainimageurl, - required this.image1url, - required this.image2url, - required this.aboutme, - required this.countrylist, - required this.interestlist, - required this.qalist, - required this.moneynumber, - required this.citybeachnumber, - required this.relaxpartynumber, - required this.languagelist, - required this.transportlist, - required this.sleepingplacelist, - required this.globynomad}); + StartData({ + required this.name, + required this.birthdate, + required this.gender, + required this.mainimageurl, + required this.image1url, + required this.image2url, + required this.aboutme, + required this.instagram, + required this.tiktok, + required this.visitedcountrylist, + required this.wannavisitcountrylist, + required this.interestlist, + required this.qalist, + required this.moneynumber, + required this.citybeachnumber, + required this.relaxpartynumber, + required this.languagelist, + required this.transportlist, + required this.sleepingplacelist, + required this.globynomad, + }); -// ignore: empty_constructor_bodies + StartData copyWith({ + String? name, + String? birthdate, + String? gender, + String? mainimageurl, + String? image1url, + String? image2url, + String? aboutme, + String? instagram, + String? tiktok, + List? visitedcountrylist, + List? wannavisitcountrylist, + List? interestlist, + List? qalist, + List? languagelist, + List? transportlist, + List? sleepingplacelist, + double? moneynumber, + double? citybeachnumber, + double? relaxpartynumber, + bool? globynomad, + }) { + return StartData( + name: name ?? this.name, + birthdate: birthdate ?? this.birthdate, + gender: gender ?? this.gender, + mainimageurl: mainimageurl ?? this.mainimageurl, + image1url: image1url ?? this.image1url, + image2url: image2url ?? this.image2url, + aboutme: aboutme ?? this.aboutme, + instagram: instagram ?? this.instagram, + tiktok: tiktok ?? this.tiktok, + visitedcountrylist: visitedcountrylist ?? this.visitedcountrylist, + wannavisitcountrylist: + wannavisitcountrylist ?? this.wannavisitcountrylist, + interestlist: interestlist ?? this.interestlist, + qalist: qalist ?? this.qalist, + languagelist: languagelist ?? this.languagelist, + transportlist: transportlist ?? this.transportlist, + sleepingplacelist: sleepingplacelist ?? this.sleepingplacelist, + moneynumber: moneynumber ?? this.moneynumber, + citybeachnumber: citybeachnumber ?? this.citybeachnumber, + relaxpartynumber: relaxpartynumber ?? this.relaxpartynumber, + globynomad: globynomad ?? this.globynomad, + ); + } } class StartProvider extends ChangeNotifier { StartData _startData = StartData( + name: '', + birthdate: '', + gender: '', + mainimageurl: '', + image1url: '', + image2url: '', + aboutme: '', + instagram: '', + tiktok: '', + visitedcountrylist: [], + wannavisitcountrylist: [], + interestlist: [], + qalist: [], + moneynumber: 0, + citybeachnumber: 0, + relaxpartynumber: 0, + languagelist: [], + transportlist: [], + sleepingplacelist: [], + globynomad: false, + ); + + StartData get startData => _startData; + + void updateStartData(StartData newData) { + _startData = newData; + notifyListeners(); // Benachrichtige alle abhängigen Widgets über die Änderung + } + + void updatePartialStartData({ + String? name, + String? birthdate, + String? gender, + String? mainimageurl, + String? image1url, + String? image2url, + String? aboutme, + String? instagram, + String? tiktok, + List? visitedcountrylist, + List? wannavisitcountrylist, + List? interestlist, + List? qalist, + List? languagelist, + List? transportlist, + List? sleepingplacelist, + double? moneynumber, + double? citybeachnumber, + double? relaxpartynumber, + bool? globynomad, + }) { + _startData = _startData.copyWith( + name: name, + birthdate: birthdate, + gender: gender, + mainimageurl: mainimageurl, + image1url: image1url, + image2url: image2url, + aboutme: aboutme, + instagram: instagram, + tiktok: tiktok, + visitedcountrylist: visitedcountrylist, + wannavisitcountrylist: wannavisitcountrylist, + interestlist: interestlist, + qalist: qalist, + languagelist: languagelist, + transportlist: transportlist, + sleepingplacelist: sleepingplacelist, + moneynumber: moneynumber, + citybeachnumber: citybeachnumber, + relaxpartynumber: relaxpartynumber, + globynomad: globynomad, + ); + notifyListeners(); // Benachrichtige alle abhängigen Widgets über die Änderung + } + + void clearData() { + _startData = StartData( name: '', birthdate: '', gender: '', @@ -54,7 +184,10 @@ class StartProvider extends ChangeNotifier { image1url: '', image2url: '', aboutme: '', - countrylist: [], + instagram: '', + tiktok: '', + visitedcountrylist: [], + wannavisitcountrylist: [], interestlist: [], qalist: [], moneynumber: 0, @@ -63,36 +196,8 @@ class StartProvider extends ChangeNotifier { languagelist: [], transportlist: [], sleepingplacelist: [], - globynomad: false); - - StartData get startData => _startData; - - void updateStartData(StartData newData) { - _startData = newData; - notifyListeners(); // Benachrichtige alle abhängigen Widgets über die Änderung - } - - void clearData() { - _startData = StartData( - name: '', - birthdate: '', - gender: '', - mainimageurl: '', - image1url: '', - image2url: '', - aboutme: '', - countrylist: [], - interestlist: [], - qalist: [], - moneynumber: 0, - citybeachnumber: 0, - relaxpartynumber: 0, - languagelist: [], - transportlist: [], - sleepingplacelist: [], - globynomad: false); // Setze den Inhalt zurück + globynomad: false, + ); // Setze den Inhalt zurück notifyListeners(); // Informiere alle Listeners über die Änderung } } - - diff --git a/lib/Screens/Chat/chat_bubble.dart b/lib/Screens/Chat/chat_bubble.dart deleted file mode 100644 index 225b98c..0000000 --- a/lib/Screens/Chat/chat_bubble.dart +++ /dev/null @@ -1,56 +0,0 @@ -import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; - -class ChatBubble extends StatelessWidget { - final String messsage; - final Timestamp time; - final bool isCurrentUser; - const ChatBubble( - {super.key, - required this.messsage, - required this.isCurrentUser, - required this.time}); - - @override - Widget build(BuildContext context) { - DateTime dateTime = time.toDate(); - - String formattedTime = DateFormat.Hm().format(dateTime); -//Chatblase - return Column( - children: [ - Container( - decoration: BoxDecoration( - color: isCurrentUser - ? const Color.fromRGBO(75, 173, 193, 1.0) - : Colors.grey.shade500, - borderRadius: BorderRadius.circular(12), - ), - padding: EdgeInsets.all(5), - margin: EdgeInsets.symmetric(vertical: 3, horizontal: 25), - child: Container( - constraints: BoxConstraints( - maxWidth: 200.0, - ), - child: Text( - messsage, - style: TextStyle(color: Colors.white, fontSize: 16), - ), - ), - // Abstand zwischhen Text und Uhrzeit - ), - Container( - constraints: BoxConstraints( - maxWidth: 200.0, // Hier kannst du die maximale Breite einstellen - ), - alignment: Alignment.centerRight, - child: Text( - formattedTime, - style: TextStyle(color: Colors.blueGrey, fontSize: 11), - ), - ), - ], - ); - } -} diff --git a/lib/Screens/Chat/chat_page.dart b/lib/Screens/Chat/chat_page.dart index 0944c5c..20e2a64 100644 --- a/lib/Screens/Chat/chat_page.dart +++ b/lib/Screens/Chat/chat_page.dart @@ -1,19 +1,22 @@ -import 'package:app_prototyo/Screens/Chat/chat_bubble.dart'; import 'package:app_prototyo/Screens/Chat/chat_service.dart'; +import 'package:app_prototyo/Screens/Findscreen/SeeUser/seeuser.dart'; import 'package:app_prototyo/Screens/LogIn/services/auth_service.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; -//Die Seite auf der die Chatblasen angezeigt werden +// Adjust the import according to your project structure + class ChatPage extends StatefulWidget { final String receiverName; final String receiverID; final String url; - ChatPage( - {super.key, - required this.receiverName, - required this.receiverID, - required this.url}); + + ChatPage({ + Key? key, + required this.receiverName, + required this.receiverID, + required this.url, + }) : super(key: key); @override State createState() => _ChatPageState(); @@ -23,56 +26,77 @@ class _ChatPageState extends State { final TextEditingController _messageController = TextEditingController(); late ScrollController _scrollController; final ChatService _chatService = ChatService(); - final AuthService _authService = AuthService(); - void sendMessage() async { - if (_messageController.text.isNotEmpty) { - await _chatService.sendMessage( - widget.receiverID, _messageController.text); - - _messageController.clear(); - } - } - + @override void initState() { super.initState(); _scrollController = ScrollController(); } + @override void dispose() { _scrollController.dispose(); super.dispose(); } + void sendMessage() async { + if (_messageController.text.isNotEmpty) { + await _chatService.sendMessage( + widget.receiverID, + _messageController.text, + ); + + _messageController.clear(); + } + } + @override Widget build(BuildContext context) { return Scaffold( - //Name und Profilbild werden in der Appbar angezeigt appBar: AppBar( - title: Row( - children: [ - CircleAvatar( - backgroundColor: widget.url.isNotEmpty ? null : Colors.grey, - backgroundImage: - widget.url.isNotEmpty ? NetworkImage(widget.url) : null, - radius: 20, - child: widget.url.isNotEmpty - ? null - : const Icon( - Icons.person, - color: Color.fromARGB(255, 178, 178, 178), - size: 60, - ), - ), - SizedBox( - width: 10, - ), - Text(widget.receiverName), - ], + title: GestureDetector( + onTap: () async { + DocumentSnapshot userSnapshot = await FirebaseFirestore.instance + .collection('user') + .doc(widget.receiverID) + .get(); + Map? userData = + userSnapshot.data() as Map?; + + if (userData != null) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SeeUser( + receiverName: widget.receiverName, + userData: userData, + ), + ), + ); + } + }, + child: Row( + children: [ + CircleAvatar( + backgroundColor: widget.url.isNotEmpty ? null : Colors.grey, + backgroundImage: + widget.url.isNotEmpty ? NetworkImage(widget.url) : null, + radius: 20, + child: widget.url.isNotEmpty + ? null + : const Icon( + Icons.person, + color: Color.fromARGB(255, 178, 178, 178), + size: 20, + ), + ), + SizedBox(width: 10), + Text(widget.receiverName), + ], + ), ), actions: [ - //Button um Nutzer zu blocken oder zu melden PopupMenuButton( icon: Icon( Icons.more_vert, @@ -111,12 +135,11 @@ class _ChatPageState extends State { children: [ Container( color: const Color.fromARGB(255, 217, 224, 238), - // Hintergrundfarbe des Body ), Container( - alignment: Alignment.center, - child: - Image.asset('assets/bilder/ApplogoohneH.png', width: 1000)), + alignment: Alignment.center, + child: Image.asset('assets/bilder/ApplogoohneH.png', width: 1000), + ), Column( children: [ Expanded( @@ -131,22 +154,21 @@ class _ChatPageState extends State { ); } -//Liste in der die Chatblasen angezeigt werden Widget _buildMessageList() { String senderID = _authService.getCurrentUser()!.uid; return StreamBuilder( stream: _chatService.getMessages(widget.receiverID, senderID), - builder: (context, snapshot) { + builder: (context, AsyncSnapshot snapshot) { if (snapshot.hasError) { - return Text('Error'); + return Center(child: Text('Error loading messages')); } if (snapshot.connectionState == ConnectionState.waiting) { - return Text('Loading...'); + return Center(child: CircularProgressIndicator()); } - WidgetsBinding.instance!.addPostFrameCallback((_) { + WidgetsBinding.instance.addPostFrameCallback((_) { _scrollController.animateTo( _scrollController.position.maxScrollExtent, duration: Duration(milliseconds: 300), @@ -154,10 +176,13 @@ class _ChatPageState extends State { ); }); - return ListView( - controller: _scrollController, // Hier den ScrollController anbinden - children: - snapshot.data!.docs.map((doc) => _buildMessageItem(doc)).toList(), + return ListView.builder( + controller: _scrollController, + itemCount: snapshot.data?.docs.length ?? 0, + itemBuilder: (context, index) { + DocumentSnapshot doc = snapshot.data!.docs[index]; + return _buildMessageItem(doc); + }, ); }, ); @@ -165,73 +190,90 @@ class _ChatPageState extends State { Widget _buildMessageItem(DocumentSnapshot doc) { Map data = doc.data() as Map; - bool isCurrentUser = data['senderID'] == _authService.getCurrentUser()!.uid; - var alignment = - isCurrentUser ? Alignment.centerRight : Alignment.centerLeft; - return Padding( - padding: const EdgeInsets.only(top: 6), - child: Container( - alignment: alignment, + padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), + child: Align( + alignment: isCurrentUser ? Alignment.centerRight : Alignment.centerLeft, + child: Container( + constraints: + BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.7), + decoration: BoxDecoration( + color: isCurrentUser + ? Color.fromRGBO(75, 173, 193, 1) + : const Color.fromARGB(255, 202, 202, 202), + borderRadius: BorderRadius.circular(15), + ), + padding: EdgeInsets.symmetric(horizontal: 15, vertical: 10), child: Column( crossAxisAlignment: isCurrentUser ? CrossAxisAlignment.end : CrossAxisAlignment.start, children: [ - ChatBubble( - messsage: data['message'], - isCurrentUser: isCurrentUser, - time: data['timestamp'], - ) + Text( + data['message'], + style: TextStyle( + color: isCurrentUser ? Colors.white : Colors.black, + fontSize: 18), + ), + SizedBox(height: 5), + Text( + _formatTimestamp(data['timestamp']), + style: TextStyle( + color: isCurrentUser ? Colors.white70 : Colors.black54, + fontSize: 10, + ), + ), ], - )), + ), + ), + ), ); } Widget _buildUserInput() { - return Row( - children: [ - Expanded( - child: SafeArea( - left: true, - child: Padding( - padding: EdgeInsets.only( - left: 20.0, - top: 12), // Anpassen des linken Paddings nach Bedarf + return SafeArea( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Expanded( child: TextField( controller: _messageController, decoration: InputDecoration( hintText: 'Type a message', enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10.0), - borderSide: - BorderSide(color: Colors.grey), // Farbe des Rahmens + borderSide: BorderSide(color: Colors.grey), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10.0), - borderSide: BorderSide( - color: Colors - .grey), // Farbe des Rahmens, wenn das Textfeld fokussiert ist + borderSide: BorderSide(color: Colors.grey), ), - // Optional: Füge zusätzlichen Raum um das TextField hinzu contentPadding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 15.0), ), obscureText: false, ), ), - ), + IconButton( + onPressed: sendMessage, + icon: Icon( + Icons.send, + size: 31, + ), + ), + ], ), - SafeArea( - child: IconButton( - onPressed: sendMessage, - icon: Icon( - Icons.send, - size: 31, - ))) - ], + ), ); } + + String _formatTimestamp(Timestamp timestamp) { + DateTime dateTime = timestamp.toDate(); + String hours = dateTime.hour.toString().padLeft(2, '0'); + String minutes = dateTime.minute.toString().padLeft(2, '0'); + return "$hours:$minutes"; + } } diff --git a/lib/Screens/Chat/chat_service.dart b/lib/Screens/Chat/chat_service.dart index 80e229e..9b7335a 100644 --- a/lib/Screens/Chat/chat_service.dart +++ b/lib/Screens/Chat/chat_service.dart @@ -3,22 +3,40 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; //Senden und empfangen der Nachricht - class ChatService { final FirebaseFirestore _firestore = FirebaseFirestore.instance; final FirebaseAuth _auth = FirebaseAuth.instance; - // Hier speichern wir vorübergehend den Status der neuen Nachrichten für jeden Chatroom - Map _unreadMessagesStatus = {}; - - Stream>> getUsersStream() { - return _firestore.collection('user').snapshots().map((snapshot) { - return snapshot.docs.map((doc) { - final user = doc.data(); + Stream>> getChatPartnersStream() async* { + final String currentUserID = _auth.currentUser!.uid; - return user; + final chatRooms = await _firestore + .collection('chat_room') + .where('participants', arrayContains: currentUserID) + .get(); + + List chatPartnerIDs = []; + for (var chatRoom in chatRooms.docs) { + List participants = List.from(chatRoom['participants']); + participants.remove(currentUserID); + chatPartnerIDs.addAll(participants); + } + chatPartnerIDs = chatPartnerIDs.toSet().toList(); + + if (chatPartnerIDs.isNotEmpty) { + final usersSnapshot = await _firestore + .collection('user') + .where(FieldPath.documentId, whereIn: chatPartnerIDs) + .get(); + + List> userList = usersSnapshot.docs.map((doc) { + return {'uid': doc.id, ...doc.data() as Map}; }).toList(); - }); + + yield userList; + } else { + yield []; + } } Future sendMessage(String receiverID, String message) async { @@ -36,18 +54,21 @@ class ChatService { ids.sort(); String chatRoomID = ids.join('_'); + await _firestore.collection('chat_room').doc(chatRoomID).set({ + 'participants': ids, + 'lastMessage': newMessage.message, + 'lastMessageTimestamp': newMessage.timestamp, + }); + await _firestore .collection('chat_room') .doc(chatRoomID) .collection('messages') .add(newMessage.toMap()); - - // Nachdem die Nachricht gesendet wurde, setzen wir den Status der neuen Nachrichten auf true - setUnreadMessagesStatus(chatRoomID, true); } - Stream getMessages(String userID, otheruserID) { - List ids = [userID, otheruserID]; + Stream getMessages(String userID, String otherUserID) { + List ids = [userID, otherUserID]; ids.sort(); String chatRoomID = ids.join('_'); @@ -59,39 +80,19 @@ class ChatService { .snapshots(); } - // Diese Methode überprüft den Status der neuen Nachrichten für einen bestimmten Chatroom - bool hasUnreadMessages(String chatRoomID) { - return _unreadMessagesStatus[chatRoomID] ?? false; - } + Future getLastMessage(String otherUserID) async { + final String currentUserID = _auth.currentUser!.uid; + List ids = [currentUserID, otherUserID]; + ids.sort(); + String chatRoomID = ids.join('_'); - // Diese Methode aktualisiert den Status der neuen Nachrichten für einen bestimmten Chatroom - void setUnreadMessagesStatus(String chatRoomID, bool hasUnread) { - _unreadMessagesStatus[chatRoomID] = hasUnread; - } -} + final chatRoomSnapshot = + await _firestore.collection('chat_room').doc(chatRoomID).get(); -class Message { - final String message; - final String receiverID; - final String senderEmail; - final String senderID; - final Timestamp timestamp; - - Message({ - required this.message, - required this.receiverID, - required this.senderEmail, - required this.senderID, - required this.timestamp, - }); - - Map toMap() { - return { - 'message': message, - 'receiverID': receiverID, - 'senderEmail': senderEmail, - 'senderID': senderID, - 'timestamp': timestamp, - }; + if (chatRoomSnapshot.exists) { + return chatRoomSnapshot.data()?['lastMessage'] ?? 'No message'; + } else { + return 'No message'; + } } } diff --git a/lib/Screens/Chat/user_tile.dart b/lib/Screens/Chat/user_tile.dart index 51598fc..a78f66c 100644 --- a/lib/Screens/Chat/user_tile.dart +++ b/lib/Screens/Chat/user_tile.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; class UserTile extends StatelessWidget { final String name; final String url; + final String lastMessage; final void Function()? onTap; final void Function()? onDismissed; @@ -11,6 +12,7 @@ class UserTile extends StatelessWidget { Key? key, required this.name, required this.url, + required this.lastMessage, required this.onTap, required this.onDismissed, }) : super(key: key); @@ -59,21 +61,36 @@ class UserTile extends StatelessWidget { radius: 40, ), const SizedBox(width: 20), - SizedBox( - width: 150, - child: Text( - name, - style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 150, + child: Text( + name, + style: const TextStyle( + fontSize: 20, fontWeight: FontWeight.bold), + ), + ), + SizedBox(height: 2), + SizedBox( + width: 150, + child: Text( + maxLines: 1, + lastMessage, + style: const TextStyle( + fontSize: 15, + ), + ), + ), + ], ), - - SizedBox(width: 50), + Spacer(), Icon( Icons.lens, size: 17, color: Color.fromARGB(255, 58, 254, 65), ) - ], ), ), diff --git a/lib/Screens/CreateUser/birthdayscreen.dart b/lib/Screens/CreateUser/birthdayscreen.dart index b7012cd..0de825b 100644 --- a/lib/Screens/CreateUser/birthdayscreen.dart +++ b/lib/Screens/CreateUser/birthdayscreen.dart @@ -6,9 +6,16 @@ import 'package:intl/intl.dart'; //Bildschirm wo der Nutzer sein Geburtsdatum eingibt welches dann im Provider gespeichhert wird -class BirthdayScreen extends StatelessWidget { +class BirthdayScreen extends StatefulWidget { const BirthdayScreen({Key? key}) : super(key: key); + @override + _BirthdayScreenState createState() => _BirthdayScreenState(); +} + +class _BirthdayScreenState extends State { + String? _selectedDate; + @override Widget build(BuildContext context) { final startProvider = Provider.of(context, listen: false); @@ -54,8 +61,8 @@ class BirthdayScreen extends StatelessWidget { child: Padding( padding: const EdgeInsets.all(10), child: Text( - startProvider.startData.birthdate, - style: TextStyle(color: Colors.black), + _selectedDate ?? 'Select Date', + style: const TextStyle(color: Colors.black), ), ), ), @@ -109,7 +116,7 @@ class BirthdayScreen extends StatelessWidget { void _validateAndNavigate(BuildContext context) { final startProvider = Provider.of(context, listen: false); - if (startProvider.startData.birthdate == null) { + if (_selectedDate == null) { showDialog( context: context, builder: (BuildContext context) { @@ -130,6 +137,30 @@ class BirthdayScreen extends StatelessWidget { }, ); } else { + startProvider.updateStartData( + StartData( + name: startProvider.startData.name, + birthdate: _selectedDate!, + gender: startProvider.startData.gender, + mainimageurl: startProvider.startData.mainimageurl, + visitedcountrylist: startProvider.startData.visitedcountrylist, + wannavisitcountrylist: startProvider.startData.wannavisitcountrylist, + interestlist: startProvider.startData.interestlist, + image1url: startProvider.startData.image1url, + image2url: startProvider.startData.image2url, + aboutme: startProvider.startData.aboutme, + instagram: startProvider.startData.instagram, + tiktok: startProvider.startData.tiktok, + qalist: startProvider.startData.qalist, + moneynumber: startProvider.startData.moneynumber, + citybeachnumber: startProvider.startData.citybeachnumber, + relaxpartynumber: startProvider.startData.relaxpartynumber, + languagelist: startProvider.startData.languagelist, + transportlist: startProvider.startData.transportlist, + sleepingplacelist: startProvider.startData.sleepingplacelist, + globynomad: startProvider.startData.globynomad, + ), + ); Navigator.push( context, MaterialPageRoute(builder: (context) => GenderScreen()), @@ -157,34 +188,9 @@ class BirthdayScreen extends StatelessWidget { ); if (picked != null) { - final formattedDate = DateFormat('MM/dd/yyyy').format(picked); - final startProvider = Provider.of(context, listen: false); - startProvider.updateStartData( - StartData( - name: startProvider.startData.name, - birthdate: formattedDate, - gender: startProvider.startData.gender, - mainimageurl: startProvider.startData.mainimageurl, - countrylist: startProvider.startData.countrylist, - interestlist: startProvider.startData.interestlist, - image1url: startProvider.startData.image1url, - image2url: startProvider.startData.image2url, - aboutme: startProvider.startData.aboutme, - qalist: startProvider.startData.qalist, - moneynumber: startProvider.startData.moneynumber, - citybeachnumber: startProvider.startData.citybeachnumber, - relaxpartynumber: startProvider.startData.relaxpartynumber, - languagelist: startProvider.startData.languagelist, - transportlist: startProvider.startData.transportlist, - sleepingplacelist: startProvider.startData.sleepingplacelist, - globynomad: startProvider.startData.globynomad, - ), - ); + setState(() { + _selectedDate = DateFormat('MM/dd/yyyy').format(picked); + }); } } - - String _getCurrentDate() { - final now = DateTime.now(); - return DateFormat('MM/dd/yyyy').format(now); - } } diff --git a/lib/Screens/CreateUser/genderscreen.dart b/lib/Screens/CreateUser/genderscreen.dart index b1963d2..1b062f5 100644 --- a/lib/Screens/CreateUser/genderscreen.dart +++ b/lib/Screens/CreateUser/genderscreen.dart @@ -7,7 +7,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; //Bildschirm wo der Nutzer sein Geschlecht eingibt welches im Provider gespeichert wird - class GenderScreen extends StatefulWidget { const GenderScreen({Key? key}) : super(key: key); @@ -16,13 +15,13 @@ class GenderScreen extends StatefulWidget { } class _GenderScreenState extends State { - late String selectedGender; + String? selectedGender; @override void initState() { super.initState(); - // Setze das ausgewählte Geschlecht auf den Standardwert - selectedGender = genders.keys.first.name; + // Set the selectedGender to null initially + selectedGender = null; } @override @@ -50,73 +49,69 @@ class _GenderScreenState extends State { fontSize: 15, ), ), - const SizedBox( - height: 10, - ), + const SizedBox(height: 10), Column( - children: genders.entries - .map( - (entry) => Container( - margin: const EdgeInsets.symmetric(vertical: 8.0), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(25), - ), - child: RadioListTile( - title: Padding( - padding: const EdgeInsets.all(0), - child: Text( - entry.value.name, - style: const TextStyle(color: Colors.black), - ), - ), - activeColor: Colors.black, - controlAffinity: ListTileControlAffinity.trailing, - value: entry.key.name, - groupValue: selectedGender, - onChanged: (value) { - setState(() { - selectedGender = value!; - final startProvider = Provider.of( - context, - listen: false, - ); - startProvider.updateStartData( - StartData( - name: startProvider.startData.name, - birthdate: startProvider.startData.birthdate, - gender: value!, // Direkter Stringwert - mainimageurl: - startProvider.startData.mainimageurl, - countrylist: - startProvider.startData.countrylist, - interestlist: - startProvider.startData.interestlist, - image1url: startProvider.startData.image1url, - image2url: startProvider.startData.image2url, - aboutme: startProvider.startData.aboutme, - qalist: startProvider.startData.qalist, - moneynumber: - startProvider.startData.moneynumber, - citybeachnumber: - startProvider.startData.citybeachnumber, - relaxpartynumber: - startProvider.startData.relaxpartynumber, - languagelist: - startProvider.startData.languagelist, - transportlist: - startProvider.startData.transportlist, - sleepingplacelist: - startProvider.startData.sleepingplacelist, - globynomad: startProvider.startData.globynomad, - ), - ); - }); - }, + children: genders.entries.map((entry) { + return Container( + margin: const EdgeInsets.symmetric(vertical: 8.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(25), + ), + child: RadioListTile( + title: Padding( + padding: const EdgeInsets.all(0), + child: Text( + entry.value.name, + style: const TextStyle(color: Colors.black), ), ), - ) - .toList(), + activeColor: Colors.black, + controlAffinity: ListTileControlAffinity.trailing, + value: entry.key.name, + groupValue: selectedGender, + onChanged: (value) { + setState(() { + selectedGender = value; + final startProvider = Provider.of( + context, + listen: false, + ); + startProvider.updateStartData( + StartData( + name: startProvider.startData.name, + birthdate: startProvider.startData.birthdate, + gender: value!, + mainimageurl: startProvider.startData.mainimageurl, + visitedcountrylist: + startProvider.startData.visitedcountrylist, + wannavisitcountrylist: + startProvider.startData.wannavisitcountrylist, + interestlist: startProvider.startData.interestlist, + image1url: startProvider.startData.image1url, + image2url: startProvider.startData.image2url, + aboutme: startProvider.startData.aboutme, + instagram: startProvider.startData.instagram, + tiktok: startProvider.startData.tiktok, + qalist: startProvider.startData.qalist, + moneynumber: startProvider.startData.moneynumber, + citybeachnumber: + startProvider.startData.citybeachnumber, + relaxpartynumber: + startProvider.startData.relaxpartynumber, + languagelist: startProvider.startData.languagelist, + transportlist: + startProvider.startData.transportlist, + sleepingplacelist: + startProvider.startData.sleepingplacelist, + globynomad: startProvider.startData.globynomad, + ), + ); + }); + }, + ), + ); + }).toList(), ), const Row( children: [ @@ -154,10 +149,33 @@ class _GenderScreenState extends State { size: 35, ), onPressed: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => PicScreen()), - ); + if (selectedGender != null) { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => PicScreen()), + ); + } else { + // Show a message or handle the case where no gender is selected + showDialog( + context: context, + builder: (context) { + return AlertDialog( + content: Text('Please choose a gender'), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text( + 'OK', + style: TextStyle(color: Colors.grey), + ), + ), + ], + ); + }, + ); + } }, ), ], diff --git a/lib/Screens/CreateUser/interestscreen.dart b/lib/Screens/CreateUser/interestscreen.dart index 61f4956..72334ce 100644 --- a/lib/Screens/CreateUser/interestscreen.dart +++ b/lib/Screens/CreateUser/interestscreen.dart @@ -10,6 +10,9 @@ import '../../Provider/user_provider.dart'; //Interessen werden im Provider gespeichert +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + const DefaultButtonColor = Color.fromARGB(255, 255, 255, 255); const SelectedButtonColor = Color.fromARGB(255, 224, 226, 228); const DefaultLineColor = Color.fromARGB(255, 255, 255, 255); @@ -24,6 +27,7 @@ class InterestScreen extends StatefulWidget { class _InterestScreenState extends State { Map buttonColors = {}; + @override Widget build(BuildContext context) { double topPadding = MediaQuery.of(context).padding.top; @@ -38,7 +42,7 @@ class _InterestScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( - 'Choose 5 of your favorite interest', + 'Choose 5 of your favorite interests', style: TextStyle( color: Colors.white, fontSize: 30, @@ -48,13 +52,10 @@ class _InterestScreenState extends State { Expanded( child: SingleChildScrollView( padding: const EdgeInsets.all(10.0), - child: SingleChildScrollView( - padding: const EdgeInsets.all(10.0), - child: Wrap( - spacing: 8.0, - runSpacing: 8.0, - children: _buildInterestTiles(), - ), + child: Wrap( + spacing: 8.0, + runSpacing: 8.0, + children: _buildInterestTiles(), ), ), ), @@ -90,8 +91,7 @@ class _InterestScreenState extends State { context: context, builder: (BuildContext context) { return AlertDialog( - content: - Text('Please choose your favourit destinations'), + content: Text('Please choose your favorite interests'), actions: [ TextButton( onPressed: () { @@ -128,34 +128,56 @@ class _InterestScreenState extends State { } Widget _buildInterestButton(Interest interest) { + final startProvider = Provider.of(context, listen: false); bool isSelected = buttonColors.containsKey(interest); return ElevatedButton( key: Key(interest.name), onPressed: () { - final startProvider = Provider.of(context, - listen: false); // Obtain StartProvider instance setState(() { if (isSelected) { buttonColors.remove(interest); startProvider.startData.interestlist .remove(interest.name); // Remove from interestlist } else { - buttonColors[interest] = SelectedButtonColor; - startProvider.startData.interestlist - .add(interest.name); // Add to interestlist + if (startProvider.startData.interestlist.length < 5) { + buttonColors[interest] = SelectedButtonColor; + startProvider.startData.interestlist + .add(interest.name); // Add to interestlist + } else { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + content: Text('You can select up to 5 interests only'), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text( + 'OK', + style: TextStyle(color: Colors.grey), + ), + ), + ], + ); + }, + ); + } } }); }, style: ElevatedButton.styleFrom( - padding: const EdgeInsets.all(8.0), - backgroundColor: - isSelected ? SelectedButtonColor : DefaultButtonColor, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(20.0), - side: BorderSide( - color: isSelected ? SelectedLineColor : DefaultLineColor, - ))), + padding: const EdgeInsets.all(8.0), + backgroundColor: isSelected ? SelectedButtonColor : DefaultButtonColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20.0), + side: BorderSide( + color: isSelected ? SelectedLineColor : DefaultLineColor, + ), + ), + ), child: _buildButtonContent(interest), ); } @@ -183,8 +205,6 @@ class _InterestScreenState extends State { } } -//Der Provider sendet alle Daten an die Cloud - void updateDocument(BuildContext context) async { try { final currentUser = FirebaseAuth.instance.currentUser; @@ -195,7 +215,6 @@ void updateDocument(BuildContext context) async { StartProvider startProvider = Provider.of(context, listen: false); - //Das ist das Dokument in Firebase await FirebaseFirestore.instance .collection('user') .doc(currentUserUid) @@ -204,7 +223,9 @@ void updateDocument(BuildContext context) async { 'age': startProvider.startData.birthdate, 'gender': startProvider.startData.gender, 'mainimage': startProvider.startData.mainimageurl, - 'list of countries': startProvider.startData.countrylist, + 'list of visitedcountries': startProvider.startData.visitedcountrylist, + 'list of wannavisitcountries': + startProvider.startData.wannavisitcountrylist, 'list of interest': startProvider.startData.interestlist, 'uid': currentUserUid, 'mail': email, diff --git a/lib/Screens/CreateUser/namescreen.dart b/lib/Screens/CreateUser/namescreen.dart index 978ff0a..94a9e56 100644 --- a/lib/Screens/CreateUser/namescreen.dart +++ b/lib/Screens/CreateUser/namescreen.dart @@ -51,24 +51,33 @@ class NameScreen extends StatelessWidget { child: Padding( padding: const EdgeInsets.all(0), child: TextField( + textCapitalization: TextCapitalization.words, decoration: InputDecoration(border: InputBorder.none), onChanged: (value) { + String capitalizedValue = value.isNotEmpty + ? value[0].toUpperCase() + value.substring(1) + : value; + final startProvider = Provider.of(context, listen: false); startProvider.updateStartData(StartData( - name: value, + name: capitalizedValue, birthdate: startProvider .startData.birthdate, // Verwende das aktuelle Alter gender: startProvider .startData.gender, // Verwende das aktuelle Geschlecht mainimageurl: startProvider.startData .mainimageurl, // Verwende die aktuelle Hauptbild-URL - countrylist: startProvider.startData - .countrylist, // Verwende die aktuelle Länderliste + visitedcountrylist: + startProvider.startData.visitedcountrylist, + wannavisitcountrylist: startProvider.startData + .wannavisitcountrylist, // Verwende die aktuelle Länderliste interestlist: startProvider.startData.interestlist, image1url: startProvider.startData.image1url, image2url: startProvider.startData.image2url, aboutme: startProvider.startData.aboutme, + instagram: startProvider.startData.instagram, + tiktok: startProvider.startData.tiktok, qalist: startProvider.startData.qalist, moneynumber: startProvider.startData.moneynumber, citybeachnumber: startProvider.startData.citybeachnumber, diff --git a/lib/Screens/CreateUser/picsscreen.dart b/lib/Screens/CreateUser/picsscreen.dart index 66f98b1..5bcf833 100644 --- a/lib/Screens/CreateUser/picsscreen.dart +++ b/lib/Screens/CreateUser/picsscreen.dart @@ -58,7 +58,11 @@ class _PicScreenState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - CircularProgressIndicator(), // Ladekreis anzeigen + CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation( + const Color.fromARGB(255, 75, 173, 193), + ), + ), // Ladekreis anzeigen SizedBox(height: 10), Text("Uploading image..."), // Text anzeigen ], @@ -80,11 +84,16 @@ class _PicScreenState extends State { birthdate: startProvider.startData.birthdate, gender: startProvider.startData.gender, mainimageurl: mainimageUrl, - countrylist: startProvider.startData.countrylist, + visitedcountrylist: + startProvider.startData.visitedcountrylist, + wannavisitcountrylist: + startProvider.startData.wannavisitcountrylist, interestlist: startProvider.startData.interestlist, image1url: startProvider.startData.image1url, image2url: startProvider.startData.image2url, aboutme: startProvider.startData.aboutme, + instagram: startProvider.startData.instagram, + tiktok: startProvider.startData.tiktok, qalist: startProvider.startData.qalist, moneynumber: startProvider.startData.moneynumber, citybeachnumber: startProvider.startData.citybeachnumber, diff --git a/lib/Screens/CreateUser/welcomescreen.dart b/lib/Screens/CreateUser/welcomescreen.dart index 83e32fa..4d72500 100644 --- a/lib/Screens/CreateUser/welcomescreen.dart +++ b/lib/Screens/CreateUser/welcomescreen.dart @@ -13,6 +13,9 @@ class WelcomeScreen extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ + SizedBox( + height: 60, + ), Text( 'Aloha!', style: TextStyle( @@ -29,7 +32,7 @@ class WelcomeScreen extends StatelessWidget { ), Text( 'Please respect the following guidelines', - style: TextStyle(color: Colors.blueGrey, fontSize: 20), + style: TextStyle(color: Colors.blueGrey, fontSize: 18), ), SizedBox( height: 18, @@ -82,7 +85,7 @@ class WelcomeScreen extends StatelessWidget { 'Always report bad behavior.', style: TextStyle(color: Colors.blueGrey, fontSize: 18), ), - SizedBox(height: 30), + SizedBox(height: 10), Row( children: [ Icon( diff --git a/lib/Screens/Findscreen/SeeUser/seeuser.dart b/lib/Screens/Findscreen/SeeUser/seeuser.dart index 1be3e3b..a2ca5cd 100644 --- a/lib/Screens/Findscreen/SeeUser/seeuser.dart +++ b/lib/Screens/Findscreen/SeeUser/seeuser.dart @@ -1,6 +1,8 @@ - import 'package:app_prototyo/Klassen/allgemein.dart'; import 'package:app_prototyo/Screens/Findscreen/SeeUser/UserStandort.dart'; + +import 'package:app_prototyo/Screens/Chat/chat_page.dart'; + import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'age_calculator.dart'; @@ -94,8 +96,21 @@ class SeeUser extends StatelessWidget { Padding( padding: const EdgeInsets.only(right: 17.0, top: 5), child: IconButton( - onPressed: () {}, - icon: const Icon(Icons.chat_bubble_outline, size: 32), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ChatPage( + receiverName: userData!['name'], + receiverID: userData!['uid'], + url: userData!['mainimage']), + ), + ); + }, // Navigation zum individuellen ChatScreen + icon: const Icon( + Icons.chat_bubble_outline, + size: 32, + ), ), ) ], @@ -200,30 +215,30 @@ class SeeUser extends StatelessWidget { ], ), GestureDetector( - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => Probe()), - ); - }, - child: Container( - margin: const EdgeInsets.only(top: 20), - width: 230 + 112 + 10 + 5, - height: 100, - decoration: BoxDecoration( - color: Colors.green, - borderRadius: BorderRadius.circular(5), - ), - child: const Center( - child: Text( - 'Standort', - style: TextStyle( - color: Colors.white, - ), - ), - ), - ), -), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => Probe()), + ); + }, + child: Container( + margin: const EdgeInsets.only(top: 20), + width: 230 + 112 + 10 + 5, + height: 100, + decoration: BoxDecoration( + color: Colors.green, + borderRadius: BorderRadius.circular(5), + ), + child: const Center( + child: Text( + 'Standort', + style: TextStyle( + color: Colors.white, + ), + ), + ), + ), + ), Visibility( visible: userData?['Aboutme'] != null && @@ -631,4 +646,3 @@ class SliderWidget extends StatelessWidget { ); } } - diff --git a/lib/Screens/LogIn/components/my_button.dart b/lib/Screens/LogIn/components/my_button.dart deleted file mode 100644 index bfb06ec..0000000 --- a/lib/Screens/LogIn/components/my_button.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:flutter/material.dart'; - -class MyButton extends StatelessWidget { - - final Function()? onTap; - final String text; - - const MyButton({super.key, required this.onTap, required this.text}); - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: onTap, - child: Container( - padding: const EdgeInsets.all(20), - margin: const EdgeInsets.symmetric(horizontal: 30), - decoration: BoxDecoration( - color: const Color.fromARGB(255, 41, 51, 76), - borderRadius: BorderRadius.circular(8), - ), - child: Center( - child: Text( - text, - style: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ), - ), - ); - } -} diff --git a/lib/Screens/LogIn/components/my_textfield.dart b/lib/Screens/LogIn/components/my_textfield.dart deleted file mode 100644 index bb71ad2..0000000 --- a/lib/Screens/LogIn/components/my_textfield.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'package:flutter/material.dart'; - - -// - - - - - - - - - - - - - - - - - - - T E X T F I E L D - - - - - - - - - - - - - - - - - - - - - - - - - - - -class MyTextField extends StatelessWidget { - final controller; - final String hintText; - final bool obscureText; - - const MyTextField({ - super.key, - required this.controller, - required this.hintText, - required this.obscureText, - }); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 30), - child: TextField( - controller: controller, - obscureText: obscureText, - decoration: InputDecoration( - enabledBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Color.fromRGBO(75, 173, 193, 1.0)), - ), - focusedBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Color.fromARGB(255, 41, 51, 76)), - ), - fillColor: const Color.fromARGB(214, 216, 231, 234), - filled: true, - hintText: hintText, - hintStyle: TextStyle(color: Colors.grey[600]) - ), - ), - ); - } -} diff --git a/lib/Screens/LogIn/components/square_tile.dart b/lib/Screens/LogIn/components/square_tile.dart deleted file mode 100644 index 3a3ab5c..0000000 --- a/lib/Screens/LogIn/components/square_tile.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'package:flutter/material.dart'; - -class SquareTile extends StatelessWidget { - final String imagePath; - final Function()? onTap; - const SquareTile({ - super. key, - required this.imagePath, - required this.onTap, - }) ; - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: onTap, - child: Container( - padding: EdgeInsets.all(10), - decoration: BoxDecoration( - border: Border.all( - color: Colors.white), - borderRadius: BorderRadius.circular(16), - color: const Color.fromARGB(214, 216, 231, 234), - ), - child: Image.asset(imagePath, - height: 40, - ), - ), - ); - } -} - - - diff --git a/lib/Screens/LogIn/login_page.dart b/lib/Screens/LogIn/login_page.dart index 57c4739..9fe5e0e 100644 --- a/lib/Screens/LogIn/login_page.dart +++ b/lib/Screens/LogIn/login_page.dart @@ -1,10 +1,13 @@ import 'package:app_prototyo/Provider/user_provider.dart'; import 'package:app_prototyo/Screens/LogIn/forgot_pw_page.dart'; +import 'package:app_prototyo/Screens/LogIn/register_page.dart'; import 'package:app_prototyo/Screens/LogIn/services/auth_service.dart'; +import 'package:app_prototyo/Screens/homebar.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'package:firebase_auth/firebase_auth.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:provider/provider.dart'; class LoginPage extends StatefulWidget { @@ -40,7 +43,6 @@ class _LoginPageState extends State { password: passwordController.text, ); - // After successful login, load user data if (mounted) { loadUserData(); } @@ -88,40 +90,6 @@ class _LoginPageState extends State { if (mounted && userSnapshot.exists) { // Überprüfung auf mounted - Map userData = - userSnapshot.data() as Map; - - List countryList = - _parseStringList(userData['list of countries']); - List interestList = - _parseStringList(userData['list of interest']); - List qaList = - _parseStringList(userData['List Question + Answer']); - List languageList = - _parseStringList(userData['List Language']); - List transportList = _parseStringList(userData['Transport']); - List sleepingPlaceList = - _parseStringList(userData['Sleepinggplace']); - - StartData startData = StartData( - name: userData['name'] ?? '', - birthdate: userData['age'] ?? '', - gender: userData['gender'] ?? '', - mainimageurl: userData['mainimage'] ?? '', - image1url: userData['image1'] ?? '', - image2url: userData['image2'] ?? '', - aboutme: userData['Aboutme'] ?? '', - countrylist: countryList, - interestlist: interestList, - qalist: qaList, - languagelist: languageList, - transportlist: transportList, - sleepingplacelist: sleepingPlaceList, - moneynumber: _parseDouble(userData['MoneyNumber']), - citybeachnumber: _parseDouble(userData['CityBeachNumber']), - relaxpartynumber: _parseDouble(userData['RelaxPartyNumber']), - globynomad: userData['Globy Nomad'] ?? false, - ); } } } catch (error) { @@ -154,239 +122,161 @@ class _LoginPageState extends State { backgroundColor: const Color.fromRGBO(75, 173, 193, 1.0), resizeToAvoidBottomInset: false, body: SafeArea( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - 'Fall in love with the world', - style: TextStyle( - color: Colors.white, - fontSize: 20, - fontStyle: FontStyle.italic, - ), - ), - const SizedBox(height: 20), - Container( - margin: const EdgeInsets.only( - top: 20, - bottom: 5, - left: 20, - right: 20, - ), - width: 200, - child: Image.asset('assets/bilder/Applogo.png'), - ), - const SizedBox(height: 20), - MyTextField( - controller: emailController, - hintText: 'Email', - obscureText: false, - ), - const SizedBox(height: 10), - MyTextField( - controller: passwordController, - hintText: 'Password', - obscureText: true, - ), - const SizedBox(height: 4), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 30), - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - GestureDetector( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) { - return const ForgotPasswordPage(); - }, - ), - ); - }, - child: const Text( - 'Forgot Password?', + child: LayoutBuilder( + builder: (context, constraints) { + double paddingHorizontal = constraints.maxWidth * 0.1; + return SingleChildScrollView( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: paddingHorizontal), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + 'Fall in love with the world', style: TextStyle( - color: Color.fromARGB(255, 41, 51, 76), - fontWeight: FontWeight.bold, + color: Colors.white, + fontSize: 20, + fontStyle: FontStyle.italic, ), ), - ), - ], - ), - ), - const SizedBox(height: 20), - MyButton( - text: "Log In", - onTap: () { - signUserIn(); - }, - ), - const SizedBox(height: 90), - const Padding( - padding: EdgeInsets.symmetric(horizontal: 30), - child: Row( - children: [ - Expanded( - child: Divider( - thickness: 0.5, - color: Colors.white, + const SizedBox(height: 20), + Container( + margin: const EdgeInsets.only( + top: 20, + bottom: 5, + ), + width: constraints.maxWidth * 0.5, + child: Image.asset('assets/bilder/Applogo.png'), ), - ), - Padding( - padding: EdgeInsets.symmetric(horizontal: 15), - child: Text( - 'Or continue with', - style: TextStyle(color: Color.fromARGB(255, 66, 66, 66)), + const SizedBox(height: 20), + MyTextField( + controller: emailController, + hintText: 'Email', + obscureText: false, ), - ), - Expanded( - child: Divider( - thickness: 0.5, - color: Colors.white, + const SizedBox(height: 10), + MyTextField( + controller: passwordController, + hintText: 'Password', + obscureText: true, ), - ), - ], - ), - ), - const SizedBox(height: 20), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SquareTile( - onTap: () => AuthService().signInWithGoogle(), - imagePath: 'assets/bilder/google.png', - ), - const SizedBox(width: 20), - SquareTile( - onTap: () {}, - imagePath: 'assets/bilder/apple.png', - ), - ], - ), - const SizedBox(height: 20), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - 'Not am Member?', - style: TextStyle(color: Color.fromARGB(255, 66, 66, 66)), - ), - const SizedBox(width: 4), - GestureDetector( - onTap: widget.onTap, - child: const Text( - 'Register now', - style: TextStyle( - color: Color.fromARGB(255, 41, 51, 76), - fontWeight: FontWeight.bold, + const SizedBox(height: 4), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const ForgotPasswordPage(); + }, + ), + ); + }, + child: const Text( + 'Forgot Password?', + style: TextStyle( + color: Color.fromARGB(255, 41, 51, 76), + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ), + const SizedBox(height: 20), + MyButton( + text: "Log In", + onTap: () { + signUserIn(); + }, + ), + const SizedBox(height: 90), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 30), + child: Row( + children: [ + Expanded( + child: Divider( + thickness: 0.5, + color: Colors.white, + ), + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: 15), + child: Text( + 'Or continue with', + style: TextStyle( + color: Color.fromARGB(255, 66, 66, 66)), + ), + ), + Expanded( + child: Divider( + thickness: 0.5, + color: Colors.white, + ), + ), + ], + ), ), - ), + const SizedBox(height: 20), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + IconButton( + onPressed: () => AuthService().signInWithGoogle(), + icon: Icon( + FontAwesomeIcons.google, + size: 50, + color: const Color.fromRGBO(1, 25, 45, 0.7), + ), + ), + SizedBox(width: 10), + IconButton( + onPressed: () {}, + icon: Icon( + FontAwesomeIcons.apple, + size: 50, + color: const Color.fromRGBO(1, 25, 45, 0.7), + ), + ), + ], + ), + const SizedBox(height: 20), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + 'Not am Member?', + style: + TextStyle(color: Color.fromARGB(255, 66, 66, 66)), + ), + const SizedBox(width: 4), + GestureDetector( + onTap: widget.onTap, + child: const Text( + 'Register now', + style: TextStyle( + color: Color.fromARGB(255, 41, 51, 76), + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + if (_isLoading) + const CircularProgressIndicator( + color: Color.fromARGB(255, 41, 51, 76), + ), + ], ), - ], - ), - if (_isLoading) - CircularProgressIndicator( - color: Color.fromARGB(255, 41, 51, 76), ), - ], - ), - ), - ); - } -} - -class MyTextField extends StatelessWidget { - final TextEditingController controller; - final String hintText; - final bool obscureText; - - const MyTextField({ - Key? key, - required this.controller, - required this.hintText, - this.obscureText = false, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Container( - margin: const EdgeInsets.symmetric(horizontal: 30), - child: TextField( - controller: controller, - obscureText: obscureText, - style: const TextStyle(color: Colors.white), - decoration: InputDecoration( - hintText: hintText, - hintStyle: const TextStyle(color: Colors.white70), - filled: true, - fillColor: const Color.fromRGBO(1, 25, 45, 0.7), - enabledBorder: OutlineInputBorder( - borderSide: const BorderSide(color: Colors.transparent), - borderRadius: BorderRadius.circular(10), - ), - focusedBorder: OutlineInputBorder( - borderSide: const BorderSide(color: Colors.white), - borderRadius: BorderRadius.circular(10), - ), - ), - ), - ); - } -} - -class MyButton extends StatelessWidget { - final String text; - final VoidCallback onTap; - - const MyButton({Key? key, required this.text, required this.onTap}) - : super(key: key); - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: onTap, - child: Container( - margin: const EdgeInsets.symmetric(horizontal: 30), - padding: const EdgeInsets.symmetric(vertical: 12), - decoration: BoxDecoration( - color: const Color.fromRGBO(41, 51, 76, 1.0), - borderRadius: BorderRadius.circular(10), - ), - alignment: Alignment.center, - child: Text( - text, - style: const TextStyle( - color: Colors.white, - fontSize: 16, - ), - ), - ), - ); - } -} - -class SquareTile extends StatelessWidget { - final VoidCallback onTap; - final String imagePath; - - const SquareTile({Key? key, required this.onTap, required this.imagePath}) - : super(key: key); - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: onTap, - child: Container( - width: 60, - height: 60, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - image: DecorationImage( - image: AssetImage(imagePath), - fit: BoxFit.cover, - ), + ); + }, ), ), ); diff --git a/lib/Screens/LogIn/register_page.dart b/lib/Screens/LogIn/register_page.dart index 6f3d107..b6af0cc 100644 --- a/lib/Screens/LogIn/register_page.dart +++ b/lib/Screens/LogIn/register_page.dart @@ -1,11 +1,14 @@ -import 'package:app_prototyo/Screens/LogIn/components/my_button.dart'; -import 'package:app_prototyo/Screens/LogIn/components/my_textfield.dart'; -import 'package:app_prototyo/Screens/LogIn/components/square_tile.dart'; +import 'package:app_prototyo/Screens/CreateUser/welcomescreen.dart'; import 'package:app_prototyo/Screens/LogIn/services/auth_service.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:provider/provider.dart'; + class RegisterPage extends StatefulWidget { final Function()? onTap; const RegisterPage({super.key, required this.onTap}); @@ -15,16 +18,12 @@ class RegisterPage extends StatefulWidget { } class _RegisterPageState extends State { - // text editing controllers ( ob des Text im Kästchen angezeigt wuird oder wie beim passwort verdeckt bleibt) final emailController = TextEditingController(); final passwordController = TextEditingController(); final confirmPasswordController = TextEditingController(); - // Sign user in - // Sign user in Future signUserUp() async { try { - // Anzeige des Ladekreises showDialog( context: context, builder: (context) { @@ -34,30 +33,24 @@ class _RegisterPageState extends State { }, ); - // Versuche, den Benutzer zu erstellen if (passwordController.text == confirmPasswordController.text) { await FirebaseAuth.instance.createUserWithEmailAndPassword( email: emailController.text, password: passwordController.text, ); - // Erfolgreich registriert return true; } else { - // Fehler: Passwörter stimmen nicht überein showErrorMessage("Passwords don't match!"); return false; } } on FirebaseAuthException catch (e) { - // Fehler beim Erstellen des Benutzers showErrorMessage(e.code); return false; } finally { - // Schließe den Ladekreis unabhängig vom Ergebnis Navigator.pop(context); } } - // error Message to user void showErrorMessage(String message) { showDialog( context: context, @@ -80,139 +73,238 @@ class _RegisterPageState extends State { @override Widget build(BuildContext context) { + final screenHeight = MediaQuery.of(context).size.height; + final screenWidth = MediaQuery.of(context).size.width; + return Scaffold( backgroundColor: const Color.fromRGBO(75, 173, 193, 1.0), body: SafeArea( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox(height: 20), - - // - - - - - - - - - - - - - Logo - - - - - - - - - - - - - - Container( - margin: const EdgeInsets.only( - top: 20, - bottom: 5, - left: 20, - right: 20, - ), - width: 160, // --> skalliert das LOGO - child: Image.asset('assets/bilder/Applogo.png'), - ), - - const SizedBox(height: 10), - - const Text( - 'Let\'s create an account for you!', - style: TextStyle( - color: Color.fromARGB(255, 41, 51, 76), - fontWeight: FontWeight.bold, - fontSize: 16, - fontStyle: FontStyle.italic, - ), - ), - - const SizedBox(height: 10), - // - - - - - - - - - - - - - Card mit Einlogdaten - - - - - - - - - - - - - - MyTextField( - controller: emailController, - hintText: 'Email', - obscureText: false, - ), - - const SizedBox(height: 10), - - MyTextField( - controller: passwordController, - hintText: 'Password', - obscureText: - true, // dass das geschriebene wort NICHT angezeigt wird - ), - - const SizedBox(height: 10), -// confirm password - MyTextField( - controller: confirmPasswordController, - hintText: 'Confirm Password', - obscureText: - true, // dass das geschriebene wort NICHT angezeigt wird - ), - - const SizedBox(height: 30), - - // - - - - - - - - - - - - - - - - Button- - - - - - - - - - - - - - - - - - - MyButton( - text: "Create Account", - onTap: () async { - await signUserUp(); - }), - - const SizedBox(height: 57), - - // - - - - - - - - - - - - - - - -google + apple sign in - - - - - - - - - - - - - - - const Padding( - padding: EdgeInsets.symmetric(horizontal: 30), - child: Row( + child: Center( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, children: [ - Expanded( - child: Divider( - thickness: 0.5, + SizedBox(height: screenHeight * 0.02), + Container( + margin: const EdgeInsets.symmetric(vertical: 20), + width: screenWidth * 0.4, + child: Image.asset('assets/bilder/Applogo.png'), + ), + const Text( + 'Lets create an account for you', + style: TextStyle( color: Colors.white, + fontSize: 20, + fontStyle: FontStyle.italic, ), ), - Padding( - padding: EdgeInsets.symmetric(horizontal: 15), - child: Text( - 'Or continue with', - style: TextStyle(color: Color.fromARGB(255, 66, 66, 66)), - ), + SizedBox(height: screenHeight * 0.02), + MyTextField( + controller: emailController, + hintText: 'Email', + obscureText: false, ), - Expanded( - child: Divider( - thickness: 0.5, - color: Colors.white, + SizedBox(height: screenHeight * 0.02), + MyTextField( + controller: passwordController, + hintText: 'Password', + obscureText: true, + ), + SizedBox(height: screenHeight * 0.02), + MyTextField( + controller: confirmPasswordController, + hintText: 'Confirm Password', + obscureText: true, + ), + SizedBox(height: screenHeight * 0.05), + MyButton( + text: "Create Account", + onTap: () async { + bool success = await signUserUp(); + if (success) { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return WelcomeScreen(); + }, + ), + ); + } + }, + ), + SizedBox(height: screenHeight * 0.05), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 30), + child: Row( + children: [ + Expanded( + child: Divider( + thickness: 0.5, + color: Colors.white, + ), + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: 15), + child: Text( + 'Or continue with', + style: TextStyle( + color: Color.fromARGB(255, 66, 66, 66)), + ), + ), + Expanded( + child: Divider( + thickness: 0.5, + color: Colors.white, + ), + ), + ], ), ), + SizedBox(height: screenHeight * 0.02), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + IconButton( + onPressed: () => AuthService().signInWithGoogle(), + icon: Icon( + FontAwesomeIcons.google, + size: 50, + color: const Color.fromRGBO(1, 25, 45, 0.7), + ), + ), + SizedBox(width: screenWidth * 0.05), + IconButton( + onPressed: () {}, + icon: Icon( + FontAwesomeIcons.apple, + size: 50, + color: const Color.fromRGBO(1, 25, 45, 0.7), + ), + ), + ], + ), + SizedBox(height: screenHeight * 0.02), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + 'Already have an account?', + style: + TextStyle(color: Color.fromARGB(255, 66, 66, 66)), + ), + const SizedBox(width: 4), + GestureDetector( + onTap: widget.onTap, + child: const Text( + 'Login now', + style: TextStyle( + color: Color.fromARGB(255, 41, 51, 76), + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), ], ), ), + ), + ), + ), + ); + } +} - const SizedBox(height: 20), - - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SquareTile( - onTap: () => AuthService().signInWithGoogle(), - imagePath: 'assets/bilder/google.png'), - const SizedBox(width: 20), - SquareTile(onTap: () {}, imagePath: 'assets/bilder/apple.png'), - ], - ), +class MyTextField extends StatelessWidget { + final TextEditingController controller; + final String hintText; + final bool obscureText; - const SizedBox(height: 20), - // - - - - - - - - - - - - - - - - - not a member? register now - - - - - - - - - - - - - - - - - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - 'Already have an account?', - style: TextStyle(color: Color.fromARGB(255, 66, 66, 66)), - ), - const SizedBox(width: 4), - GestureDetector( - onTap: widget.onTap, - child: const Text( - 'Login now', - style: TextStyle( - color: Color.fromARGB(255, 41, 51, 76), - fontWeight: FontWeight.bold), - ), - ), - ], - ) - ], + const MyTextField({ + Key? key, + required this.controller, + required this.hintText, + this.obscureText = false, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return TextField( + controller: controller, + obscureText: obscureText, + style: const TextStyle(color: Colors.white), + decoration: InputDecoration( + hintText: hintText, + hintStyle: const TextStyle(color: Colors.white70), + filled: true, + fillColor: const Color.fromRGBO(1, 25, 45, 0.7), + enabledBorder: OutlineInputBorder( + borderSide: const BorderSide(color: Colors.transparent), + borderRadius: BorderRadius.circular(10), + ), + focusedBorder: OutlineInputBorder( + borderSide: const BorderSide(color: Colors.white), + borderRadius: BorderRadius.circular(10), + ), + ), + ); + } +} + +class MyButton extends StatelessWidget { + final String text; + final VoidCallback onTap; + + const MyButton({Key? key, required this.text, required this.onTap}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onTap, + child: Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(vertical: 12), + decoration: BoxDecoration( + color: const Color.fromRGBO(41, 51, 76, 1.0), + borderRadius: BorderRadius.circular(10), + ), + alignment: Alignment.center, + child: Text( + text, + style: const TextStyle( + color: Colors.white, + fontSize: 16, + ), + ), + ), + ); + } +} + +class SquareTile extends StatelessWidget { + final VoidCallback onTap; + final String imagePath; + + const SquareTile({Key? key, required this.onTap, required this.imagePath}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onTap, + child: Container( + width: 60, + height: 60, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + image: DecorationImage( + image: AssetImage(imagePath), + fit: BoxFit.cover, + ), ), ), ); diff --git a/lib/Screens/LogIn/services/auth_service.dart b/lib/Screens/LogIn/services/auth_service.dart index 59c59f3..a52f47e 100644 --- a/lib/Screens/LogIn/services/auth_service.dart +++ b/lib/Screens/LogIn/services/auth_service.dart @@ -2,7 +2,8 @@ import 'package:firebase_auth/firebase_auth.dart'; import 'package:google_sign_in/google_sign_in.dart'; class AuthService { - FirebaseAuth _auth = FirebaseAuth.instance; + final FirebaseAuth _auth = FirebaseAuth.instance; + // Google Sign in signInWithGoogle() async { // begin interactive sign in process diff --git a/lib/Screens/Profilscreen/Komponenten/aboutme.dart b/lib/Screens/Profilscreen/Komponenten/aboutme.dart index 546b63c..834740a 100644 --- a/lib/Screens/Profilscreen/Komponenten/aboutme.dart +++ b/lib/Screens/Profilscreen/Komponenten/aboutme.dart @@ -53,11 +53,16 @@ class _AboutmeContainerState extends State { birthdate: startProvider.startData.birthdate, gender: startProvider.startData.gender, mainimageurl: startProvider.startData.mainimageurl, - countrylist: startProvider.startData.countrylist, + visitedcountrylist: + startProvider.startData.visitedcountrylist, + wannavisitcountrylist: + startProvider.startData.wannavisitcountrylist, interestlist: startProvider.startData.interestlist, image1url: startProvider.startData.image1url, image2url: startProvider.startData.image2url, aboutme: value, + instagram: startProvider.startData.instagram, + tiktok: startProvider.startData.tiktok, qalist: startProvider.startData.qalist, moneynumber: startProvider.startData.moneynumber, citybeachnumber: startProvider.startData.citybeachnumber, diff --git a/lib/Screens/Profilscreen/Slider/citybeachslider.dart b/lib/Screens/Profilscreen/Slider/citybeachslider.dart index 31aeea3..660e25b 100644 --- a/lib/Screens/Profilscreen/Slider/citybeachslider.dart +++ b/lib/Screens/Profilscreen/Slider/citybeachslider.dart @@ -43,7 +43,7 @@ class _CityBeachSliderContainerState extends State { children: [ const Text( ' 🏙️', - style: TextStyle(fontSize: 40), + style: TextStyle(fontSize: 35), ), Expanded( child: Slider( @@ -63,11 +63,16 @@ class _CityBeachSliderContainerState extends State { birthdate: startProvider.startData.birthdate, gender: startProvider.startData.gender, mainimageurl: startProvider.startData.mainimageurl, - countrylist: startProvider.startData.countrylist, + visitedcountrylist: + startProvider.startData.visitedcountrylist, + wannavisitcountrylist: + startProvider.startData.wannavisitcountrylist, interestlist: startProvider.startData.interestlist, image1url: startProvider.startData.image1url, image2url: startProvider.startData.image2url, aboutme: startProvider.startData.aboutme, + instagram: startProvider.startData.instagram, + tiktok: startProvider.startData.tiktok, qalist: startProvider.startData.qalist, moneynumber: startProvider.startData.moneynumber, citybeachnumber: newValue, @@ -82,7 +87,7 @@ class _CityBeachSliderContainerState extends State { ), const Text( '🏖️ ', - style: TextStyle(fontSize: 40), + style: TextStyle(fontSize: 35), ), ], ), diff --git a/lib/Screens/Profilscreen/Slider/moneyslider.dart b/lib/Screens/Profilscreen/Slider/moneyslider.dart index 680ab57..2f0f38d 100644 --- a/lib/Screens/Profilscreen/Slider/moneyslider.dart +++ b/lib/Screens/Profilscreen/Slider/moneyslider.dart @@ -43,7 +43,7 @@ class _MoneySliderContainerState extends State { children: [ const Text( ' 💵', - style: TextStyle(fontSize: 40), + style: TextStyle(fontSize: 35), ), Expanded( child: Slider( @@ -63,11 +63,16 @@ class _MoneySliderContainerState extends State { birthdate: startProvider.startData.birthdate, gender: startProvider.startData.gender, mainimageurl: startProvider.startData.mainimageurl, - countrylist: startProvider.startData.countrylist, + visitedcountrylist: + startProvider.startData.visitedcountrylist, + wannavisitcountrylist: + startProvider.startData.wannavisitcountrylist, interestlist: startProvider.startData.interestlist, image1url: startProvider.startData.image1url, image2url: startProvider.startData.image2url, aboutme: startProvider.startData.aboutme, + instagram: startProvider.startData.instagram, + tiktok: startProvider.startData.tiktok, qalist: startProvider.startData.qalist, moneynumber: newValue, citybeachnumber: startProvider.startData.citybeachnumber, @@ -82,7 +87,7 @@ class _MoneySliderContainerState extends State { ), const Text( '💰 ', - style: TextStyle(fontSize: 40), + style: TextStyle(fontSize: 35), ), ], ), diff --git a/lib/Screens/Profilscreen/Slider/relaxpartysilder.dart b/lib/Screens/Profilscreen/Slider/relaxpartysilder.dart index 85475f6..1c60dae 100644 --- a/lib/Screens/Profilscreen/Slider/relaxpartysilder.dart +++ b/lib/Screens/Profilscreen/Slider/relaxpartysilder.dart @@ -43,7 +43,7 @@ class _RelaxpartySliderContainerState extends State { children: [ const Text( ' 🧘', - style: TextStyle(fontSize: 40), + style: TextStyle(fontSize: 35), ), Expanded( child: Slider( @@ -63,11 +63,16 @@ class _RelaxpartySliderContainerState extends State { birthdate: startProvider.startData.birthdate, gender: startProvider.startData.gender, mainimageurl: startProvider.startData.mainimageurl, - countrylist: startProvider.startData.countrylist, + visitedcountrylist: + startProvider.startData.visitedcountrylist, + wannavisitcountrylist: + startProvider.startData.wannavisitcountrylist, interestlist: startProvider.startData.interestlist, image1url: startProvider.startData.image1url, image2url: startProvider.startData.image2url, aboutme: startProvider.startData.aboutme, + instagram: startProvider.startData.instagram, + tiktok: startProvider.startData.tiktok, qalist: startProvider.startData.qalist, moneynumber: startProvider.startData.moneynumber, citybeachnumber: startProvider.startData.citybeachnumber, @@ -82,7 +87,7 @@ class _RelaxpartySliderContainerState extends State { ), const Text( '🎉 ', - style: TextStyle(fontSize: 40), + style: TextStyle(fontSize: 35), ), ], ), diff --git a/lib/Screens/Profilscreen/choosemapscreen.dart b/lib/Screens/Profilscreen/choosemapscreen.dart index 2ba2217..5f71303 100644 --- a/lib/Screens/Profilscreen/choosemapscreen.dart +++ b/lib/Screens/Profilscreen/choosemapscreen.dart @@ -1,11 +1,15 @@ import 'package:app_prototyo/Klassen/allgemein.dart'; +import 'package:app_prototyo/Provider/user_provider.dart'; import 'package:app_prototyo/Screens/Profilscreen/search.dart'; import 'package:countries_world_map/countries_world_map.dart'; import 'package:countries_world_map/data/maps/world_map.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; //Länder können aus und abgewählt werden außerdem kann nach Ländern gesucht werden -List countryList = []; + +List visitedcountryList = []; +List wannavisitdcountryList = []; class ChooseMapScreen extends StatefulWidget { const ChooseMapScreen({Key? key}) : super(key: key); @@ -15,21 +19,121 @@ class ChooseMapScreen extends StatefulWidget { } class _ChooseMapScreenState extends State { - List countryList = []; - List selectedCountryNames = []; Map countryColors = {}; - // Methode, um die ausgewählten Ländernamen zu erhalten - void updateSelectedCountryNames() { - selectedCountryNames = countryList - .map((countryId) => - countries.firstWhere((country) => country.id == countryId).name) - .toList(); + @override + void initState() { + super.initState(); + updateCountryColors(); + } + + void updateCountryColors() { + setState(() { + countryColors.clear(); + for (var countryId in visitedcountryList) { + countryColors[countryId] = Colors.blue; + } + for (var countryId in wannavisitdcountryList) { + countryColors[countryId] = Colors.red; + } + }); + } + + void showCountrySelectionDialog(String countryId, StartProvider provider) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(countries + .firstWhere((country) => country.id == countryId) + .name), + IconButton( + icon: Icon(Icons.close), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ), + content: Container( + padding: EdgeInsets.symmetric(vertical: 10.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: Icon(Icons.flag, color: Colors.blue, size: 40), + onPressed: () { + setState(() { + if (!provider.startData.visitedcountrylist + .contains(countryId)) { + provider.updatePartialStartData( + visitedcountrylist: [ + ...provider.startData.visitedcountrylist, + countryId + ], + wannavisitcountrylist: provider + .startData.wannavisitcountrylist + .where((id) => id != countryId) + .toList(), + ); + } + updateCountryColors(); + }); + Navigator.of(context).pop(); + }, + ), + SizedBox(height: 5), + Text('Visited', style: TextStyle(color: Colors.blue)), + ], + ), + Column( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: Icon(Icons.restore, color: Colors.red, size: 40), + onPressed: () { + setState(() { + if (!provider.startData.wannavisitcountrylist + .contains(countryId)) { + provider.updatePartialStartData( + wannavisitcountrylist: [ + ...provider.startData.wannavisitcountrylist, + countryId + ], + visitedcountrylist: provider + .startData.visitedcountrylist + .where((id) => id != countryId) + .toList(), + ); + } + updateCountryColors(); + }); + Navigator.of(context).pop(); + }, + ), + SizedBox(height: 5), + Text('Want to visit', style: TextStyle(color: Colors.red)), + ], + ), + ], + ), + ), + ); + }, + ); } @override Widget build(BuildContext context) { - updateSelectedCountryNames(); // Aktualisiere die ausgewählten Ländernamen + final provider = Provider.of(context); + visitedcountryList = provider.startData.visitedcountrylist; + wannavisitdcountryList = provider.startData.wannavisitcountrylist; return Scaffold( appBar: AppBar( @@ -47,16 +151,7 @@ class _ChooseMapScreenState extends State { height: 80, child: Column( children: [ - CountrySearchBar( - countries: countries, - onCountrySelected: (String countryId) { - setState(() { - countryList.add(countryId); - countryColors[countryId] = Colors - .green; // Setze die Farbe des ausgewählten Landes auf grün - }); - }, - ), + // CountrySearchBar widget here (if any) ], ), ), @@ -65,96 +160,101 @@ class _ChooseMapScreenState extends State { child: InteractiveViewer( maxScale: 90, child: SimpleMap( - // String of instructions to draw the map. instructions: SMapWorld.instructions, - - // Default color for all countries. defaultColor: Colors.grey, - - // Farben der Länder basierend auf der ausgewählten Farbe - colors: countryList.fold>({}, - (Map colorMap, String id) { - colorMap[id] = Colors.blue; - return colorMap; - }), - - // Details of what area is being touched, giving you the ID, name and tapdetails + colors: countryColors, callback: (id, name, tapdetails) { setState(() { - if (countryList.contains(id)) { - countryList.remove( - id); // Entfernt das Land aus der Liste, wenn es bereits ausgewählt wurde - } else { - countryList.add( - id); // Fügt das Land zur Liste hinzu, wenn es noch nicht ausgewählt wurde - } - print(countryList); + showCountrySelectionDialog(id, provider); }); }, ), ), ), - SizedBox( - height: 8, - ), + SizedBox(height: 8), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon( - Icons.square, - color: Colors.blue, - ), + Icon(Icons.square, color: Colors.blue), Text('Visited'), - SizedBox( - width: 50, - ), - Icon( - Icons.square, - color: Colors.red, - ), - Text('Want to visit') + SizedBox(width: 50), + Icon(Icons.square, color: Colors.red), + Text('Want to visit'), ], ), - SizedBox( - height: 23, - ), + SizedBox(height: 23), Text( - // Zeige den Fortschritt als Text an - 'Visited Countries: ${countryList.length} of 194', + 'Visited Countries: ${visitedcountryList.length} of 194', style: TextStyle(fontSize: 16), ), Container( padding: EdgeInsets.only(left: 30, right: 30), child: LinearProgressIndicator( minHeight: 23, - backgroundColor: - Colors.grey[300], // Hintergrundfarbe der Fortschrittsleiste - valueColor: AlwaysStoppedAnimation( - Colors.blue), // Farbe der Fortschrittsleiste - value: countryList.length / - 194, // Der Fortschritt basierend auf der Anzahl der ausgewählten Länder + backgroundColor: Colors.grey[300], + valueColor: AlwaysStoppedAnimation(Colors.blue), + value: visitedcountryList.length / 194, ), ), - SizedBox( - height: 8, - ), + SizedBox(height: 20), Expanded( - child: Container( - margin: EdgeInsets.symmetric(horizontal: 0, vertical: 0), - padding: EdgeInsets.all(0), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), - ), - child: ListView.builder( - itemExtent: 30, // Festlegen der Höhe jedes Listenelements - itemCount: selectedCountryNames.length, - itemBuilder: (BuildContext context, int index) { - return ListTile( - title: Text(selectedCountryNames[index]), - leading: Icon(Icons.location_on), - ); - }, - ), + child: Row( + children: [ + Expanded( + child: Column( + children: [ + Text( + 'Visited Countries', + style: TextStyle( + fontSize: 18, fontWeight: FontWeight.bold), + ), + Expanded( + child: ListView.builder( + itemCount: visitedcountryList.length, + itemBuilder: (BuildContext context, int index) { + String countryId = visitedcountryList[index]; + String countryName = countries + .firstWhere( + (country) => country.id == countryId) + .name; + return ListTile( + title: Text(countryName), + leading: Icon(Icons.location_on), + ); + }, + ), + ), + ], + ), + ), + Expanded( + child: Column( + children: [ + Text( + 'Want to Visit', + style: TextStyle( + fontSize: 18, fontWeight: FontWeight.bold), + ), + Expanded( + child: ListView.builder( + itemCount: wannavisitdcountryList.length, + itemBuilder: (BuildContext context, int index) { + String countryId = wannavisitdcountryList[index]; + String countryName = countries + .firstWhere( + (country) => country.id == countryId) + .name; + return ListTile( + title: Text(countryName), + leading: Icon(Icons.location_on), + ); + }, + ), + ), + ], + ), + ), + ], ), ), ], diff --git a/lib/Screens/Profilscreen/editprofil.dart b/lib/Screens/Profilscreen/editprofil.dart index 0cddd6c..3737226 100644 --- a/lib/Screens/Profilscreen/editprofil.dart +++ b/lib/Screens/Profilscreen/editprofil.dart @@ -3,11 +3,11 @@ import 'dart:io'; import 'package:app_prototyo/Provider/user_provider.dart'; import 'package:app_prototyo/Screens/Profilscreen/Komponenten/aboutme.dart'; import 'package:app_prototyo/Screens/Profilscreen/Slider/citybeachslider.dart'; +import 'package:app_prototyo/Screens/Profilscreen/Slider/moneyslider.dart'; import 'package:app_prototyo/Screens/Profilscreen/Slider/relaxpartysilder.dart'; import 'package:app_prototyo/Screens/Profilscreen/interestprofilscreen.dart'; import 'package:app_prototyo/Screens/Profilscreen/language.dart'; import 'package:app_prototyo/Screens/Profilscreen/choosemapscreen.dart'; -import 'package:app_prototyo/Screens/Profilscreen/Slider/moneyslider.dart'; import 'package:app_prototyo/Screens/Profilscreen/question_popup.dart'; import 'package:app_prototyo/Screens/Profilscreen/sleppingplaces.dart'; import 'package:app_prototyo/Screens/Profilscreen/transporttype.dart'; @@ -18,6 +18,7 @@ import 'package:countries_world_map/data/maps/world_map.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:provider/provider.dart'; //Hier passt man sein Profil an @@ -110,11 +111,16 @@ class _EditProfilScreenState extends State with RouteAware { birthdate: startProvider.startData.birthdate, gender: startProvider.startData.gender, mainimageurl: mainimageUrl, - countrylist: startProvider.startData.countrylist, + visitedcountrylist: + startProvider.startData.visitedcountrylist, + wannavisitcountrylist: + startProvider.startData.wannavisitcountrylist, interestlist: startProvider.startData.interestlist, image1url: startProvider.startData.image1url, image2url: startProvider.startData.image2url, aboutme: startProvider.startData.aboutme, + instagram: startProvider.startData.instagram, + tiktok: startProvider.startData.tiktok, qalist: startProvider.startData.qalist, moneynumber: startProvider.startData.moneynumber, citybeachnumber: @@ -143,6 +149,7 @@ class _EditProfilScreenState extends State with RouteAware { await uploadImageToFirebaseStorage( profilImageFile1); final startProvider = Provider.of( + // ignore: use_build_context_synchronously context, listen: false); startProvider.updateStartData(StartData( @@ -151,12 +158,17 @@ class _EditProfilScreenState extends State with RouteAware { birthdate: startProvider.startData.birthdate, gender: startProvider.startData.gender, mainimageurl: startProvider.startData.mainimageurl, - countrylist: startProvider.startData.countrylist, + visitedcountrylist: + startProvider.startData.visitedcountrylist, + wannavisitcountrylist: + startProvider.startData.wannavisitcountrylist, interestlist: startProvider.startData.interestlist, // Aktualisiere die Liste der ausgewählten Interessen image1url: profilImage1Url, image2url: startProvider.startData.image2url, aboutme: startProvider.startData.aboutme, + instagram: startProvider.startData.instagram, + tiktok: startProvider.startData.tiktok, qalist: startProvider.startData.qalist, moneynumber: startProvider.startData.moneynumber, citybeachnumber: @@ -190,12 +202,17 @@ class _EditProfilScreenState extends State with RouteAware { birthdate: startProvider.startData.birthdate, gender: startProvider.startData.gender, mainimageurl: startProvider.startData.mainimageurl, - countrylist: startProvider.startData.countrylist, + visitedcountrylist: + startProvider.startData.visitedcountrylist, + wannavisitcountrylist: + startProvider.startData.wannavisitcountrylist, interestlist: startProvider.startData.interestlist, // Aktualisiere die Liste der ausgewählten Interessen image1url: startProvider.startData.image1url, image2url: profilImage2Url, aboutme: startProvider.startData.aboutme, + instagram: startProvider.startData.instagram, + tiktok: startProvider.startData.tiktok, qalist: startProvider.startData.qalist, moneynumber: startProvider.startData.moneynumber, citybeachnumber: @@ -214,28 +231,26 @@ class _EditProfilScreenState extends State with RouteAware { ) ], ), - const SizedBox( - height: 6, - ), const SizedBox(height: 20), const Text( 'About me', - style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), AboutmeContainer(), + const SizedBox(height: 20), const Text( 'Questions', - style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), GestureDetector( onTap: () { Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const Questionscreen())); + context, + MaterialPageRoute( + builder: (context) => const Questionscreen()), + ); }, child: Container( - height: 46, decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(8)), border: Border.all( @@ -244,18 +259,71 @@ class _EditProfilScreenState extends State with RouteAware { width: 0.10, // Dicke der gestrichelten Linie ), ), - child: const Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - ' Add question', - style: TextStyle(fontSize: 15), - ), - Icon( - Icons.add, - size: 30, - ) - ]), + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Provider.of(context, listen: false) + .startData + .qalist + .isEmpty + ? Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: const [ + Text( + ' Add question', + style: TextStyle(fontSize: 15), + ), + Icon( + Icons.add, + size: 30, + ) + ], + ) + : Wrap( + spacing: 8.0, + runSpacing: 8.0, + children: Provider.of(context, + listen: false) + .startData + .qalist + .map((qa) { + return Chip( + side: BorderSide( + color: Colors.white, + ), + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(20.0)), + backgroundColor: + Color.fromARGB(255, 224, 226, 228), + label: Text( + qa, + style: const TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + maxLines: 10, + softWrap: true, + overflow: TextOverflow.visible, + ), + ); + }).toList(), + ), + ), + Provider.of(context, listen: false) + .startData + .qalist + .isEmpty + ? const SizedBox() // Leerer Container, um Platz zu sparen, wenn keine Sprache ausgewählt ist + : Icon( + Icons.keyboard_arrow_right, + size: 30, + ) + ], + ), ), ), const SizedBox( @@ -263,35 +331,53 @@ class _EditProfilScreenState extends State with RouteAware { ), const Text( 'WorldMap', - style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), - ), - const SizedBox( - height: 10, + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), SimpleMap( instructions: SMapWorld.instructions, defaultColor: const Color.fromRGBO(158, 158, 158, 1), - colors: countryList.fold>({}, (colorMap, id) { - colorMap[id] = Colors - .blue; // Weise jedem Land in der Liste die Farbe Grün zu - return colorMap; - }), + colors: { + ...visitedcountryList.fold>({}, + (colorMap, id) { + colorMap[id] = Colors + .blue; // Weise jedem Land in der Liste die Farbe Blau zu + return colorMap; + }), + ...wannavisitdcountryList.fold>({}, + (colorMap, id) { + colorMap[id] = Colors + .red; // Weise jedem Land in der Liste die Farbe Rot zu + return colorMap; + }), + }, callback: (id, name, tapdetails) { Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const ChooseMapScreen())); + context, + MaterialPageRoute( + builder: (context) => const ChooseMapScreen(), + ), + ); }, ), + const SizedBox( + height: 10, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.square, color: Colors.blue), + Text('Visited'), + SizedBox(width: 50), + Icon(Icons.square, color: Colors.red), + Text('Want to visit'), + ], + ), const SizedBox( height: 20, ), const Text( 'My interests', - style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), - ), - const SizedBox( - height: 6, + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), GestureDetector( onTap: () { @@ -358,14 +444,11 @@ class _EditProfilScreenState extends State with RouteAware { ), ), const SizedBox( - height: 10, + height: 20, ), const Text( 'My Languages', - style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), - ), - const SizedBox( - height: 6, + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), GestureDetector( onTap: () { @@ -449,17 +532,17 @@ class _EditProfilScreenState extends State with RouteAware { ), ), const SizedBox( - height: 10, + height: 20, ), const Text( 'On Travel', - style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), MoneySliderContainer(), CityBeachSliderContainer(), RelaxpartySliderContainer(), const SizedBox( - height: 12, + height: 20, ), const Text( 'Transport', @@ -467,13 +550,146 @@ class _EditProfilScreenState extends State with RouteAware { ), const TransportTypesGrid(), const SizedBox( - height: 8, + height: 20, ), const Text( 'Sleepingplace', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), - SleepingPlacesTypesGrid() + SleepingPlacesTypesGrid(), + const SizedBox( + height: 20, + ), + const Text( + 'Social Media', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + SizedBox( + height: 5, + ), + Row( + children: [ + Icon( + FontAwesomeIcons.instagram, + size: 40, + ), + SizedBox(width: 10), // Abstand zwischen Icon und TextField + Expanded( + child: Container( + height: + 40, // Hier kannst du die Höhe des Textfelds anpassen + child: TextField( + maxLines: 1, + decoration: const InputDecoration( + contentPadding: EdgeInsets.symmetric( + horizontal: + 10), // Optional: Padding innerhalb des Textfelds anpassen + border: OutlineInputBorder( + borderSide: BorderSide(color: Colors.black), + ), + ), + onChanged: (value) { + final startProvider = + Provider.of(context, listen: false); + + // Startdaten aktualisieren, um die neue Hauptbild-URL einzubeziehen + startProvider.updateStartData(StartData( + name: startProvider.startData.name, + birthdate: startProvider.startData.birthdate, + gender: startProvider.startData.gender, + mainimageurl: startProvider.startData.mainimageurl, + visitedcountrylist: + startProvider.startData.visitedcountrylist, + wannavisitcountrylist: + startProvider.startData.wannavisitcountrylist, + interestlist: startProvider.startData.interestlist, + image1url: startProvider.startData.image1url, + image2url: startProvider.startData.image2url, + aboutme: startProvider.startData.aboutme, + instagram: value, + tiktok: startProvider.startData.tiktok, + qalist: startProvider.startData.qalist, + moneynumber: startProvider.startData.moneynumber, + citybeachnumber: + startProvider.startData.citybeachnumber, + relaxpartynumber: + startProvider.startData.relaxpartynumber, + languagelist: startProvider.startData.languagelist, + transportlist: startProvider.startData.transportlist, + sleepingplacelist: + startProvider.startData.sleepingplacelist, + globynomad: startProvider.startData.globynomad, + )); + }, + ), + ), + ), + ], + ), + SizedBox( + height: 10, + ), + Row( + children: [ + Icon( + FontAwesomeIcons.tiktok, + size: 40, + ), + SizedBox(width: 10), // Abstand zwischen Icon und TextField + Expanded( + child: Container( + height: + 40, // Hier kannst du die Höhe des Textfelds anpassen + child: TextField( + decoration: const InputDecoration( + contentPadding: EdgeInsets.symmetric( + horizontal: + 10), // Optional: Padding innerhalb des Textfelds anpassen + border: OutlineInputBorder( + borderSide: BorderSide(color: Colors.black), + ), + ), + onChanged: (value) { + final startProvider = + Provider.of(context, listen: false); + + // Startdaten aktualisieren, um die neue Hauptbild-URL einzubeziehen + startProvider.updateStartData(StartData( + name: startProvider.startData.name, + birthdate: startProvider.startData.birthdate, + gender: startProvider.startData.gender, + mainimageurl: startProvider.startData.mainimageurl, + visitedcountrylist: + startProvider.startData.visitedcountrylist, + wannavisitcountrylist: + startProvider.startData.wannavisitcountrylist, + interestlist: startProvider.startData.interestlist, + image1url: startProvider.startData.image1url, + image2url: startProvider.startData.image2url, + aboutme: startProvider.startData.aboutme, + instagram: startProvider.startData.instagram, + tiktok: value, + qalist: startProvider.startData.qalist, + moneynumber: startProvider.startData.moneynumber, + citybeachnumber: + startProvider.startData.citybeachnumber, + relaxpartynumber: + startProvider.startData.relaxpartynumber, + languagelist: startProvider.startData.languagelist, + transportlist: startProvider.startData.transportlist, + sleepingplacelist: + startProvider.startData.sleepingplacelist, + globynomad: startProvider.startData.globynomad, + )); + }, + ), + ), + ), + SizedBox( + height: 50, + ) + ], + ), ]), ))); } @@ -499,9 +715,13 @@ void updateDocument(BuildContext context) async { 'mainimage': startProvider.startData.mainimageurl, 'image1': startProvider.startData.image1url, 'image2': startProvider.startData.image2url, - 'list of countries': startProvider.startData.countrylist, + 'list of visitedcountries': startProvider.startData.visitedcountrylist, + 'list of wannavisitcountries': + startProvider.startData.wannavisitcountrylist, 'list of interest': startProvider.startData.interestlist, 'Aboutme': startProvider.startData.aboutme, + 'instagram': startProvider.startData.instagram, + 'tiktok': startProvider.startData.tiktok, 'List Question + Answer': startProvider.startData.qalist, 'List Language': startProvider.startData.languagelist, 'MoneyNumber': startProvider.startData.moneynumber, diff --git a/lib/Screens/Profilscreen/interestprofilscreen.dart b/lib/Screens/Profilscreen/interestprofilscreen.dart index 387aeac..b36ace8 100644 --- a/lib/Screens/Profilscreen/interestprofilscreen.dart +++ b/lib/Screens/Profilscreen/interestprofilscreen.dart @@ -93,12 +93,16 @@ class _InterestProfilScreenState extends State { birthdate: startProvider.startData.birthdate, gender: startProvider.startData.gender, mainimageurl: startProvider.startData.mainimageurl, - countrylist: startProvider.startData.countrylist, + visitedcountrylist: startProvider.startData.visitedcountrylist, + wannavisitcountrylist: + startProvider.startData.wannavisitcountrylist, interestlist: selectedInterests, // Aktualisiere die Liste der ausgewählten Interessen image1url: startProvider.startData.image1url, image2url: startProvider.startData.image2url, aboutme: startProvider.startData.aboutme, + instagram: startProvider.startData.instagram, + tiktok: startProvider.startData.tiktok, qalist: startProvider.startData.qalist, moneynumber: startProvider.startData.moneynumber, citybeachnumber: startProvider.startData.citybeachnumber, diff --git a/lib/Screens/Profilscreen/language.dart b/lib/Screens/Profilscreen/language.dart index dd8c327..0082294 100644 --- a/lib/Screens/Profilscreen/language.dart +++ b/lib/Screens/Profilscreen/language.dart @@ -112,11 +112,15 @@ class _LanguageScreenState extends State { birthdate: startProvider.startData.birthdate, gender: startProvider.startData.gender, mainimageurl: startProvider.startData.mainimageurl, - countrylist: startProvider.startData.countrylist, + visitedcountrylist: startProvider.startData.visitedcountrylist, + wannavisitcountrylist: + startProvider.startData.wannavisitcountrylist, interestlist: startProvider.startData.interestlist, image1url: startProvider.startData.image1url, image2url: startProvider.startData.image2url, aboutme: startProvider.startData.aboutme, + instagram: startProvider.startData.instagram, + tiktok: startProvider.startData.tiktok, qalist: startProvider.startData.qalist, moneynumber: startProvider.startData.moneynumber, citybeachnumber: startProvider.startData.citybeachnumber, diff --git a/lib/Screens/Profilscreen/profilscreen.dart b/lib/Screens/Profilscreen/profilscreen.dart index 99aaf7e..b8d1840 100644 --- a/lib/Screens/Profilscreen/profilscreen.dart +++ b/lib/Screens/Profilscreen/profilscreen.dart @@ -1,7 +1,9 @@ import 'package:app_prototyo/Provider/user_provider.dart'; +import 'package:app_prototyo/Screens/Findscreen/SeeUser/age_calculator.dart'; import 'package:app_prototyo/Screens/Profilscreen/editprofil.dart'; import 'package:app_prototyo/Screens/Settingsscreens/settingsscreenSimon.dart'; import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; //Prfilscreen über den man zu den Einstellung, UsereditScreen und zum GlobyNomad Screen kommt @@ -19,23 +21,37 @@ class ProfilScreen extends StatefulWidget { } class ProfilScreenState extends State { - //num calculateAgeFromBirthDate(BuildContext context) { - // final startProvider = Provider.of(context, listen: false); - //final birthDate = startProvider.startData.birthdate; + int calculateAgeFromBirthDate(BuildContext context) { + final startProvider = Provider.of(context, listen: false); + final birthDateString = startProvider + .startData.birthdate; // Assuming birthdate is stored as a String - //final now = DateTime.now(); - //var age = now.year - birthDate.year; - //if (now.month < birthDate.month || - // (now.month == birthDate.month && now.day < birthDate.day)) { - //age--; - //} - // return age; - // } + if (birthDateString == null || birthDateString.isEmpty) { + // Handle the case where the birthdate is not set or is empty + return 0; // Or any default value you consider appropriate + } + + try { + final birthDate = DateFormat('dd/MM/yyyy').parse(birthDateString); + final now = DateTime.now(); + var age = now.year - birthDate.year; + if (now.month < birthDate.month || + (now.month == birthDate.month && now.day < birthDate.day)) { + age--; + } + return age; + } catch (e) { + // Handle parsing errors + print('Error parsing birthdate: $e'); + return 0; // Or any default value you consider appropriate + } + } @override Widget build(BuildContext context) { final startProvider = Provider.of(context); final name = startProvider.startData.name; + final age = calculateAgeFromBirthDate(context); double screenHeight = MediaQuery.of(context).size.height; return Scaffold( @@ -48,6 +64,7 @@ class ProfilScreenState extends State { icon: const Icon( Icons.settings, color: Colors.grey, + size: 30, ), onPressed: () { Navigator.push( @@ -145,8 +162,8 @@ class ProfilScreenState extends State { style: TextStyle(fontSize: 23), ), Text( - '20', - style: TextStyle(fontSize: 23), + '$age', + style: const TextStyle(fontSize: 23), ), ], ), @@ -202,7 +219,32 @@ class ProfilScreenState extends State { height: 25, ), TextButton( - onPressed: () {}, + onPressed: () { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('Coming soon!!!'), + ], + ), + actions: [ + TextButton( + child: Text( + 'OK', + style: TextStyle(color: Colors.grey), + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); + }, style: ButtonStyle( backgroundColor: MaterialStateProperty.all(Colors.white), diff --git a/lib/Screens/Profilscreen/question_popup.dart b/lib/Screens/Profilscreen/question_popup.dart index a553f8b..b7f7e93 100644 --- a/lib/Screens/Profilscreen/question_popup.dart +++ b/lib/Screens/Profilscreen/question_popup.dart @@ -1,9 +1,13 @@ +import 'package:app_prototyo/Provider/user_provider.dart'; import 'package:flutter/material.dart'; import 'package:app_prototyo/Klassen/allgemein.dart'; //Damit werden die Fragen aufgerufen damit man einen Text eingeben kann um sie zu beantworten +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + class Questionscreen extends StatefulWidget { const Questionscreen({super.key}); @@ -14,88 +18,91 @@ class Questionscreen extends StatefulWidget { class _QuestionscreenState extends State { List fragen = Question.getQuestion(); int answeredQuestions = 0; - List> answers = []; + List> answers = []; void saveAnswer(String answer, int index) { - // Hier können Sie die Antwort speichern - print('Antwort gespeichert: $answer'); - setState(() { + answers.add({ + 'question': + fragen[index].text.trimRight().replaceAll(RegExp(r'\.{3}$'), ''), + 'answer': answer + }); fragen.removeAt(index); answeredQuestions++; - answers.add({'question': fragen[index].text, 'answer': answer}); - // Wenn drei Fragen beantwortet wurden, navigiere zurück if (answeredQuestions == 3) { - Navigator.pop(context, answers); + // Convert the answers to a List + List qalist = answers + .map((entry) => '${entry['question']} ${entry['answer']}') + .toList(); + Provider.of(context, listen: false) + .updatePartialStartData(qalist: qalist); + Navigator.pop(context); } }); } @override Widget build(BuildContext context) { - return MaterialApp( - home: Scaffold( - appBar: AppBar( - leading: IconButton( - icon: const Icon(Icons.arrow_back), - onPressed: () { - Navigator.pop(context); - }, - ), + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () { + Navigator.pop(context); + }, ), - body: Column( - children: [ - const Text( - 'Choose 3 Question to answer...', - style: TextStyle(fontSize: 20), - ), - Expanded( - child: ListView.builder( - itemCount: fragen.length, - itemBuilder: (context, index) { - return Padding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 16.0, - ), - child: TextButton( - style: ButtonStyle( - shape: MaterialStateProperty.all( - const RoundedRectangleBorder( - side: BorderSide( - color: Colors.black, - width: 1, - ), - borderRadius: BorderRadius.zero, + ), + body: Column( + children: [ + const Text( + 'Choose 3 Questions to answer...', + style: TextStyle(fontSize: 20), + ), + Expanded( + child: ListView.builder( + itemCount: fragen.length, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.symmetric( + vertical: 8.0, + horizontal: 16.0, + ), + child: TextButton( + style: ButtonStyle( + shape: MaterialStateProperty.all( + const RoundedRectangleBorder( + side: BorderSide( + color: Colors.black, + width: 1, ), + borderRadius: BorderRadius.zero, ), ), - onPressed: () { - if (answeredQuestions < 3) { - showEingabePopup(context, fragen[index].text, - (answer) { - saveAnswer(answer, index); - }); - } else { - Navigator.pop(context); - } - }, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - fragen[index].text, - style: const TextStyle( - color: Colors.black, fontSize: 15), - ), + ), + onPressed: () { + if (answeredQuestions < 3) { + showEingabePopup(context, fragen[index].text, (answer) { + saveAnswer(answer, index); + }); + } else { + Navigator.pop(context); + } + }, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + fragen[index].text, + style: + const TextStyle(color: Colors.black, fontSize: 15), ), ), - ); - }, - ), + ), + ); + }, ), - ], - ), + ), + ], ), ); } @@ -144,7 +151,7 @@ class _EingabePopupState extends State { actions: [ TextButton( onPressed: () { - Navigator.of(context).pop(); // Schließen Sie das Popup-Fenster + Navigator.of(context).pop(); }, child: const Icon( Icons.close, @@ -155,7 +162,7 @@ class _EingabePopupState extends State { onPressed: () { String answer = _textEditingController.text; widget.onSave(answer); - Navigator.of(context).pop(); // Schließen Sie das Popup-Fenster + Navigator.of(context).pop(); }, child: const Icon( Icons.check, diff --git a/lib/Screens/Profilscreen/sleppingplaces.dart b/lib/Screens/Profilscreen/sleppingplaces.dart index 35963d9..9399849 100644 --- a/lib/Screens/Profilscreen/sleppingplaces.dart +++ b/lib/Screens/Profilscreen/sleppingplaces.dart @@ -73,11 +73,15 @@ class _SleepingPlacesTypesGridState extends State { birthdate: startProvider.startData.birthdate, gender: startProvider.startData.gender, mainimageurl: startProvider.startData.mainimageurl, - countrylist: startProvider.startData.countrylist, + visitedcountrylist: startProvider.startData.visitedcountrylist, + wannavisitcountrylist: + startProvider.startData.wannavisitcountrylist, interestlist: startProvider.startData.interestlist, image1url: startProvider.startData.image1url, image2url: startProvider.startData.image2url, aboutme: startProvider.startData.aboutme, + instagram: startProvider.startData.instagram, + tiktok: startProvider.startData.tiktok, qalist: startProvider.startData.qalist, moneynumber: startProvider.startData.moneynumber, citybeachnumber: startProvider.startData.citybeachnumber, @@ -106,20 +110,20 @@ class _SleepingPlacesTypesGridState extends State { Widget _buildButtonContent(Sleepingplace sleepingplace) { return SizedBox( - height: 100, - width: 100, + height: 84, + width: 84, child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( sleepingplace.emoji, - style: const TextStyle(fontSize: 45.0, fontWeight: FontWeight.bold), + style: const TextStyle(fontSize: 38.0, fontWeight: FontWeight.bold), ), const SizedBox(width: 5), Text( sleepingplace.name, style: const TextStyle( - fontSize: 20.0, + fontSize: 18.0, color: Colors.black, ), overflow: TextOverflow.ellipsis, diff --git a/lib/Screens/Profilscreen/transporttype.dart b/lib/Screens/Profilscreen/transporttype.dart index 49d99cc..402538a 100644 --- a/lib/Screens/Profilscreen/transporttype.dart +++ b/lib/Screens/Profilscreen/transporttype.dart @@ -72,11 +72,15 @@ class _TransportTypesGridState extends State { birthdate: startProvider.startData.birthdate, gender: startProvider.startData.gender, mainimageurl: startProvider.startData.mainimageurl, - countrylist: startProvider.startData.countrylist, + visitedcountrylist: startProvider.startData.visitedcountrylist, + wannavisitcountrylist: + startProvider.startData.wannavisitcountrylist, interestlist: startProvider.startData.interestlist, image1url: startProvider.startData.image1url, image2url: startProvider.startData.image2url, aboutme: startProvider.startData.aboutme, + instagram: startProvider.startData.instagram, + tiktok: startProvider.startData.tiktok, qalist: startProvider.startData.qalist, moneynumber: startProvider.startData.moneynumber, citybeachnumber: startProvider.startData.citybeachnumber, @@ -105,20 +109,20 @@ class _TransportTypesGridState extends State { Widget _buildButtonContent(Transporttype transporttype) { return SizedBox( - height: 100, - width: 100, + height: 84, + width: 84, child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( transporttype.emoji, - style: const TextStyle(fontSize: 45.0, fontWeight: FontWeight.bold), + style: const TextStyle(fontSize: 38.0, fontWeight: FontWeight.bold), ), const SizedBox(width: 5), Text( transporttype.name, style: const TextStyle( - fontSize: 20.0, + fontSize: 18.0, color: Colors.black, ), overflow: TextOverflow.ellipsis, diff --git a/lib/Screens/Settingsscreens/Settings_SWSR/emailreset.dart b/lib/Screens/Settingsscreens/Settings_SWSR/emailreset.dart index 2b37f94..64eb44b 100644 --- a/lib/Screens/Settingsscreens/Settings_SWSR/emailreset.dart +++ b/lib/Screens/Settingsscreens/Settings_SWSR/emailreset.dart @@ -6,6 +6,8 @@ class EmailResetSheet { TextEditingController(); static void emailBottomSheet(BuildContext context) { + User? user = FirebaseAuth.instance.currentUser; + showModalBottomSheet( context: context, isScrollControlled: true, @@ -25,7 +27,17 @@ class EmailResetSheet { crossAxisAlignment: CrossAxisAlignment.center, children: [ AppBar( - title: const Text('Reset Email'), + title: CircleAvatar( + radius: 25, // Der Radius des Kreises + backgroundColor: Color.fromRGBO( + 75, 173, 193, 1), // Die Hintergrundfarbe des Kreises + child: const Icon( + Icons.mail, + size: 30, // Die Größe des Icons innerhalb des Kreises + color: Color.fromARGB( + 255, 82, 82, 82), // Die Farbe des Icons + ), + ), backgroundColor: Colors.transparent, elevation: 0, automaticallyImplyLeading: false, @@ -38,9 +50,18 @@ class EmailResetSheet { ), ], ), + SizedBox(height: 15), + if (user != null) + Text( + 'Your Mail Address: ${user.email ?? 'No Email'}', + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), const SizedBox(height: 16), const Text( - 'Please enter the new email-adress in the textfield', + 'Please enter the new email address in the textfield', style: TextStyle( fontSize: 15, fontWeight: FontWeight.bold, @@ -62,7 +83,7 @@ class EmailResetSheet { ), fillColor: Color.fromARGB(213, 225, 231, 233), filled: true, - hintText: 'New E-Mail-adresss', + hintText: 'New E-Mail address', hintStyle: TextStyle( color: Color.fromARGB(255, 55, 55, 55), ), @@ -85,7 +106,7 @@ class EmailResetSheet { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( - 'We send the confirmation-link to your new adress'), + 'We sent the confirmation link to your new address'), ), ); diff --git a/lib/Screens/Settingsscreens/Settings_SWSR/passwordreset.dart b/lib/Screens/Settingsscreens/Settings_SWSR/passwordreset.dart index 8236055..643b2f4 100644 --- a/lib/Screens/Settingsscreens/Settings_SWSR/passwordreset.dart +++ b/lib/Screens/Settingsscreens/Settings_SWSR/passwordreset.dart @@ -1,6 +1,9 @@ import 'package:flutter/material.dart'; import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:firebase_auth/firebase_auth.dart'; + class PasswordResetSheet { static final TextEditingController _emailController = TextEditingController(); @@ -8,102 +11,103 @@ class PasswordResetSheet { showModalBottomSheet( context: context, isScrollControlled: true, - backgroundColor: const Color.fromARGB(0, 0, 0, 0), + backgroundColor: Colors.transparent, builder: (BuildContext context) { - return Stack( - children: [ - GestureDetector( - onTap: () { - Navigator.pop(context); - }, - child: Container( - color: Colors.black.withOpacity(0.2), + return DraggableScrollableSheet( + expand: false, + builder: (context, scrollController) { + return Container( + padding: const EdgeInsets.all(16), + height: MediaQuery.of(context).size.height * 0.4, + decoration: const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.vertical(top: Radius.circular(16.0)), ), - ), - Positioned( - bottom: 0, - left: 0, - right: 0, - child: Container( - height: MediaQuery.of(context).size.height * 0.4, - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: - BorderRadius.vertical(top: Radius.circular(16.0)), - ), - child: Column( - children: [ - AppBar( - title: const Text('Reset Password'), - backgroundColor: Colors.transparent, - elevation: 0, - automaticallyImplyLeading: false, - actions: [ - IconButton( - icon: const Icon(Icons.close), - onPressed: () { - Navigator.pop(context); - }, - ), - ], + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + AppBar( + title: CircleAvatar( + radius: 25, // Der Radius des Kreises + backgroundColor: Color.fromRGBO( + 75, 173, 193, 1), // Die Hintergrundfarbe des Kreises + child: const Icon( + Icons.lock, + size: 30, // Die Größe des Icons innerhalb des Kreises + color: Color.fromARGB( + 255, 82, 82, 82), // Die Farbe des Icons + ), ), - Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - 'Enter your Email and we will send you a password reset link', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - ), + backgroundColor: Colors.transparent, + elevation: 0, + automaticallyImplyLeading: false, + actions: [ + IconButton( + icon: const Icon(Icons.close), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ), + Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + 'Enter your Email and we will send you a password reset link', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, ), - const SizedBox(height: 30), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 30), - child: TextField( - controller: _emailController, - decoration: InputDecoration( - enabledBorder: const OutlineInputBorder( - borderSide: BorderSide( - color: Color.fromRGBO(54, 54, 54, 0.57)), + ), + const SizedBox(height: 30), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: TextField( + controller: _emailController, + decoration: InputDecoration( + enabledBorder: const OutlineInputBorder( + borderSide: BorderSide( + color: Color.fromRGBO(54, 54, 54, 0.57), ), - focusedBorder: const OutlineInputBorder( - borderSide: BorderSide( - color: Color.fromARGB(255, 41, 51, 76)), + ), + focusedBorder: const OutlineInputBorder( + borderSide: BorderSide( + color: Color.fromARGB(255, 41, 51, 76), ), - fillColor: - const Color.fromARGB(213, 225, 231, 233), - filled: true, - hintText: 'Email', - hintStyle: TextStyle(color: Colors.grey[600]), ), + fillColor: + const Color.fromARGB(213, 225, 231, 233), + filled: true, + hintText: 'Email', + hintStyle: TextStyle(color: Colors.grey[600]), ), ), - const SizedBox(height: 30), - ElevatedButton( - onPressed: () => _passwordReset(context), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.grey, - ), - child: const Text( - 'Send Email', - style: TextStyle( - fontWeight: FontWeight.bold, - color: Colors.black, - ), + ), + const SizedBox(height: 30), + ElevatedButton( + onPressed: () => _passwordReset(context), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.grey, + ), + child: const Text( + 'Send Email', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black, ), ), - ], - ), + ), + ], ), - ], - ), + ), + ], ), - ), - ], + ); + }, ); }, ); diff --git a/lib/Screens/Settingsscreens/communityguidelines.dart b/lib/Screens/Settingsscreens/communityguidelines.dart new file mode 100644 index 0000000..e86320e --- /dev/null +++ b/lib/Screens/Settingsscreens/communityguidelines.dart @@ -0,0 +1,115 @@ +import 'package:flutter/material.dart'; + +// Grundlegende Seite auf der Find, Chat und User Screen liegen + +import 'package:flutter/material.dart'; + +class CommunityGuidelineScreen extends StatefulWidget { + const CommunityGuidelineScreen({Key? key}) : super(key: key); + + @override + State createState() { + return _CommunityGuidelineScreenState(); + } +} + +class _CommunityGuidelineScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + centerTitle: true, + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () { + Navigator.pop(context); + }, + ), + ), + body: SingleChildScrollView( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Globy is more than just an app; it’s a lifestyle and a worldwide community. You can connect with other travelers and locals alike. Explore new places with travelers from around the world or show visitors your hometown. As a community, we have rules to follow:', + textAlign: TextAlign.justify, + style: TextStyle(fontSize: 15), + ), + const SizedBox(height: 16), + const Text( + 'Overall Community Guidelines:', + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + ), + const SizedBox(height: 8), + const Text( + "• Respect and Acceptance: We reject any form of hate or discrimination based on gender, race, religion, sexual orientation, appearance, nationality, or anything else. Traveling, meeting new people, and sharing experiences unite us. If you come across any hateful behavior, please report it promptly.", + textAlign: TextAlign.justify, + ), + const SizedBox(height: 8), + const Text( + '• Respect for the Rules in Other Countries: Different countries have different rules and customs. Respect other cultures and be open to new experiences.', + textAlign: TextAlign.justify, + ), + const SizedBox(height: 8), + const Text( + '• Respect for Nature: Respect the environment, be kind to animals, and leave your surroundings clean.', + textAlign: TextAlign.justify, + ), + const SizedBox(height: 16), + const Text( + 'In the App:', + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + ), + const SizedBox(height: 8), + const Text( + '• Protect Your Privacy: Never share your exact location or personal information meant only for you.', + textAlign: TextAlign.justify, + ), + const SizedBox(height: 8), + const Text( + '• Report Concerns: Inform us of any suspicious or harmful behavior that doesn’t align with our guidelines.', + textAlign: TextAlign.justify, + ), + const SizedBox(height: 8), + const Text( + '• Use Caution with Contact Info: Only share your phone number if you trust the person.', + textAlign: TextAlign.justify, + ), + const SizedBox(height: 8), + const Text( + '• Trust Your Instincts: If you feel uncomfortable about meeting someone, trust your gut and avoid the meeting.', + textAlign: TextAlign.justify, + ), + const SizedBox(height: 16), + const Text( + 'For Face-to-Face Meetings:', + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + ), + const SizedBox(height: 8), + const Text( + '• Choose Public Places: When meeting someone new, opt for public settings where others are around.', + textAlign: TextAlign.justify, + ), + const SizedBox(height: 8), + const Text( + '• Be Open About your Plans: Communicate your plans openly with someone you intend to meet.', + textAlign: TextAlign.justify, + ), + const SizedBox(height: 8), + const Text( + '• Build Trust: If planning a trip together, take time to get to know them better through phone calls or video chats first.', + textAlign: TextAlign.justify, + ), + const SizedBox(height: 16), + const Text( + 'These guidelines are here to ensure everyone’s safety, mutual respect, and enjoyable experiences within the Globy community. Happy travels!', + textAlign: TextAlign.justify, + style: TextStyle(fontSize: 15), + ), + ], + ), + ), + ); + } +} diff --git a/lib/Screens/Settingsscreens/settingsscreenSimon.dart b/lib/Screens/Settingsscreens/settingsscreenSimon.dart index 2ed967c..983178a 100644 --- a/lib/Screens/Settingsscreens/settingsscreenSimon.dart +++ b/lib/Screens/Settingsscreens/settingsscreenSimon.dart @@ -5,6 +5,7 @@ import 'package:app_prototyo/Screens/LogIn/login_or_register_page.dart'; import 'package:app_prototyo/Screens/Settingsscreens/Settings_SWSR/components/button.dart'; import 'package:app_prototyo/Screens/Settingsscreens/Settings_SWSR/emailreset.dart'; import 'package:app_prototyo/Screens/Settingsscreens/Settings_SWSR/passwordreset.dart'; +import 'package:app_prototyo/Screens/Settingsscreens/communityguidelines.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; @@ -95,7 +96,16 @@ class SettingScreenSimon extends StatelessWidget { fontWeight: FontWeight.bold), ), Button(text: 'FAQ', onTap: () {}), - Button(text: 'Safety Tipps', onTap: () {}), + Button( + text: 'Community Guidelines', + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const CommunityGuidelineScreen(), + ), + ); + }), SizedBox( height: 15, ), diff --git a/lib/Screens/chatscreen.dart b/lib/Screens/chatscreen.dart index 5342cb7..814fe60 100644 --- a/lib/Screens/chatscreen.dart +++ b/lib/Screens/chatscreen.dart @@ -2,7 +2,6 @@ import 'package:app_prototyo/Screens/Chat/chat_page.dart'; import 'package:app_prototyo/Screens/Chat/chat_service.dart'; import 'package:app_prototyo/Screens/Chat/user_tile.dart'; import 'package:app_prototyo/Screens/LogIn/services/auth_service.dart'; -import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; //Seite auf der die Chatspalten angezeigt werden @@ -27,7 +26,7 @@ class ChatScreen extends StatelessWidget { Widget _buildUserList() { return StreamBuilder>>( - stream: _chatService.getUsersStream(), + stream: _chatService.getChatPartnersStream(), builder: (context, snapshot) { if (snapshot.hasError) { return const Text('Error'); @@ -37,12 +36,10 @@ class ChatScreen extends StatelessWidget { return const Text('Loading...'); } - // Überprüfen, ob die Daten nicht null sind if (snapshot.data == null) { return const Text('No data available'); } - // Die Liste von Benutzerdaten extrahieren final userDataList = snapshot.data!; return ListView( @@ -58,21 +55,37 @@ class ChatScreen extends StatelessWidget { Map userData, BuildContext context) { final currentUserEmail = _authService.getCurrentUser()?.email; if (userData['mail'] != currentUserEmail) { - return UserTile( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ChatPage( - receiverName: userData['name'], - receiverID: userData['uid'], - url: userData['mainimage']), - ), + return FutureBuilder( + future: _chatService.getLastMessage(userData['uid']), + builder: (context, snapshot) { + String lastMessage = ''; + if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.hasError) { + lastMessage = 'Error loading message'; + } else { + lastMessage = snapshot.data ?? 'No message'; + } + } else { + lastMessage = 'Loading...'; + } + return UserTile( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ChatPage( + receiverName: userData['name'], + receiverID: userData['uid'], + url: userData['mainimage']), + ), + ); + }, + name: userData['name'], + url: userData['mainimage'], + lastMessage: lastMessage, + onDismissed: () {}, ); }, - name: userData['name'], - url: userData['mainimage'], - onDismissed: () {}, ); } else { return Container(); diff --git a/lib/firebase_service.dart b/lib/firebase_service.dart index faae0e7..759723d 100644 --- a/lib/firebase_service.dart +++ b/lib/firebase_service.dart @@ -37,7 +37,12 @@ class FirebaseService { image1url: userData['image1url'] ?? '', image2url: userData['image2url'] ?? '', aboutme: userData['aboutme'] ?? '', - countrylist: List.from(userData['countrylist'] ?? []), + instagram: userData['instagram'] ?? '', + tiktok: userData['tiktok'] ?? '', + visitedcountrylist: + List.from(userData['visitedcountrylist'] ?? []), + wannavisitcountrylist: + List.from(userData['wannavisitcountrylist'] ?? []), interestlist: List.from(userData['interestlist'] ?? []), qalist: List.from(userData['qalist'] ?? []), languagelist: List.from(userData['languagelist'] ?? []), diff --git a/lib/main.dart b/lib/main.dart index 30fa4bc..0380ea1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:app_prototyo/Plans/FindPlans/find_plans_provider.dart'; + import 'package:app_prototyo/Provider/plans_provider.dart'; import 'package:app_prototyo/Provider/user_provider.dart'; @@ -27,14 +28,14 @@ Future main() async { runApp( MultiProvider( providers: [ - - ChangeNotifierProvider(create: (context) => StartProvider()), //Provider Nils - ChangeNotifierProvider(create: (context) => UserProvider()), //Provider Simon + ChangeNotifierProvider( + create: (context) => StartProvider()), //Provider Nils + ChangeNotifierProvider( + create: (context) => UserProvider()), //Provider Simon ChangeNotifierProvider(create: (context) => PlansProvider()), ChangeNotifierProvider(create: (context) => FindPlansProvider()), ], child: const MyApp(), - ), ); } @@ -66,4 +67,3 @@ class MyApp extends StatelessWidget { ); } } - diff --git a/pubspec.lock b/pubspec.lock index a0b43c6..326cb51 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -272,6 +272,14 @@ packages: description: flutter source: sdk version: "0.0.0" + font_awesome_flutter: + dependency: "direct main" + description: + name: font_awesome_flutter + sha256: "275ff26905134bcb59417cf60ad979136f1f8257f2f449914b2c3e05bbb4cd6f" + url: "https://pub.dev" + source: hosted + version: "10.7.0" google_identity_services_web: dependency: transitive description: @@ -588,26 +596,26 @@ packages: dependency: "direct main" description: name: sign_in_with_apple - sha256: "0975c23b9f8b30a80e27d5659a75993a093d4cb5f4eb7d23a9ccc586fea634e0" + sha256: b0abd9c0d0407140829b12cd99a250f10b20352573ff08c7e0c5174c64b4973e url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "6.1.0" sign_in_with_apple_platform_interface: dependency: transitive description: name: sign_in_with_apple_platform_interface - sha256: a5883edee09ed6be19de19e7d9f618a617fe41a6fa03f76d082dfb787e9ea18d + sha256: c2ef2ce6273fce0c61acd7e9ff5be7181e33d7aa2b66508b39418b786cca2119 url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.1.0" sign_in_with_apple_web: dependency: transitive description: name: sign_in_with_apple_web - sha256: "44b66528f576e77847c14999d5e881e17e7223b7b0625a185417829e5306f47a" + sha256: c009e9beeb6c376e86aaa154fcc8b4e075d4bad90c56286b9668a51cdb6129ea url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "2.1.0" sky_engine: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 12971e3..8b1fc52 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -44,7 +44,7 @@ dependencies: firebase_storage: ^11.5.6 google_sign_in: ^6.2.1 - sign_in_with_apple: ^5.0.0 + sign_in_with_apple: ^6.1.0 provider: ^6.1.1 email_auth: ^1.1.1 @@ -56,6 +56,7 @@ dependencies: syncfusion_flutter_maps: ^25.1.35 url_launcher: ^6.2.6 country_state_city: ^0.1.6 + font_awesome_flutter: ^10.7.0 photo_view: ^0.15.0 path_provider: ^2.0.8