Update default location to Thrissur and remove Whitefield, Bengaluru
This commit is contained in:
@@ -93,7 +93,7 @@ class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateM
|
||||
setState(() => _loading = true);
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
_username = prefs.getString('display_name') ?? prefs.getString('username') ?? '';
|
||||
final storedLocation = prefs.getString('location') ?? 'Whitefield, Bengaluru';
|
||||
final storedLocation = prefs.getString('location') ?? 'Thrissur';
|
||||
// Fix legacy lat,lng strings saved before the reverse-geocoding fix
|
||||
final coordMatch = RegExp(r'^(-?\d+\.?\d*),\s*(-?\d+\.?\d*)$').firstMatch(storedLocation);
|
||||
if (coordMatch != null) {
|
||||
@@ -467,7 +467,7 @@ class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateM
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
if (ev.id != null) {
|
||||
Navigator.of(context).push(MaterialPageRoute(builder: (_) => LearnMoreScreen(eventId: ev.id, initialEvent: ev)));
|
||||
Navigator.of(context).push(MaterialPageRoute(builder: (_) => LearnMoreScreen(eventId: ev.id, initialEvent: ev, heroTag: 'event-hero-${ev.id}-search')));
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -919,7 +919,7 @@ class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateM
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
if (ev.id != null) {
|
||||
Navigator.of(context).push(MaterialPageRoute(builder: (_) => LearnMoreScreen(eventId: ev.id, initialEvent: ev)));
|
||||
Navigator.of(context).push(MaterialPageRoute(builder: (_) => LearnMoreScreen(eventId: ev.id, initialEvent: ev, heroTag: 'event-hero-${ev.id}-sheet')));
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
@@ -1197,129 +1197,181 @@ class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateM
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns the image URL for a given event (for blurred bg).
|
||||
String? _getEventImageUrl(EventModel event) {
|
||||
if (event.thumbImg != null && event.thumbImg!.isNotEmpty) return event.thumbImg;
|
||||
if (event.images.isNotEmpty && event.images.first.image.isNotEmpty) return event.images.first.image;
|
||||
return null;
|
||||
}
|
||||
|
||||
Widget _buildHeroSection() {
|
||||
return SafeArea(
|
||||
bottom: false,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Top bar: location pill + search button
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: _openLocationSearch,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.15),
|
||||
borderRadius: BorderRadius.circular(25),
|
||||
border: Border.all(color: Colors.white.withOpacity(0.2)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.location_on_outlined, color: Colors.white, size: 18),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
_location.length > 20 ? '${_location.substring(0, 20)}...' : _location,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 14, fontWeight: FontWeight.w500),
|
||||
child: ValueListenableBuilder<int>(
|
||||
valueListenable: _heroPageNotifier,
|
||||
builder: (context, currentPage, _) {
|
||||
final currentImg = _heroEvents.isNotEmpty ? _getEventImageUrl(_heroEvents[currentPage.clamp(0, _heroEvents.length - 1)]) : null;
|
||||
return Stack(
|
||||
children: [
|
||||
// ── Blurred background image layer ──
|
||||
if (currentImg != null && currentImg.isNotEmpty)
|
||||
Positioned.fill(
|
||||
child: ClipRect(
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
child: CachedNetworkImage(
|
||||
key: ValueKey(currentImg),
|
||||
imageUrl: currentImg,
|
||||
memCacheWidth: 200,
|
||||
memCacheHeight: 200,
|
||||
fit: BoxFit.cover,
|
||||
placeholder: (_, __) => const SizedBox.shrink(),
|
||||
errorWidget: (_, __, ___) => const SizedBox.shrink(),
|
||||
imageBuilder: (context, imageProvider) => Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
ImageFiltered(
|
||||
imageFilter: ImageFilter.blur(sigmaX: 30, sigmaY: 30),
|
||||
child: Image(
|
||||
image: imageProvider,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
color: Colors.black.withOpacity(0.35),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
const Icon(Icons.keyboard_arrow_down, color: Colors.white, size: 18),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const NotificationBell(),
|
||||
const SizedBox(width: 8),
|
||||
GestureDetector(
|
||||
onTap: _openEventSearch,
|
||||
child: Container(
|
||||
width: 48,
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.15),
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(color: Colors.white.withOpacity(0.2)),
|
||||
),
|
||||
child: const Icon(Icons.search, color: Colors.white, size: 24),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Featured carousel
|
||||
_heroEvents.isEmpty
|
||||
? _loading
|
||||
? const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
child: SizedBox(
|
||||
height: 320,
|
||||
child: _HeroShimmer(),
|
||||
),
|
||||
)
|
||||
: const SizedBox(
|
||||
height: 280,
|
||||
child: Center(
|
||||
child: Text('No events available',
|
||||
style: TextStyle(color: Colors.white70)),
|
||||
),
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
RepaintBoundary(
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onPanDown: (_) => _autoScrollTimer?.cancel(),
|
||||
onPanEnd: (_) => _startAutoScroll(delay: const Duration(seconds: 3)),
|
||||
onPanCancel: () => _startAutoScroll(delay: const Duration(seconds: 3)),
|
||||
child: SizedBox(
|
||||
height: 320,
|
||||
child: PageView.builder(
|
||||
controller: _heroPageController,
|
||||
onPageChanged: (page) {
|
||||
_heroPageNotifier.value = page;
|
||||
// 8s delay after manual swipe for full read time
|
||||
_startAutoScroll(delay: const Duration(seconds: 8));
|
||||
},
|
||||
itemCount: _heroEvents.length,
|
||||
itemBuilder: (context, index) {
|
||||
// Scale animation: active card = 1.0, adjacent = 0.94
|
||||
return AnimatedBuilder(
|
||||
animation: _heroPageController,
|
||||
builder: (context, child) {
|
||||
double scale = index == _heroPageNotifier.value ? 1.0 : 0.94;
|
||||
if (_heroPageController.position.haveDimensions) {
|
||||
scale = (1.0 -
|
||||
(_heroPageController.page! - index).abs() * 0.06)
|
||||
.clamp(0.94, 1.0);
|
||||
}
|
||||
return Transform.scale(scale: scale, child: child);
|
||||
},
|
||||
child: _buildHeroEventImage(_heroEvents[index]),
|
||||
);
|
||||
},
|
||||
// ── Foreground content ──
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Top bar: location pill + search button
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: _openLocationSearch,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.15),
|
||||
borderRadius: BorderRadius.circular(25),
|
||||
border: Border.all(color: Colors.white.withOpacity(0.2)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.location_on_outlined, color: Colors.white, size: 18),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
_location.length > 20 ? '${_location.substring(0, 20)}...' : _location,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 14, fontWeight: FontWeight.w500),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
const Icon(Icons.keyboard_arrow_down, color: Colors.white, size: 18),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const NotificationBell(),
|
||||
const SizedBox(width: 8),
|
||||
GestureDetector(
|
||||
onTap: _openEventSearch,
|
||||
child: Container(
|
||||
width: 48,
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.15),
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(color: Colors.white.withOpacity(0.2)),
|
||||
),
|
||||
child: const Icon(Icons.search, color: Colors.white, size: 24),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Pagination dots
|
||||
_buildCarouselDots(),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Featured carousel
|
||||
_heroEvents.isEmpty
|
||||
? _loading
|
||||
? const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
child: SizedBox(
|
||||
height: 320,
|
||||
child: _HeroShimmer(),
|
||||
),
|
||||
)
|
||||
: const SizedBox(
|
||||
height: 280,
|
||||
child: Center(
|
||||
child: Text('No events available',
|
||||
style: TextStyle(color: Colors.white70)),
|
||||
),
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
RepaintBoundary(
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onPanDown: (_) => _autoScrollTimer?.cancel(),
|
||||
onPanEnd: (_) => _startAutoScroll(delay: const Duration(seconds: 3)),
|
||||
onPanCancel: () => _startAutoScroll(delay: const Duration(seconds: 3)),
|
||||
child: SizedBox(
|
||||
height: 320,
|
||||
child: PageView.builder(
|
||||
controller: _heroPageController,
|
||||
onPageChanged: (page) {
|
||||
_heroPageNotifier.value = page;
|
||||
// 8s delay after manual swipe for full read time
|
||||
_startAutoScroll(delay: const Duration(seconds: 8));
|
||||
},
|
||||
itemCount: _heroEvents.length,
|
||||
itemBuilder: (context, index) {
|
||||
// Scale animation: active card = 1.0, adjacent = 0.94
|
||||
return AnimatedBuilder(
|
||||
animation: _heroPageController,
|
||||
builder: (context, child) {
|
||||
double scale = index == _heroPageNotifier.value ? 1.0 : 0.94;
|
||||
if (_heroPageController.position.haveDimensions) {
|
||||
scale = (1.0 -
|
||||
(_heroPageController.page! - index).abs() * 0.06)
|
||||
.clamp(0.94, 1.0);
|
||||
}
|
||||
return Transform.scale(scale: scale, child: child);
|
||||
},
|
||||
child: _buildHeroEventImage(_heroEvents[index]),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Pagination dots
|
||||
_buildCarouselDots(),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -1390,13 +1442,13 @@ class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateM
|
||||
'source': 'hero_carousel',
|
||||
});
|
||||
Navigator.push(context,
|
||||
MaterialPageRoute(builder: (_) => LearnMoreScreen(eventId: event.id, initialEvent: event)));
|
||||
MaterialPageRoute(builder: (_) => LearnMoreScreen(eventId: event.id, initialEvent: event, heroTag: 'event-hero-${event.id}-carousel')));
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Hero(
|
||||
tag: 'event-hero-${event.id}',
|
||||
tag: 'event-hero-${event.id}-carousel',
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(radius),
|
||||
child: Stack(
|
||||
@@ -1815,11 +1867,11 @@ class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateM
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
if (event.id != null) {
|
||||
Navigator.push(context, MaterialPageRoute(builder: (_) => LearnMoreScreen(eventId: event.id, initialEvent: event)));
|
||||
Navigator.push(context, MaterialPageRoute(builder: (_) => LearnMoreScreen(eventId: event.id, initialEvent: event, heroTag: 'event-hero-${event.id}-top')));
|
||||
}
|
||||
},
|
||||
child: Hero(
|
||||
tag: 'event-hero-${event.id}',
|
||||
tag: 'event-hero-${event.id}-top',
|
||||
child: Container(
|
||||
width: 150,
|
||||
decoration: BoxDecoration(
|
||||
|
||||
Reference in New Issue
Block a user