perf: optimize home screen rendering with ListView.builder and improve image loading performance by persisting disk cache
This commit is contained in:
@@ -112,6 +112,8 @@ class _S3ImageState extends State<S3Image> {
|
|||||||
height: widget.height,
|
height: widget.height,
|
||||||
fit: widget.fit,
|
fit: widget.fit,
|
||||||
alignment: widget.alignment,
|
alignment: widget.alignment,
|
||||||
|
fadeInDuration: const Duration(milliseconds: 200),
|
||||||
|
fadeOutDuration: const Duration(milliseconds: 100),
|
||||||
placeholder: (ctx, _) => _buildPlaceholder(ctx),
|
placeholder: (ctx, _) => _buildPlaceholder(ctx),
|
||||||
errorWidget: (ctx, _, err) {
|
errorWidget: (ctx, _, err) {
|
||||||
// On error (expired URL), evict and retry once
|
// On error (expired URL), evict and retry once
|
||||||
|
|||||||
@@ -21,31 +21,25 @@ class HomeScreen extends ConsumerWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final scrollController = ref.watch(homeScrollControllerProvider);
|
final scrollController = ref.watch(homeScrollControllerProvider);
|
||||||
return SingleChildScrollView(
|
// Use ListView.builder for lazy rendering — only builds sections as
|
||||||
controller: scrollController,
|
// they scroll into view, instead of rendering all 5 heavy sections at
|
||||||
child: Column(
|
// once in a Column (which causes jank on initial load).
|
||||||
children: [
|
final sections = <Widget>[
|
||||||
// Hero Section with Search
|
const RepaintBoundary(child: HeroSection()),
|
||||||
const HeroSection(),
|
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
|
const RepaintBoundary(child: FeaturesSection()),
|
||||||
// Features Section
|
|
||||||
const FeaturesSection(),
|
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
|
const RepaintBoundary(child: TopProfessionalsSection()),
|
||||||
// Top Professionals Section (Agents/Lenders tabs)
|
|
||||||
const TopProfessionalsSection(),
|
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
|
const RepaintBoundary(child: TrustStatsSection()),
|
||||||
// Trust & Stats Section
|
|
||||||
const TrustStatsSection(),
|
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
|
const RepaintBoundary(child: TestimonialsSection()),
|
||||||
// Testimonials Section
|
|
||||||
const TestimonialsSection(),
|
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
],
|
];
|
||||||
),
|
return ListView.builder(
|
||||||
|
controller: scrollController,
|
||||||
|
itemCount: sections.length,
|
||||||
|
itemBuilder: (_, i) => sections[i],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
|
||||||
import 'package:firebase_core/firebase_core.dart';
|
import 'package:firebase_core/firebase_core.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:real_estate_mobile/config/app_config.dart';
|
import 'package:real_estate_mobile/config/app_config.dart';
|
||||||
import 'package:real_estate_mobile/config/firebase_config.dart';
|
import 'package:real_estate_mobile/config/firebase_config.dart';
|
||||||
@@ -15,13 +13,12 @@ Future<void> mainCommon(Flavor flavor) async {
|
|||||||
|
|
||||||
await Firebase.initializeApp(options: FirebaseConfig.currentOptions);
|
await Firebase.initializeApp(options: FirebaseConfig.currentOptions);
|
||||||
|
|
||||||
// Clear stale image caches on app start to ensure fresh presigned URLs
|
// Only clear the in-memory presigned URL cache — NOT the disk image cache.
|
||||||
|
// Presigned URLs expire after ~1 hour and are re-fetched lazily by
|
||||||
|
// ImageUrlResolver when needed. The disk cache (CachedNetworkImage) must
|
||||||
|
// persist across restarts for app smoothness — clearing it on every start
|
||||||
|
// forces every image to re-download, causing visible delay on all screens.
|
||||||
ImageUrlResolver.instance.clearCache();
|
ImageUrlResolver.instance.clearCache();
|
||||||
PaintingBinding.instance.imageCache.clear();
|
|
||||||
PaintingBinding.instance.imageCache.clearLiveImages();
|
|
||||||
// Also clear CachedNetworkImage disk cache so old presigned URLs
|
|
||||||
// (which may point to stale/wrong images) don't persist across sessions.
|
|
||||||
DefaultCacheManager().emptyCache();
|
|
||||||
|
|
||||||
runApp(const ProviderScope(child: MyApp()));
|
runApp(const ProviderScope(child: MyApp()));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user