minio fix
Some checks are pending
Web App CI / test (push) Waiting to run
Web App CI / build (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions
Some checks are pending
Web App CI / test (push) Waiting to run
Web App CI / build (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions
This commit is contained in:
parent
275ff88615
commit
9ed1a00a38
1 changed files with 117 additions and 7 deletions
|
|
@ -173,6 +173,22 @@ class _ExpiringCardImageState extends State<ExpiringCardImage> {
|
|||
);
|
||||
|
||||
if (mounted) {
|
||||
// Clear cache for old URL before updating
|
||||
if (_currentUrl != null && widget.useCachedNetworkImage) {
|
||||
try {
|
||||
await CachedNetworkImage.evictFromCache(_currentUrl!);
|
||||
log(
|
||||
'Cleared cache for old URL: $_currentUrl',
|
||||
name: 'ExpiringCardImage',
|
||||
);
|
||||
} catch (e) {
|
||||
log(
|
||||
'Failed to clear cache: $e',
|
||||
name: 'ExpiringCardImage',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_currentUrl = newUrl;
|
||||
_isRefreshing = false;
|
||||
|
|
@ -194,22 +210,111 @@ class _ExpiringCardImageState extends State<ExpiringCardImage> {
|
|||
}
|
||||
|
||||
bool _isExpiredError(dynamic error) {
|
||||
// Check if error is a 403 or 404 (expired or not found)
|
||||
if (error is Exception) {
|
||||
final errorString = error.toString().toLowerCase();
|
||||
return errorString.contains('403') ||
|
||||
errorString.contains('forbidden') ||
|
||||
errorString.contains('expired');
|
||||
if (error == null) return false;
|
||||
|
||||
// Log error details for debugging
|
||||
log(
|
||||
'Checking error for 403/expired: type=${error.runtimeType}, value=$error',
|
||||
name: 'ExpiringCardImage',
|
||||
);
|
||||
|
||||
// Check error string representation for HTTP status codes
|
||||
final errorString = error.toString().toLowerCase();
|
||||
final contains403 = errorString.contains('403') ||
|
||||
errorString.contains('forbidden') ||
|
||||
errorString.contains('expired') ||
|
||||
errorString.contains('http status 403') ||
|
||||
errorString.contains('status code 403');
|
||||
|
||||
if (contains403) {
|
||||
log(
|
||||
'Detected expired error: $errorString',
|
||||
name: 'ExpiringCardImage',
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to extract status code from error object if it has statusCode property
|
||||
try {
|
||||
final statusCode = (error as dynamic).statusCode;
|
||||
if (statusCode != null) {
|
||||
final code = statusCode is int ? statusCode : int.tryParse(statusCode.toString());
|
||||
if (code == 403 || code == 401) {
|
||||
log(
|
||||
'Detected expired error via statusCode: $code',
|
||||
name: 'ExpiringCardImage',
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
// statusCode property doesn't exist, continue
|
||||
}
|
||||
|
||||
// Try to check if error has response property with statusCode
|
||||
try {
|
||||
final response = (error as dynamic).response;
|
||||
if (response != null) {
|
||||
final statusCode = (response as dynamic).statusCode;
|
||||
if (statusCode != null) {
|
||||
final code = statusCode is int ? statusCode : int.tryParse(statusCode.toString());
|
||||
if (code == 403 || code == 401) {
|
||||
log(
|
||||
'Detected expired error via response.statusCode: $code',
|
||||
name: 'ExpiringCardImage',
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
// response property doesn't exist, continue
|
||||
}
|
||||
|
||||
// Check if error is a NetworkImageLoadException (Flutter's image loading error)
|
||||
try {
|
||||
if (error.toString().contains('NetworkImageLoadException') ||
|
||||
error.toString().contains('Failed to load network image')) {
|
||||
// For network image errors, assume it might be 403 if we have a valid objectId
|
||||
final objectId = _getObjectId();
|
||||
if (objectId != null && _isUuid(objectId)) {
|
||||
log(
|
||||
'Detected NetworkImageLoadException with valid objectId, assuming expired',
|
||||
name: 'ExpiringCardImage',
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
// Continue
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Widget _buildErrorWidget(BuildContext context, String url, dynamic error) {
|
||||
// Log error for debugging
|
||||
log(
|
||||
'Error widget called: url=$url, error=$error, errorType=${error?.runtimeType}',
|
||||
name: 'ExpiringCardImage',
|
||||
);
|
||||
|
||||
// Check if we can refresh the URL
|
||||
final objectId = _getObjectId();
|
||||
final canRefresh = objectId != null && _isUuid(objectId) && _isExpiredError(error);
|
||||
final isExpired = _isExpiredError(error);
|
||||
final hasValidObjectId = objectId != null && _isUuid(objectId);
|
||||
final canRefresh = hasValidObjectId && isExpired;
|
||||
|
||||
log(
|
||||
'Refresh check: objectId=$objectId, isUuid=$hasValidObjectId, isExpired=$isExpired, canRefresh=$canRefresh, isRefreshing=$_isRefreshing',
|
||||
name: 'ExpiringCardImage',
|
||||
);
|
||||
|
||||
if (canRefresh && !_isRefreshing) {
|
||||
log(
|
||||
'Scheduling presigned URL refresh for objectId: $objectId',
|
||||
name: 'ExpiringCardImage',
|
||||
);
|
||||
// Automatically try to refresh
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_refreshPresignedUrl();
|
||||
|
|
@ -238,7 +343,9 @@ class _ExpiringCardImageState extends State<ExpiringCardImage> {
|
|||
}
|
||||
|
||||
if (widget.useCachedNetworkImage) {
|
||||
// Use key based on URL to force rebuild when URL changes
|
||||
return CachedNetworkImage(
|
||||
key: ValueKey('cached_image_$_currentUrl'),
|
||||
imageUrl: _currentUrl!,
|
||||
fit: widget.fit,
|
||||
width: widget.width,
|
||||
|
|
@ -249,10 +356,13 @@ class _ExpiringCardImageState extends State<ExpiringCardImage> {
|
|||
fadeOutDuration: widget.fadeOutDuration,
|
||||
placeholder: widget.placeholder ?? (context, url) => const SizedBox.shrink(),
|
||||
errorWidget: _buildErrorWidget,
|
||||
// Clear cache on error to allow retry with new URL
|
||||
cacheKey: _currentUrl,
|
||||
);
|
||||
} else {
|
||||
return Image.network(
|
||||
_currentUrl!,
|
||||
key: ValueKey('network_image_$_currentUrl'),
|
||||
fit: widget.fit,
|
||||
width: widget.width,
|
||||
height: widget.height,
|
||||
|
|
|
|||
Loading…
Reference in a new issue