diff --git a/.gitignore b/.gitignore
index 24476c5..3f3ca0f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,3 +42,6 @@ app.*.map.json
/android/app/debug
/android/app/profile
/android/app/release
+
+# Hide key from version control
+lib/api_key.dart
\ No newline at end of file
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index ed53d24..fd1afc0 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -4,7 +4,7 @@
();
@@ -51,9 +55,9 @@ class MainPage extends StatelessWidget {
} else if (snapshot.hasError) {
return const Center(child: Text('Something went wrong!'));
} else if (snapshot.hasData) {
- return TabsScreen();
+ return const TabsScreen();
} else {
- return AuthPage();
+ return const AuthPage();
}
},
),
diff --git a/lib/models/listing.dart b/lib/models/listing.dart
index 11ec031..df05b11 100644
--- a/lib/models/listing.dart
+++ b/lib/models/listing.dart
@@ -70,7 +70,6 @@ enum DietaryNeeds {
containsNuts,
containShellfish,
containsSoy,
- others,
none,
}
@@ -114,7 +113,7 @@ Map> categorySubcategoryMap = {
MainCategory.frozen: [
SubCategory.desserts,
SubCategory.meat,
- SubCategory.seafood,
+ SubCategory.seafoods,
],
MainCategory.fruitsAndVegetables: [
SubCategory.fruits,
@@ -137,11 +136,13 @@ class UserLocation {
required this.latitude,
required this.longitude,
required this.address,
+ required this.addressImageUrl,
});
final double latitude;
final double longitude;
final String address;
+ final String addressImageUrl;
}
class Listing {
@@ -160,14 +161,17 @@ class Listing {
required this.isAvailable,
required this.userId,
required this.userName,
+ required this.userPhoto,
+ required this.addressImageUrl,
});
// : isAvailable = DateTime.now().isAfter(expiryDate),
// userId = FirebaseAuth.instance.currentUser!.email.toString();
final String id;
final String userName;
- final String userId; //not necessary?
+ final String userId;
+ final String userPhoto;
final String itemName;
- final String image; //change type //
+ final String image;
final String mainCategory; //
final String subCategory; //
final String dietaryNeeds; //
@@ -176,23 +180,27 @@ class Listing {
final bool isAvailable;
final double lat;
final double lng;
- final String address; //
+ final String address;
+ final String addressImageUrl; //
static Listing fromJson(Map json) => Listing(
- id: json['id'],
- itemName: json['itemName'],
- userName: json['userName'],
- userId: json['userId'],
- image: json['image'],
- mainCategory: json['mainCategory'],
- subCategory: json['subCategory'],
- dietaryNeeds: json['dietaryNeeds'],
- expiryDate: (json['expiryDate'] as Timestamp).toDate(),
- isAvailable: json['isAvailable'],
- lat: json['lat'],
- lng: json['lng'],
- address: json['address'],
- additionalNotes: json['additionalNotes']);
+ id: json['id'],
+ itemName: json['itemName'],
+ userName: json['userName'],
+ userId: json['userId'],
+ userPhoto: json['userPhoto'],
+ image: json['image'],
+ mainCategory: json['mainCategory'],
+ subCategory: json['subCategory'],
+ dietaryNeeds: json['dietaryNeeds'],
+ expiryDate: (json['expiryDate'] as Timestamp).toDate(),
+ isAvailable: json['isAvailable'],
+ lat: json['lat'],
+ lng: json['lng'],
+ address: json['address'],
+ addressImageUrl: json['addressImageUrl'],
+ additionalNotes: json['additionalNotes'],
+ );
Map toJson() => {
'id': id,
@@ -208,6 +216,8 @@ class Listing {
'isAvailable': isAvailable,
'lat': lat,
'lng': lng,
- 'address': address
+ 'address': address,
+ 'addressImageUrl': addressImageUrl,
+ 'userPhoto' : userPhoto,
};
}
diff --git a/lib/providers/all_listings_provider.dart b/lib/providers/all_listings_provider.dart
new file mode 100644
index 0000000..e777c0b
--- /dev/null
+++ b/lib/providers/all_listings_provider.dart
@@ -0,0 +1,7 @@
+// import 'package:flutter_riverpod/flutter_riverpod.dart';
+// import 'package:cloud_firestore/cloud_firestore.dart';
+
+// class ListingsNotifier extends StateNotifier {
+// ListingsNotifier(): super([]);
+
+// }
\ No newline at end of file
diff --git a/lib/providers/current_user_provider.dart b/lib/providers/current_user_provider.dart
new file mode 100644
index 0000000..9ee30b8
--- /dev/null
+++ b/lib/providers/current_user_provider.dart
@@ -0,0 +1,6 @@
+import 'package:firebase_auth/firebase_auth.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+final currentUser = Provider((ref) {
+ return FirebaseAuth.instance.currentUser!;
+});
diff --git a/lib/screens/chat_list_screen.dart b/lib/screens/chat/chat_list_screen.dart
similarity index 63%
rename from lib/screens/chat_list_screen.dart
rename to lib/screens/chat/chat_list_screen.dart
index e5821cf..1718a5a 100644
--- a/lib/screens/chat_list_screen.dart
+++ b/lib/screens/chat/chat_list_screen.dart
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
+import 'package:foodbridge_project/widgets/chat_widgets/chat_list.dart';
class ChatListScreen extends StatefulWidget {
const ChatListScreen({super.key});
@@ -8,13 +9,17 @@ class ChatListScreen extends StatefulWidget {
}
class _ChatListScreenState extends State {
+
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
- title: const Text('Your chats'),
- backgroundColor: Colors.orange,
+ title: Text(
+ 'Chats',
+ style: Theme.of(context).textTheme.titleLarge,
+ ),
),
+ body: const AllChatList(),
);
}
-}
\ No newline at end of file
+}
diff --git a/lib/screens/chat/chatroom_screen.dart b/lib/screens/chat/chatroom_screen.dart
new file mode 100644
index 0000000..c8dc0f9
--- /dev/null
+++ b/lib/screens/chat/chatroom_screen.dart
@@ -0,0 +1,130 @@
+import 'package:cloud_firestore/cloud_firestore.dart';
+import 'package:flutter/material.dart';
+import '../../widgets/chat_widgets/chat_messages.dart';
+import '../../widgets/chat_widgets/new_message.dart';
+
+class ChatScreen extends StatelessWidget {
+ const ChatScreen({Key? key, required this.chatId, required this.listingId})
+ : super(key: key);
+
+ final String chatId;
+ final String listingId;
+
+ @override
+ Widget build(BuildContext context) {
+ //Retrieves information about listing
+ return FutureBuilder>>(
+ future: FirebaseFirestore.instance
+ .collection('Listings')
+ .doc(listingId)
+ .get(),
+ builder: (context, snapshot) {
+ if (snapshot.connectionState == ConnectionState.waiting) {
+ return const Center(child: CircularProgressIndicator());
+ }
+ if (snapshot.hasError) {
+ return Center(child: Text('Error: ${snapshot.error}'));
+ }
+ if (!snapshot.hasData || snapshot.data!.data() == null) {
+ return const Center(child: Text('Data not available'));
+ }
+
+ final listing = snapshot.data!.data()!;
+
+ return Scaffold(
+ appBar: AppBar(
+ title: Text(
+ 'Chat',
+ style: Theme.of(context).textTheme.titleLarge,
+ ),
+ ),
+ body: Column(
+ children: [
+ //Brief summary of listing details
+ //displayed at the top of chatroom
+ Card(
+ margin: const EdgeInsets.all(16),
+ elevation: 4,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(10),
+ ),
+ child: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: Row(
+ children: [
+ Container(
+ height: 120,
+ width: 120,
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(8),
+ image: DecorationImage(
+ image: NetworkImage(listing['image']),
+ fit: BoxFit.cover,
+ ),
+ ),
+ ),
+ const SizedBox(
+ width: 8,
+ ),
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ listing['itemName'],
+ style: const TextStyle(
+ fontSize: 14,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ const SizedBox(height: 8),
+ Text(
+ 'Main category: ${listing['mainCategory'].split('.').last}',
+ style: const TextStyle(fontSize: 12),
+ ),
+ const SizedBox(height: 8),
+ Text(
+ 'Subcategory: ${listing['subCategory'].split('.').last}',
+ style: const TextStyle(fontSize: 12),
+ ),
+ const SizedBox(height: 8),
+ Text(
+ 'Location: ${listing['address'].split('.').last}',
+ style: const TextStyle(fontSize: 12),
+ overflow: TextOverflow.visible,
+ ),
+ const SizedBox(height: 8),
+ Text(
+ 'Available: ${listing['isAvailable'].toString()}',
+ style: const TextStyle(fontSize: 12),
+ ),
+ const SizedBox(height: 8),
+ Text(
+ 'Donor: ${listing['userName'].toString()}',
+ style: const TextStyle(fontSize: 12),
+ ),
+ ],
+ ),
+ )
+ ],
+ ),
+ ),
+ ),
+ //All text messages/ text bubbles
+ Expanded(
+ child: ChatMessages(
+ chatId: chatId,
+ ),
+ ),
+ //text field to key in new
+ //message or text
+ NewMessage(
+ chatId: chatId,
+ ),
+ ],
+ ),
+ );
+ },
+ );
+ }
+}
diff --git a/lib/screens/edit_listing_screen.dart b/lib/screens/edit_listing_screen.dart
index 7d15665..61a5e1d 100644
--- a/lib/screens/edit_listing_screen.dart
+++ b/lib/screens/edit_listing_screen.dart
@@ -5,9 +5,9 @@ import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:foodbridge_project/models/listing.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
-
-import '../widgets/edit_image_input.dart';
-import '../widgets/edit_location_input.dart';
+import '../widgets/image_input/edit_image_input.dart';
+import '../widgets/location_input/edit_location_input.dart';
+import '../widgets/utils.dart';
class EditListingScreen extends StatefulWidget {
const EditListingScreen(
@@ -32,6 +32,15 @@ class _EditListingScreenState extends State {
MainCategory? selectedMainCategory;
SubCategory? selectedSubCategory;
+ @override
+ void dispose() {
+ dateInputController.dispose();
+ super.dispose();
+ }
+
+ //initialize fields to original values. In the event that
+ //user does not make any edits, the original values
+ //will be retained in the database.
@override
void initState() {
selectedMainCategory = MainCategory.values.firstWhere(
@@ -48,6 +57,7 @@ class _EditListingScreenState extends State {
_editedAddress = _address;
_editedLng = _lng;
_editedLat = _lat;
+ _editedAddressImageUrl = _addressImageUrl;
_editedSelectedImage = _image;
_editedChosenDate = _expiryDate;
_editedChosenMainCategory = _mainCategory;
@@ -101,6 +111,10 @@ class _EditListingScreenState extends State {
return widget.listing.lng;
}
+ String get _addressImageUrl {
+ return widget.listing.addressImageUrl;
+ }
+
String get _mainCategory {
return widget.listing.mainCategory;
}
@@ -120,15 +134,17 @@ class _EditListingScreenState extends State {
var _editedChosenDate;
var _editedAdditionalInfo;
var _editedSelectedImage;
- var _editedLat;
- var _editedLng;
- var _editedAddress;
+ double? _editedLat;
+ double? _editedLng;
+ String? _editedAddress;
+ String? _editedAddressImageUrl;
var _unchangedId;
var _unchangeduserId;
var _unchangedIsAvailable;
var _urlLink;
bool _isSaving = false;
+ //upload new image to storage
Future uploadImage(File file) async {
String fileName = DateTime.now().millisecondsSinceEpoch.toString();
firebase_storage.Reference ref =
@@ -138,6 +154,7 @@ class _EditListingScreenState extends State {
return imageUrl;
}
+ //If user uploads new photo, delete old photo in storage
Future deleteFileByUrl(String fileUrl) async {
try {
// Extract the file name from the URL
@@ -162,6 +179,7 @@ class _EditListingScreenState extends State {
await ref.delete();
}
+ //save updates made by user, if any
void _saveItem() async {
if (_editedSelectedImage == null) {
showDialog(
@@ -171,10 +189,10 @@ class _EditListingScreenState extends State {
'Picture missing',
textAlign: TextAlign.center,
),
- content: Container(
+ content: const SizedBox(
height: 16,
width: 32,
- child: const Center(
+ child: Center(
child: Text('Add a picture'),
),
),
@@ -198,10 +216,10 @@ class _EditListingScreenState extends State {
'Address missing',
textAlign: TextAlign.center,
),
- content: Container(
+ content: const SizedBox(
height: 16,
width: 32,
- child: const Center(
+ child: Center(
child: Text('Click on get address'),
),
),
@@ -222,6 +240,7 @@ class _EditListingScreenState extends State {
_isSaving = true;
});
_formKey.currentState!.save();
+ try {
if (_editedSelectedImage == _image) {
_urlLink = _editedSelectedImage;
} else {
@@ -237,6 +256,7 @@ class _EditListingScreenState extends State {
'itemName': _editedItemName,
'lat': _editedLat,
'lng': _editedLng,
+ 'addressImageUrl' :_editedAddressImageUrl,
'mainCategory': _editedChosenMainCategory,
'subCategory': _editedChosenSubCategory,
});
@@ -247,11 +267,15 @@ class _EditListingScreenState extends State {
content: Text('Edits are saved'),
),
);
+ } catch (e) {
+ Utils.showSnackBar('error: $e');
+ }
Navigator.pop(context);
Navigator.pop(context);
}
}
+ //date picker, formatted
void _presentDatePicker() async {
final now = DateTime.now();
final firstDate = DateTime(
@@ -280,15 +304,9 @@ class _EditListingScreenState extends State {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
- centerTitle: true,
- backgroundColor: Colors.orange,
- title: const Text(
- 'EDIT LISTING',
- style: TextStyle(
- fontWeight: FontWeight.bold,
- color: Colors.white,
- fontSize: 24,
- ),
+ title: Text(
+ 'Edit Listing',
+ style: Theme.of(context).textTheme.titleLarge,
),
),
body: Padding(
@@ -440,10 +458,11 @@ class _EditListingScreenState extends State {
),
EditLocationInput(
listing: widget.listing,
- chosenLocation: (UserLocation location) {
- _editedLat = location.latitude;
- _editedLng = location.longitude;
- _editedAddress = location.address;
+ chosenLocation: (UserLocation? location) {
+ _editedLat = location?.latitude;
+ _editedLng = location?.longitude;
+ _editedAddress = location?.address;
+ _editedAddressImageUrl = location?.addressImageUrl;
},
),
const SizedBox(
diff --git a/lib/screens/likes_screen.dart b/lib/screens/favorites_screen.dart
similarity index 82%
rename from lib/screens/likes_screen.dart
rename to lib/screens/favorites_screen.dart
index e91a726..0036208 100644
--- a/lib/screens/likes_screen.dart
+++ b/lib/screens/favorites_screen.dart
@@ -12,8 +12,10 @@ class _LikesScreenState extends State {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
- title: const Text('Your likes'),
- backgroundColor: Colors.orange,
+ title: Text(
+ 'Favorites',
+ style: Theme.of(context).textTheme.titleLarge,
+ ),
),
// body: ListingsScreen(
// toList: [], //to be used as a consumer to listen for changes in likes
diff --git a/lib/screens/filter.dart b/lib/screens/filter.dart
deleted file mode 100644
index 3400c89..0000000
--- a/lib/screens/filter.dart
+++ /dev/null
@@ -1,176 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:foodbridge_project/models/listing.dart';
-import 'package:foodbridge_project/screens/tabs_screen.dart';
-
-List selectedOptions = []; // Stores selection
-
-class FilterWidget extends StatefulWidget {
- const FilterWidget({super.key});
- @override
- State createState() {
- return _FilterWidgetState();
- }
-}
-
-class _FilterWidgetState extends State {
- List categories = [
- Category(
- 'Food Types',
- [
- Subcategory('Baby Food'),
- Subcategory('Baked Goods'),
- Subcategory(
- 'Dairy, Chilled and Eggs',
- [
- 'Eggs',
- 'Milk',
- 'Cheese',
- 'Butter, Margarine and Spreads',
- 'Cream',
- 'Yoghurt',
- ],
- ),
- Subcategory(
- 'Beverages',
- [
- 'Coffee',
- 'Tea',
- 'Juices',
- 'Soft Drinks',
- ],
- ),
- Subcategory('Pantry Essentials', [
- 'Canned',
- 'Rice',
- 'Pasta',
- 'noodles',
- 'Cereal',
- 'Condiments',
- 'Baking Needs',
- 'Oil',
- ]),
- //Subcategory('Subcategory 1.2'),
- //Subcategory('Subcategory 1.2'),
- //Subcategory('Subcategory 1.2'),
- //Subcategory('Subcategory 1.2'),
- ],
- ),
- Category(
- 'Dietary Needs',
- [
- Subcategory('Subcategory 2.1', ['Option 2.1', 'Option 2.2']),
- Subcategory('Subcategory 2.2'),
- ],
- ),
- Category(
- 'Category 3',
- [
- Subcategory('Subcategory 3.1', ['Option 3.1', 'Option 3.2']),
- Subcategory('Subcategory 3.2', ['Option 3.3']),
- ],
- ),
- ];
-
- @override
- Widget build(BuildContext context) {
- return Column(
- children: [
- Expanded(
- child: ListView.builder(
- itemCount: categories.length,
- itemBuilder: (context, categoryIndex) {
- return ExpansionTile(
- title: Text(categories[categoryIndex].name),
- children:
- categories[categoryIndex].subcategories.map((subcategory) {
- if (subcategory.options != null &&
- subcategory.options!.isNotEmpty) {
- return _buildExpandableSubcategoryTile(subcategory);
- } else {
- return _buildCheckboxSubcategoryTile(subcategory);
- }
- }).toList(),
- );
- },
- ),
- ),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- mainAxisSize: MainAxisSize.max,
- children: [
- ElevatedButton(
- onPressed: () {
- selectedOptions.clear();
- setState(() {});
- },
- child: Text('Clear'),
- ),
- const SizedBox(
- width: 30,
- ),
- ElevatedButton(
- onPressed: () {
- Navigator.pop(context);
- setState(() {
- const TabsScreen();
- });
- },
- child: Text('Save'),
- ),
- ],
- ),
- ],
- );
- }
-
- Widget _buildExpandableSubcategoryTile(Subcategory subcategory) {
- return ExpansionTile(
- title: Text(subcategory.name),
- children: subcategory.options!.map((option) {
- return CheckboxListTile(
- title: Text(option),
- value: selectedOptions.contains(option),
- onChanged: (value) {
- setState(() {
- if (value != null && value) {
- selectedOptions.add(option);
- } else {
- selectedOptions.remove(option);
- }
- });
- },
- );
- }).toList(),
- );
- }
-
- Widget _buildCheckboxSubcategoryTile(Subcategory subcategory) {
- return CheckboxListTile(
- title: Text(subcategory.name),
- value: selectedOptions.contains(subcategory.name),
- onChanged: (value) {
- setState(() {
- if (value != null && value) {
- selectedOptions.add(subcategory.name);
- } else {
- selectedOptions.remove(subcategory.name);
- }
- });
- },
- );
- }
-}
-
-class Category {
- final String name;
- final List subcategories;
-
- Category(this.name, this.subcategories);
-}
-
-class Subcategory {
- final String name;
- final List? options;
-
- Subcategory(this.name, [this.options]);
-}
diff --git a/lib/screens/listing_screen.dart b/lib/screens/listing_screen.dart
index fa6e748..d141be2 100644
--- a/lib/screens/listing_screen.dart
+++ b/lib/screens/listing_screen.dart
@@ -1,21 +1,31 @@
import 'package:cloud_firestore/cloud_firestore.dart';
+import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:foodbridge_project/models/listing.dart';
+import 'package:foodbridge_project/screens/chat/chatroom_screen.dart';
import 'package:foodbridge_project/screens/edit_listing_screen.dart';
+import 'package:foodbridge_project/screens/profile_screens/others_profile_screen.dart';
+import 'package:foodbridge_project/widgets/loading.dart';
import 'package:intl/intl.dart';
import 'package:firebase_storage/firebase_storage.dart';
final formatter = DateFormat.yMd();
-class ListingScreen extends StatelessWidget {
+class ListingScreen extends StatefulWidget {
const ListingScreen(
{super.key, required this.listing, required this.isYourListing});
final Listing listing;
final bool isYourListing;
+ @override
+ State createState() => _ListingScreenState();
+}
+
+class _ListingScreenState extends State {
+ bool isLoading = false;
String get formattedDate {
- return formatter.format(listing.expiryDate);
+ return formatter.format(widget.listing.expiryDate);
}
FirebaseStorage get storage {
@@ -23,9 +33,12 @@ class ListingScreen extends StatelessWidget {
}
DocumentReference get docListing {
- return FirebaseFirestore.instance.collection('Listings').doc(listing.id);
+ return FirebaseFirestore.instance
+ .collection('Listings')
+ .doc(widget.listing.id);
}
+ //Deletes image in firebase
Future deleteFileByUrl(String fileUrl) async {
try {
// Extract the file name from the URL
@@ -50,12 +63,35 @@ class ListingScreen extends StatelessWidget {
await ref.delete();
}
- void _deleteLisiting() async {
- String fileUrl = listing.image;
+ //Deletes listing in firestore
+ void _deleteListing() async {
+ String fileUrl = widget.listing.image;
await deleteFileByUrl(fileUrl);
+ String listingId = widget.listing.id;
+ deleteChatDocuments(listingId);
docListing.delete();
}
+ void deleteChatDocuments(String listingId) async {
+ // Get a reference to the 'chat' collection
+ CollectionReference chatCollection =
+ FirebaseFirestore.instance.collection('chat');
+
+ // Query the collection to find the documents with the specified listingId
+ QuerySnapshot snapshot =
+ await chatCollection.where('listing', isEqualTo: listingId).get();
+
+ // Loop through each document and delete it
+ for (DocumentSnapshot doc in snapshot.docs) {
+ // Get the document reference
+ DocumentReference documentRef = doc.reference;
+
+ // Delete the document
+ await documentRef.delete();
+ }
+ }
+
+ //updates listing isAvailable field to true in firestore
void _markDonatedLisiting() {
docListing.update({
'isAvailable': false,
@@ -64,286 +100,702 @@ class ListingScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- backgroundColor: Colors.orange,
- title: Text(
- 'LISTING: ${listing.itemName.toUpperCase()}',
- style: const TextStyle(
- fontWeight: FontWeight.bold,
- color: Colors.white,
- fontSize: 24,
- ),
- ),
- centerTitle: true,
- ),
- body: Padding(
- padding: const EdgeInsets.all(16.0),
- child: Column(
- mainAxisAlignment: MainAxisAlignment.start,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Stack(
- children: [
- SizedBox(
- width: double.infinity,
- height: 350,
- child: ClipRRect(
- borderRadius: BorderRadius.circular(16),
- child: Image.network(
- listing.image,
- fit: BoxFit.cover,
- ),
- ),
- ),
- Positioned(
- right: 0,
- bottom: 0,
- child: Container(
- height: 80,
- width: 128,
- decoration: BoxDecoration(
- color: Colors.black.withOpacity(0.5),
- borderRadius: BorderRadius.circular(16),
- ),
- ),
- ),
- Positioned(
- right: 16,
- bottom: 16,
- child: Row(
+ final user = FirebaseAuth.instance.currentUser!;
+
+ //Navigates to chatroom. Create new chatroom if it doesn't
+ //yet exist between 2 specified people for a specific
+ //listing. Else, go to existing chatroom.
+ //If user leaves the new chatroom created
+ //and there are no messages,
+ //delete the chatroom doc from firestore.
+ //Else, save it in firestore.
+ void goToChat() async {
+ QuerySnapshot