fix: web thumbnail loading - bypass signing on web, add fallback, improve error handling

This commit is contained in:
Patrick Britton 2026-02-09 14:45:43 -06:00
parent d43cf2de06
commit 2377899d72
2 changed files with 38 additions and 1 deletions

View file

@ -938,8 +938,15 @@ class ApiService {
// ========================================================================= // =========================================================================
Future<String> getSignedMediaUrl(String path) async { Future<String> getSignedMediaUrl(String path) async {
// For web platform, return the original URL since signing isn't needed
// for public CDN domains
if (path.startsWith('http')) {
return path;
}
// Migrate to Go API / Nginx Signed URLs // Migrate to Go API / Nginx Signed URLs
return '${ApiConfig.baseUrl}/media/signed?path=$path'; // Placeholder // TODO: Implement proper signed URL generation
return '${ApiConfig.baseUrl}/media/signed?path=$path';
} }
Future<Map<String, dynamic>> toggleReaction(String postId, String emoji) async { Future<Map<String, dynamic>> toggleReaction(String postId, String emoji) async {

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter/foundation.dart';
import '../../providers/api_provider.dart'; import '../../providers/api_provider.dart';
class SignedMediaImage extends ConsumerStatefulWidget { class SignedMediaImage extends ConsumerStatefulWidget {
@ -62,6 +63,11 @@ class _SignedMediaImageState extends ConsumerState<SignedMediaImage> {
final trimmed = url.trim(); final trimmed = url.trim();
if (trimmed.isEmpty) return false; if (trimmed.isEmpty) return false;
// On web platform, prefer direct URLs without signing for better performance
if (kIsWeb) {
return false;
}
final uri = Uri.tryParse(trimmed); final uri = Uri.tryParse(trimmed);
if (uri == null || (!uri.hasScheme && !uri.hasAuthority)) { if (uri == null || (!uri.hasScheme && !uri.hasAuthority)) {
return true; return true;
@ -159,6 +165,15 @@ class _SignedMediaImageState extends ConsumerState<SignedMediaImage> {
return _buildLoading(context); return _buildLoading(context);
}, },
errorBuilder: (context, error, stackTrace) { errorBuilder: (context, error, stackTrace) {
// Debug: log the error and URL info
if (kDebugMode) {
print('SignedMediaImage error: $error');
print('Original URL: ${widget.url}');
print('Resolved URL: $_resolvedUrl');
print('Needs signing: $_shouldSign');
print('Platform: ${kIsWeb ? "web" : "native"}');
}
if (_shouldSign && !_refreshing && !_hasRefreshed) { if (_shouldSign && !_refreshing && !_hasRefreshed) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return; if (!mounted) return;
@ -171,6 +186,21 @@ class _SignedMediaImageState extends ConsumerState<SignedMediaImage> {
return widget.errorBuilder!(context, error, stackTrace); return widget.errorBuilder!(context, error, stackTrace);
} }
// On web, try fallback to direct URL if signing failed
if (kIsWeb && _shouldSign && _resolvedUrl == null) {
return Image.network(
widget.url,
width: widget.width,
height: widget.height,
fit: widget.fit,
errorBuilder: widget.errorBuilder,
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return _buildLoading(context);
},
);
}
return const SizedBox.shrink(); return const SizedBox.shrink();
}, },
); );