Initial commit

This commit is contained in:
Yas Opisso
2025-12-12 14:31:36 -05:00
commit 83775bdc72
175 changed files with 17284 additions and 0 deletions

View File

@@ -0,0 +1,202 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/cupertino.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:hum/core/constants/app_theme.dart';
import 'package:hum/views/listings/views/items/thumbnail_with_details.dart';
class HomeViewGrid extends StatefulWidget {
const HomeViewGrid({super.key});
@override
State<HomeViewGrid> createState() => _HomeViewGridState();
}
class _HomeViewGridState extends State<HomeViewGrid> {
final ScrollController _scrollController = ScrollController();
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final cardRadius = 16.0;
return Expanded(
child: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection('items').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(
'Error: ${snapshot.error}',
style: const TextStyle(color: CupertinoColors.systemRed),
),
);
}
// Only show loading spinner on initial load, not on updates
if (!snapshot.hasData) {
return const Center(child: CupertinoActivityIndicator());
}
if (snapshot.data!.docs.isEmpty) {
return const Center(
child: Text('No items found', style: TextStyle(color: CupertinoColors.systemGrey)),
);
}
final items = snapshot.data!.docs;
return CustomScrollView(
controller: _scrollController,
cacheExtent: 1000, // Preload images 1000 pixels ahead
slivers: [
const SliverPadding(padding: EdgeInsets.only(top: 120.0)),
SliverPadding(
padding: const EdgeInsets.all(8.0),
sliver: SliverGrid(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 6.0,
mainAxisSpacing: 6.0,
childAspectRatio: 0.9,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
final item = items[index];
Map<dynamic, dynamic>? itemData = item.data() as Map?;
String thumbnailURL = '';
if (itemData != null) {
thumbnailURL = itemData['images'][0];
}
return GestureDetector(
onTap: () {
Navigator.of(context, rootNavigator: true).push(
CupertinoPageRoute(
// fullscreenDialog: true,
builder: (context) => ViewListingsItem(
itemID: item.id,
thumbnailURL: thumbnailURL,
itemData: itemData,
),
),
);
},
child: Container(
key: ValueKey(item.id),
decoration: BoxDecoration(
color: CupertinoDynamicColor.resolve(colorBarBackground, context),
borderRadius: BorderRadius.circular(cardRadius),
// border: Border.all(color: color, width: 2.0),
),
child: Column(
children: [
Stack(
children: [
// LISTING IMAGE
Padding(
padding: const EdgeInsets.all(6.0),
child: SizedBox(
height: 150,
width: double.infinity,
child: Hero(
tag: itemData?['id'],
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(cardRadius),
topRight: Radius.circular(cardRadius),
bottomLeft: Radius.circular(cardRadius),
bottomRight: Radius.circular(cardRadius),
),
child: CachedNetworkImage(
imageUrl: thumbnailURL,
fit: BoxFit.cover,
memCacheHeight: 600,
maxHeightDiskCache: 600,
fadeInDuration: Duration.zero,
fadeOutDuration: Duration.zero,
placeholderFadeInDuration: Duration.zero,
// fadeInDuration: Duration(milliseconds: 200),
placeholder: (context, url) =>
Center(child: CupertinoActivityIndicator()),
errorWidget: (context, url, error) =>
Icon(CupertinoIcons.photo, size: 32),
),
),
),
),
),
// CATEGORY LABEL
Positioned(
top: 16,
left: 16,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
color: CupertinoColors.activeBlue.withAlpha(180),
),
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2),
child: Text(
'Electronics',
style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
),
),
),
],
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(
left: 0.0,
right: 8.0,
top: 0.0,
bottom: 0.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
spacing: 2,
children: [
Text(
itemData?['title'],
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: TextStyle(fontSize: 14),
),
Text(
'\$${itemData!['price_per_day']} / day',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: CupertinoColors.activeBlue,
),
),
],
),
),
),
],
),
),
);
},
childCount: items.length,
addAutomaticKeepAlives: true,
addRepaintBoundaries: true,
),
),
),
],
);
},
),
);
}
}