diff --git a/lib/screens/calendar_screen.dart b/lib/screens/calendar_screen.dart index 7fc7431..86ae38c 100644 --- a/lib/screens/calendar_screen.dart +++ b/lib/screens/calendar_screen.dart @@ -1,6 +1,7 @@ // lib/screens/calendar_screen.dart import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +import 'package:cached_network_image/cached_network_image.dart'; import '../features/events/services/events_service.dart'; import '../features/events/models/event_models.dart'; import 'learn_more_screen.dart'; @@ -511,7 +512,16 @@ class _CalendarScreenState extends State { children: [ ClipRRect( borderRadius: const BorderRadius.vertical(top: Radius.circular(14)), - child: imgUrl != null ? Image.network(imgUrl, height: 150, width: double.infinity, fit: BoxFit.cover, errorBuilder: (_, __, ___) => Container(height: 150, color: theme.dividerColor)) : Container(height: 150, color: theme.dividerColor, child: Icon(Icons.event, size: 44, color: theme.hintColor)), + child: imgUrl != null + ? CachedNetworkImage( + imageUrl: imgUrl, + height: 150, + width: double.infinity, + fit: BoxFit.cover, + placeholder: (_, __) => Container(height: 150, color: theme.dividerColor), + errorWidget: (_, __, ___) => Container(height: 150, color: theme.dividerColor), + ) + : Container(height: 150, color: theme.dividerColor, child: Icon(Icons.event, size: 44, color: theme.hintColor)), ), Padding( padding: const EdgeInsets.fromLTRB(12, 12, 12, 14), diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index a41afaa..6847983 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -1216,10 +1216,12 @@ class _HomeScreenState extends State with SingleTickerProviderStateM child: SizedBox( width: double.infinity, child: img != null && img.isNotEmpty - ? Image.network( - img, + ? CachedNetworkImage( + imageUrl: img, fit: BoxFit.cover, - errorBuilder: (context, error, stackTrace) => + placeholder: (_, __) => Container( + decoration: const BoxDecoration(color: Color(0xFF1A2A4A))), + errorWidget: (_, __, ___) => Container(decoration: AppDecoration.blueGradientRounded(radius)), ) : Container( diff --git a/lib/screens/learn_more_screen.dart b/lib/screens/learn_more_screen.dart index be4cb3f..9494529 100644 --- a/lib/screens/learn_more_screen.dart +++ b/lib/screens/learn_more_screen.dart @@ -223,9 +223,10 @@ class _LearnMoreScreenState extends State { ); } - final screenHeight = MediaQuery.of(context).size.height; + final mediaQuery = MediaQuery.of(context); + final screenHeight = mediaQuery.size.height; final imageHeight = screenHeight * 0.45; - final topPadding = MediaQuery.of(context).padding.top; + final topPadding = mediaQuery.padding.top; return Scaffold( backgroundColor: theme.scaffoldBackgroundColor, @@ -355,6 +356,7 @@ class _LearnMoreScreenState extends State { // --------------------------------------------------------------------------- Widget _buildLoadingShimmer(ThemeData theme) { + final shimmerHeight = MediaQuery.of(context).size.height; return SafeArea( child: Padding( padding: const EdgeInsets.all(20), @@ -363,7 +365,7 @@ class _LearnMoreScreenState extends State { children: [ // Placeholder image Container( - height: MediaQuery.of(context).size.height * 0.42, + height: shimmerHeight * 0.42, decoration: BoxDecoration( color: theme.dividerColor.withOpacity(0.3), borderRadius: BorderRadius.circular(28), diff --git a/lib/screens/profile_screen.dart b/lib/screens/profile_screen.dart index 9916633..3e38aae 100644 --- a/lib/screens/profile_screen.dart +++ b/lib/screens/profile_screen.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; @@ -273,6 +274,7 @@ class _ProfileScreenState extends State final result = await showDialog( context: context, builder: (ctx) { + // Note: ctl is disposed after dialog closes below final theme = Theme.of(ctx); return AlertDialog( title: const Text('Enter image path or URL'), @@ -305,6 +307,7 @@ class _ProfileScreenState extends State }, ); + ctl.dispose(); if (result == null || result.isEmpty) return; await _saveProfile(_username, _email, result); } @@ -318,6 +321,7 @@ class _ProfileScreenState extends State isScrollControlled: true, backgroundColor: Colors.transparent, builder: (ctx) { + // nameCtl and emailCtl are disposed via .then() below final theme = Theme.of(ctx); return DraggableScrollableSheet( expand: false, @@ -419,7 +423,10 @@ class _ProfileScreenState extends State }, ); }, - ); + ).then((_) { + nameCtl.dispose(); + emailCtl.dispose(); + }); } // ───────── Avatar builder (reused, with size param) ───────── @@ -428,11 +435,14 @@ class _ProfileScreenState extends State final path = _profileImage.trim(); if (path.startsWith('http')) { return ClipOval( - child: Image.network(path, + child: CachedNetworkImage( + imageUrl: path, width: size, height: size, fit: BoxFit.cover, - errorBuilder: (_, __, ___) => + placeholder: (_, __) => + Container(width: size, height: size, color: const Color(0xFFE5E7EB)), + errorWidget: (_, __, ___) => Icon(Icons.person, size: size / 2, color: Colors.grey))); } if (kIsWeb) { @@ -497,11 +507,16 @@ class _ProfileScreenState extends State if (imageUrl.startsWith('http')) { return ClipRRect( borderRadius: BorderRadius.circular(12), - child: Image.network(imageUrl, + child: CachedNetworkImage( + imageUrl: imageUrl, width: 60, height: 60, fit: BoxFit.cover, - errorBuilder: (_, __, ___) => Container( + placeholder: (_, __) => Container( + width: 60, + height: 60, + color: const Color(0xFFE5E7EB)), + errorWidget: (_, __, ___) => Container( width: 60, height: 60, color: theme.dividerColor, diff --git a/lib/screens/search_screen.dart b/lib/screens/search_screen.dart index 6f8f146..bae9bba 100644 --- a/lib/screens/search_screen.dart +++ b/lib/screens/search_screen.dart @@ -305,9 +305,11 @@ class _SearchScreenState extends State { child: Center(child: Text('No results found', style: TextStyle(color: Colors.grey[500]))), ) else - ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), + ConstrainedBox( + constraints: const BoxConstraints(maxHeight: 320), + child: ListView.separated( + shrinkWrap: false, + physics: const ClampingScrollPhysics(), itemCount: _searchResults.length, separatorBuilder: (_, __) => Divider(color: Colors.grey[200], height: 1), itemBuilder: (ctx, idx) { @@ -326,6 +328,7 @@ class _SearchScreenState extends State { ); }, ), + ), ] else ...[ const Text('Popular Cities', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16, color: Color(0xFF1A1A2E))), const SizedBox(height: 12),