From ecd82fab0a648c6919ee9b18e3605cd660ddc8cf Mon Sep 17 00:00:00 2001 From: Ariq Pradipa Santoso Date: Tue, 19 Aug 2025 07:04:36 +0700 Subject: [PATCH] fix: Improve GIF loading logic and handle HTTP image URLs in MxcImage widget --- lib/pages/chat/gif_picker_dialog.dart | 3 +- lib/utils/tenor_api.dart | 8 ++- lib/widgets/mxc_image.dart | 96 +++++++++++++++++++-------- 3 files changed, 77 insertions(+), 30 deletions(-) diff --git a/lib/pages/chat/gif_picker_dialog.dart b/lib/pages/chat/gif_picker_dialog.dart index 6078d643e..b5532d8c0 100644 --- a/lib/pages/chat/gif_picker_dialog.dart +++ b/lib/pages/chat/gif_picker_dialog.dart @@ -104,8 +104,9 @@ class GifPickerDialogState extends State { } Future _loadMoreGifs() async { - if (_isLoadingMore || !_hasMoreResults || isLoading || _nextPos == '0') + if (_isLoadingMore || !_hasMoreResults || isLoading || _nextPos == '0') { return; + } setState(() { _isLoadingMore = true; diff --git a/lib/utils/tenor_api.dart b/lib/utils/tenor_api.dart index ee26d5c18..93397e362 100644 --- a/lib/utils/tenor_api.dart +++ b/lib/utils/tenor_api.dart @@ -65,13 +65,15 @@ class TenorApiResponse { class TenorApi { static const String _baseUrl = 'https://tenor.googleapis.com/v2'; static const String _apiKey = - ''; // Test API key from documentation + 'AIzaSyC5xwpkbdAnIH4NSyjUwg_t9Huoy19YVH4'; // Test API key from documentation static const String _clientKey = 'fluffychat_app'; // Client key for integration tracking static const int _limit = 20; - static Future searchGifs(String query, - {String? pos}) async { + static Future searchGifs( + String query, { + String? pos, + }) async { if (query.trim().isEmpty) { return getFeaturedGifs(pos: pos); } diff --git a/lib/widgets/mxc_image.dart b/lib/widgets/mxc_image.dart index 1572fa6b9..8e1daa436 100644 --- a/lib/widgets/mxc_image.dart +++ b/lib/widgets/mxc_image.dart @@ -3,6 +3,7 @@ import 'dart:math'; import 'dart:typed_data'; import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; import 'package:matrix/matrix.dart'; @@ -75,36 +76,79 @@ class _MxcImageState extends State { final event = widget.event; if (uri != null) { - final devicePixelRatio = MediaQuery.devicePixelRatioOf(context); - final width = widget.width; - final realWidth = width == null ? null : width * devicePixelRatio; - final height = widget.height; - final realHeight = height == null ? null : height * devicePixelRatio; + // Handle direct HTTP/HTTPS URLs + if (uri.scheme == 'http' || uri.scheme == 'https') { + try { + final response = await http.get(uri); + if (response.statusCode == 200) { + if (!mounted) return; + setState(() { + _imageData = response.bodyBytes; + }); + return; + } + } catch (e) { + Logs().w('Failed to load HTTP image: $uri', e); + } + } else if (uri.scheme == 'mxc') { + // Handle MXC URLs + final devicePixelRatio = MediaQuery.devicePixelRatioOf(context); + final width = widget.width; + final realWidth = width == null ? null : width * devicePixelRatio; + final height = widget.height; + final realHeight = height == null ? null : height * devicePixelRatio; - final remoteData = await client.downloadMxcCached( - uri, - width: realWidth, - height: realHeight, - thumbnailMethod: widget.thumbnailMethod, - isThumbnail: widget.isThumbnail, - animated: widget.animated, - ); - if (!mounted) return; - setState(() { - _imageData = remoteData; - }); + final remoteData = await client.downloadMxcCached( + uri, + width: realWidth, + height: realHeight, + thumbnailMethod: widget.thumbnailMethod, + isThumbnail: widget.isThumbnail, + animated: widget.animated, + ); + if (!mounted) return; + setState(() { + _imageData = remoteData; + }); + } } if (event != null) { - final data = await event.downloadAndDecryptAttachment( - getThumbnail: widget.isThumbnail, - ); - if (data.detectFileType is MatrixImageFile || widget.isThumbnail) { - if (!mounted) return; - setState(() { - _imageData = data.bytes; - }); - return; + // Check if the event has a direct HTTP URL + final eventUrl = event.content.tryGet('url'); + if (eventUrl != null) { + final eventUri = Uri.tryParse(eventUrl); + if (eventUri != null && + (eventUri.scheme == 'http' || eventUri.scheme == 'https')) { + try { + final response = await http.get(eventUri); + if (response.statusCode == 200) { + if (!mounted) return; + setState(() { + _imageData = response.bodyBytes; + }); + return; + } + } catch (e) { + Logs().w('Failed to load HTTP image from event: $eventUrl', e); + } + } + } + + // Fallback to Matrix attachment handling for MXC URLs + try { + final data = await event.downloadAndDecryptAttachment( + getThumbnail: widget.isThumbnail, + ); + if (data.detectFileType is MatrixImageFile || widget.isThumbnail) { + if (!mounted) return; + setState(() { + _imageData = data.bytes; + }); + return; + } + } catch (e) { + Logs().w('Failed to download Matrix attachment', e); } } }