Commit c43cc7ec authored by Adam Bruck's avatar Adam Bruck

search

parent e953b7df
This diff is collapsed.
......@@ -2,35 +2,46 @@ import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class BookDetailsPage extends StatelessWidget {
final QueryDocumentSnapshot book;
final Map<String, dynamic> book;
BookDetailsPage({required this.book});
@override
Widget build(BuildContext context) {
final title = book['title'] ?? 'No title available';
final author = book['author'] ?? 'No author available';
final isbn = book['isbn'] ?? 'No ISBN available';
final price = book['price'] is String ? double.tryParse(book['price']) ?? 0.0 : book['price'] ?? 0.0;
final condition = book['condition'] ?? 'Condition not available';
final description = book['description'] ?? 'No description available';
final imageUrl = book['imageUrl'] ?? 'https://via.placeholder.com/200'; // Fallback URL
return Scaffold(
appBar: AppBar(title: Text(book['title'])),
body: Padding(
padding: const EdgeInsets.all(16.0),
appBar: AppBar(title: Text(title)),
body: SingleChildScrollView( // Makes content scrollable
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: book['imageUrl'] != null
? Image.network(book['imageUrl'], height: 200, fit: BoxFit.cover)
child: imageUrl.isNotEmpty
? Image.network(imageUrl, height: 200, fit: BoxFit.cover)
: Icon(Icons.book, size: 100),
),
SizedBox(height: 20),
Text("Title: ${book['title']}", style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold)),
Text("Author: ${book['author']}", style: TextStyle(fontSize: 18)),
Text("ISBN: ${book['isbn']}", style: TextStyle(fontSize: 16)),
Text("Price: \$${book['price']}", style: TextStyle(fontSize: 16, color: Colors.green)),
Text("Title: $title", style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold)),
Text("Author: $author", style: TextStyle(fontSize: 18)),
Text("ISBN: $isbn", style: TextStyle(fontSize: 16)),
Text("Price: \$${price.toStringAsFixed(2)}", style: TextStyle(fontSize: 16, color: Colors.green)),
Text("Condition: $condition", style: TextStyle(fontSize: 16)),
SizedBox(height: 10),
Text("Description:", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
Text(book['description'] ?? 'No description available', style: TextStyle(fontSize: 16)),
Text(description, style: TextStyle(fontSize: 16)),
],
),
),
),
);
}
}
......@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'post.dart';
import 'inbox.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
......
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:paperchase_app/book_detail_page.dart';
import 'package:paperchase_app/mybooks.dart';
import 'firebase_options.dart';
import 'package:http/http.dart' as http;
......@@ -101,6 +103,7 @@ class _HomePageState extends State<HomePage> {
void initState() {
super.initState();
_checkUserLoginStatus();
_loadRecentBooks();
}
void _checkUserLoginStatus() {
......@@ -122,22 +125,53 @@ class _HomePageState extends State<HomePage> {
Future<void> _searchBooks() async {
final query = _searchController.text;
if (query.isEmpty) return;
if (query.isEmpty) {
_loadRecentBooks(); // If search is empty, load recent books
return;
}
try {
final QuerySnapshot snapshot = await FirebaseFirestore.instance
.collection('books')
.orderBy('timestamp', descending: true) // Sort by the most recent posts
.get();
// Now filter books locally based on the title
final filteredBooks = snapshot.docs.where((doc) {
final title = doc['title'].toString().toLowerCase();
return title.contains(query.toLowerCase()); // Case-insensitive search
}).toList();
setState(() {
_books = filteredBooks.map((doc) => doc.data()).toList();
});
} catch (e) {
print("Error searching books: $e");
}
}
final url = Uri.parse('https://www.googleapis.com/books/v1/volumes?q=${Uri.encodeComponent(query)}');
Future<void> _loadRecentBooks() async {
try {
final response = await http.get(url);
final data = json.decode(response.body);
final QuerySnapshot snapshot = await FirebaseFirestore.instance
.collection('books')
.orderBy('timestamp', descending: true) // Sort by the most recent posts
.limit(10) // Optionally limit to the latest 10 books
.get();
setState(() {
_books = data['items'] ?? [];
_books = snapshot.docs.map((doc) => doc.data()).toList();
});
} catch (error) {
print("Error fetching books: $error");
} catch (e) {
print("Error fetching recent books: $e");
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
......@@ -198,23 +232,24 @@ class _HomePageState extends State<HomePage> {
child: ListView.builder(
itemCount: _books.length,
itemBuilder: (context, index) {
final book = _books[index]['volumeInfo'];
final book = _books[index];
final title = book['title'] ?? "Unknown Title";
final authors = book['authors']?.join(", ") ?? "Unknown Author";
final thumbnail = book['imageLinks']?['thumbnail'] ?? "https://via.placeholder.com/50";
final link = book['infoLink'] ?? "#";
final author = book['author'] ?? "No author available";
final thumbnail = book['imageUrl'] ?? "https://via.placeholder.com/50";
return ListTile(
leading: Image.network(thumbnail, width: 50, height: 50, fit: BoxFit.cover),
title: Text(title),
subtitle: Text(authors),
onTap: () async {
final Uri url = Uri.parse(link);
if (await canLaunchUrl(url)) {
await launchUrl(url);
} else {
print("Could not open $url");
}
subtitle: Text(author),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BookDetailsPage(book: book), // Pass book data
),
);
},
);
},
......
......@@ -28,7 +28,7 @@ class MyBooksPage extends StatelessWidget {
return ListView.builder(
itemCount: books.length,
itemBuilder: (context, index) {
var book = books[index];
var book = books[index].data() as Map<String, dynamic>; // Use data() to get the map
return ListTile(
leading: book['imageUrl'] != null
......
......@@ -19,6 +19,7 @@ class _PostBookPageState extends State<PostBookPage> {
final TextEditingController authorController = TextEditingController();
final TextEditingController descriptionController = TextEditingController();
File? _imageFile;
String _selectedCondition = "Like New";
// Function to pick an image from camera or gallery
Future<void> _pickImage(ImageSource source) async {
......@@ -52,19 +53,22 @@ Future<String?> fetchBookDescription(String isbn) async {
Future<String?> uploadImageToImgur(File imageFile) async {
try {
final uri = Uri.parse('https://api.imgur.com/3/upload');
final request = http.MultipartRequest('POST', uri)
..headers['Authorization'] = '00caf989adf38fa'
..files.add(await http.MultipartFile.fromPath('image', imageFile.path));
var request = http.MultipartRequest(
'POST', Uri.parse('https://api.imgur.com/3/upload')
);
request.headers['Authorization'] = 'Client-ID 00caf989adf38fa';
final response = await request.send();
var pic = await http.MultipartFile.fromPath('image', imageFile.path);
request.files.add(pic);
var response = await request.send();
if (response.statusCode == 200) {
final responseData = await response.stream.bytesToString();
final jsonData = json.decode(responseData);
return jsonData['data']['link']; // The image URL from Imgur
return jsonData['data']['link']; // Image URL from Imgur
} else {
print('Failed to upload image to Imgur');
print('Failed to upload image: ${response.reasonPhrase}');
return null;
}
} catch (e) {
......@@ -91,8 +95,10 @@ Future<String?> uploadImageToImgur(File imageFile) async {
'isbn': isbnController.text,
'price': priceController.text,
'description': descriptionController.text,
'condition': _selectedCondition,
'userId': user.uid, // 🔹 Save logged-in user's ID
'imageUrl': imageUrl ?? "", // Optional image
'timestamp': FieldValue.serverTimestamp(),
});
return true;
} catch(e) {
......@@ -167,7 +173,21 @@ Future<String?> uploadImageToImgur(File imageFile) async {
decoration: InputDecoration(labelText: 'Author'),
),
SizedBox(height: 20),
DropdownButtonFormField<String>(
value: _selectedCondition,
items: ['Like New', 'Good', 'Fair', 'Poor']
.map((condition) => DropdownMenuItem(
value: condition,
child: Text(condition),
))
.toList(),
onChanged: (value) {
setState(() {
_selectedCondition = value!;
});
},
decoration: InputDecoration(labelText: 'Condition'),
),
// Image Picker Buttons
Row(
mainAxisAlignment: MainAxisAlignment.center,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment