fix(car_card): cache signed URL future in state to prevent rebuild flashing
Co-authored-by: derkauzigekoala <79001016+derkauzigekoala@users.noreply.github.com>
This commit is contained in:
parent
18af2d1bf2
commit
587cd6c739
1 changed files with 49 additions and 21 deletions
|
|
@ -4,7 +4,7 @@ import '../services/storage_service.dart';
|
|||
import '../theme/app_colors.dart';
|
||||
|
||||
/// A styled card for displaying a single die-cast car in the garage.
|
||||
class CarCard extends StatelessWidget {
|
||||
class CarCard extends StatefulWidget {
|
||||
final String hwId;
|
||||
final String? name;
|
||||
final String? series;
|
||||
|
|
@ -36,22 +36,50 @@ class CarCard extends StatelessWidget {
|
|||
this.isSelected = false,
|
||||
});
|
||||
|
||||
@override
|
||||
State<CarCard> createState() => _CarCardState();
|
||||
}
|
||||
|
||||
class _CarCardState extends State<CarCard> {
|
||||
Future<String?>? _signedUrlFuture;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_initSignedUrlFuture();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(CarCard oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.imagePath != widget.imagePath) {
|
||||
_initSignedUrlFuture();
|
||||
}
|
||||
}
|
||||
|
||||
void _initSignedUrlFuture() {
|
||||
final hasImagePath = widget.imagePath != null && widget.imagePath!.isNotEmpty;
|
||||
_signedUrlFuture = hasImagePath
|
||||
? StorageService.createSignedUrl(widget.imagePath!)
|
||||
: null;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final isDark = theme.brightness == Brightness.dark;
|
||||
final resolvedImageUrl = imageUrl;
|
||||
final resolvedImageUrl = widget.imageUrl;
|
||||
final hasResolvedUrl = resolvedImageUrl != null && resolvedImageUrl.isNotEmpty;
|
||||
final hasImagePath = imagePath != null && imagePath!.isNotEmpty;
|
||||
final hasImagePath = widget.imagePath != null && widget.imagePath!.isNotEmpty;
|
||||
|
||||
return Card(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
color: isSelected
|
||||
color: widget.isSelected
|
||||
? AppColors.orange.withValues(alpha: 0.18)
|
||||
: Theme.of(context).cardTheme.color,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
onTap: widget.onTap,
|
||||
onLongPress: widget.onLongPress,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
|
@ -79,13 +107,13 @@ class CarCard extends StatelessWidget {
|
|||
fadeInDuration: Duration.zero,
|
||||
fadeOutDuration: Duration.zero,
|
||||
errorWidget: (context, url, error) {
|
||||
onImageError?.call();
|
||||
widget.onImageError?.call();
|
||||
return _PlaceholderIcon(isDark: isDark);
|
||||
},
|
||||
)
|
||||
: hasImagePath
|
||||
? FutureBuilder<String?>(
|
||||
future: StorageService.createSignedUrl(imagePath),
|
||||
future: _signedUrlFuture,
|
||||
builder: (context, snapshot) {
|
||||
final signedUrl = snapshot.data;
|
||||
if (signedUrl == null || signedUrl.isEmpty) {
|
||||
|
|
@ -97,7 +125,7 @@ class CarCard extends StatelessWidget {
|
|||
fadeInDuration: Duration.zero,
|
||||
fadeOutDuration: Duration.zero,
|
||||
errorWidget: (context, url, error) {
|
||||
onImageError?.call();
|
||||
widget.onImageError?.call();
|
||||
return _PlaceholderIcon(isDark: isDark);
|
||||
},
|
||||
);
|
||||
|
|
@ -113,7 +141,7 @@ class CarCard extends StatelessWidget {
|
|||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (isSelected)
|
||||
if (widget.isSelected)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 6),
|
||||
child: Row(
|
||||
|
|
@ -141,7 +169,7 @@ class CarCard extends StatelessWidget {
|
|||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Text(
|
||||
hwId,
|
||||
widget.hwId,
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w700,
|
||||
|
|
@ -154,19 +182,19 @@ class CarCard extends StatelessWidget {
|
|||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
isVerified
|
||||
widget.isVerified
|
||||
? Icons.verified
|
||||
: Icons.hourglass_bottom,
|
||||
size: 12,
|
||||
color: isVerified
|
||||
color: widget.isVerified
|
||||
? AppColors.success
|
||||
: AppColors.textHint,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
isVerified ? 'Verified' : 'Pending',
|
||||
widget.isVerified ? 'Verified' : 'Pending',
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: isVerified
|
||||
color: widget.isVerified
|
||||
? AppColors.success
|
||||
: AppColors.textHint,
|
||||
fontWeight: FontWeight.w600,
|
||||
|
|
@ -174,10 +202,10 @@ class CarCard extends StatelessWidget {
|
|||
),
|
||||
],
|
||||
),
|
||||
if (name != null && name!.isNotEmpty) ...[
|
||||
if (widget.name != null && widget.name!.isNotEmpty) ...[
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
name!,
|
||||
widget.name!,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
|
|
@ -185,10 +213,10 @@ class CarCard extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
],
|
||||
if (series != null && series!.isNotEmpty) ...[
|
||||
if (widget.series != null && widget.series!.isNotEmpty) ...[
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
series!,
|
||||
widget.series!,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
|
|
@ -196,7 +224,7 @@ class CarCard extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
],
|
||||
if (year != null) ...[
|
||||
if (widget.year != null) ...[
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
|
|
@ -204,7 +232,7 @@ class CarCard extends StatelessWidget {
|
|||
size: 12, color: AppColors.textHint),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'$year',
|
||||
'${widget.year}',
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: AppColors.textHint,
|
||||
),
|
||||
|
|
|
|||
Loading…
Reference in a new issue