From 3ce1f57d97f9a78d6ae324d01de4e7af9982a0be Mon Sep 17 00:00:00 2001 From: jld3103 Date: Sun, 2 Oct 2022 14:44:11 +0200 Subject: [PATCH] neon: Fix cached url images --- .../src/apps/news/widgets/articles_view.dart | 3 +- .../lib/src/apps/news/widgets/feed_icon.dart | 3 +- .../neon/lib/src/apps/notifications/app.dart | 2 + .../notifications/blocs/notifications.dart | 20 +-- .../src/apps/notifications/pages/main.dart | 3 +- packages/neon/lib/src/neon.dart | 2 +- packages/neon/lib/src/pages/home/home.dart | 10 +- .../lib/src/widgets/cached_url_image.dart | 126 ++++++++---------- packages/neon/pubspec.lock | 21 +++ packages/neon/pubspec.yaml | 1 + 10 files changed, 98 insertions(+), 93 deletions(-) diff --git a/packages/neon/lib/src/apps/news/widgets/articles_view.dart b/packages/neon/lib/src/apps/news/widgets/articles_view.dart index d8ed4540..039e1c44 100644 --- a/packages/neon/lib/src/apps/news/widgets/articles_view.dart +++ b/packages/neon/lib/src/apps/news/widgets/articles_view.dart @@ -181,8 +181,7 @@ class _NewsArticlesViewState extends State { if (article.mediaThumbnail != null) ...[ CachedURLImage( url: article.mediaThumbnail!, - requestManager: Provider.of(context), - client: RxBlocProvider.of(context).activeAccount.value!.client, + account: RxBlocProvider.of(context).activeAccount.value!, width: 100, height: 50, fit: BoxFit.cover, diff --git a/packages/neon/lib/src/apps/news/widgets/feed_icon.dart b/packages/neon/lib/src/apps/news/widgets/feed_icon.dart index de6925a2..1937da00 100644 --- a/packages/neon/lib/src/apps/news/widgets/feed_icon.dart +++ b/packages/neon/lib/src/apps/news/widgets/feed_icon.dart @@ -21,8 +21,7 @@ class NewsFeedIcon extends StatelessWidget { child: feed.faviconLink != null && feed.faviconLink != '' ? CachedURLImage( url: feed.faviconLink!, - requestManager: Provider.of(context), - client: RxBlocProvider.of(context).activeAccount.value!.client, + account: RxBlocProvider.of(context).activeAccount.value!, height: size, width: size, ) diff --git a/packages/neon/lib/src/apps/notifications/app.dart b/packages/neon/lib/src/apps/notifications/app.dart index c2fcb66d..10a3dcfd 100644 --- a/packages/neon/lib/src/apps/notifications/app.dart +++ b/packages/neon/lib/src/apps/notifications/app.dart @@ -1,10 +1,12 @@ library notifications; import 'package:flutter/material.dart'; +import 'package:flutter_rx_bloc/flutter_rx_bloc.dart'; import 'package:intersperse/intersperse.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; import 'package:neon/l10n/localizations.dart'; import 'package:neon/src/apps/notifications/blocs/notifications.dart'; +import 'package:neon/src/blocs/accounts.dart'; import 'package:neon/src/blocs/apps.dart'; import 'package:neon/src/neon.dart'; import 'package:nextcloud/nextcloud.dart'; diff --git a/packages/neon/lib/src/apps/notifications/blocs/notifications.dart b/packages/neon/lib/src/apps/notifications/blocs/notifications.dart index 12c19d34..633e1400 100644 --- a/packages/neon/lib/src/apps/notifications/blocs/notifications.dart +++ b/packages/neon/lib/src/apps/notifications/blocs/notifications.dart @@ -29,17 +29,17 @@ abstract class NotificationsBlocStates { class NotificationsBloc extends $NotificationsBloc { NotificationsBloc( this.options, - this.requestManager, - this.client, + this._requestManager, + this._client, ) { _$refreshEvent.listen((final _) => _loadNotifications()); _$deleteNotificationEvent.listen((final id) { - _wrapAction(() async => client.notifications.deleteNotification(id: id)); + _wrapAction(() async => _client.notifications.deleteNotification(id: id)); }); _$deleteAllNotificationsEvent.listen((final notification) { - _wrapAction(() async => client.notifications.deleteAllNotifications()); + _wrapAction(() async => _client.notifications.deleteAllNotifications()); }); _notificationsSubject.listen((final result) { @@ -52,7 +52,7 @@ class NotificationsBloc extends $NotificationsBloc { } void _wrapAction(final Future Function() call) { - final stream = requestManager.wrapWithoutCache(call).asBroadcastStream(); + final stream = _requestManager.wrapWithoutCache(call).asBroadcastStream(); stream.whereError().listen(_errorsStreamController.add); stream.whereSuccess().listen((final _) async { _loadNotifications(); @@ -60,11 +60,11 @@ class NotificationsBloc extends $NotificationsBloc { } void _loadNotifications() { - requestManager + _requestManager .wrapNextcloud, NotificationsListNotifications>( - client.id, + _client.id, 'notifications-notifications', - () async => client.notifications.listNotifications(), + () async => _client.notifications.listNotifications(), (final response) => response.ocs!.data!, previousData: _notificationsSubject.valueOrNull?.data, ) @@ -72,8 +72,8 @@ class NotificationsBloc extends $NotificationsBloc { } final NotificationsAppSpecificOptions options; - final RequestManager requestManager; - final NextcloudClient client; + final RequestManager _requestManager; + final NextcloudClient _client; final _notificationsSubject = BehaviorSubject>>(); final _errorsStreamController = StreamController(); diff --git a/packages/neon/lib/src/apps/notifications/pages/main.dart b/packages/neon/lib/src/apps/notifications/pages/main.dart index a83ca729..952c6916 100644 --- a/packages/neon/lib/src/apps/notifications/pages/main.dart +++ b/packages/neon/lib/src/apps/notifications/pages/main.dart @@ -115,8 +115,7 @@ class _NotificationsMainPageState extends State { height: 40, child: CachedURLImage( url: notification.icon!, - requestManager: widget.bloc.requestManager, - client: widget.bloc.client, + account: RxBlocProvider.of(context).activeAccount.value!, width: 40, height: 40, color: Theme.of(context).colorScheme.primary, diff --git a/packages/neon/lib/src/neon.dart b/packages/neon/lib/src/neon.dart index a4ba337f..628ec94c 100644 --- a/packages/neon/lib/src/neon.dart +++ b/packages/neon/lib/src/neon.dart @@ -11,13 +11,13 @@ import 'package:file_picker/file_picker.dart'; import 'package:filesize/filesize.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:flutter_file_dialog/flutter_file_dialog.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:flutter_rx_bloc/flutter_rx_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:http/http.dart'; -import 'package:http/http.dart' as http; import 'package:intl/intl_standalone.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; import 'package:neon/l10n/localizations.dart'; diff --git a/packages/neon/lib/src/pages/home/home.dart b/packages/neon/lib/src/pages/home/home.dart index 76360dd3..1b31d117 100644 --- a/packages/neon/lib/src/pages/home/home.dart +++ b/packages/neon/lib/src/pages/home/home.dart @@ -24,7 +24,6 @@ class _HomePageState extends State with tray.TrayListener, WindowListe late NeonPlatform _platform; late GlobalOptions _globalOptions; - late RequestManager _requestManager; late CapabilitiesBloc _capabilitiesBloc; late AppsBloc _appsBloc; @@ -46,9 +45,8 @@ class _HomePageState extends State with tray.TrayListener, WindowListe windowManager.addListener(this); } - _requestManager = Provider.of(context, listen: false); _capabilitiesBloc = CapabilitiesBloc( - _requestManager, + Provider.of(context, listen: false), widget.account.client, ); _capabilitiesBloc.capabilities.listen((final result) async { @@ -446,8 +444,7 @@ class _HomePageState extends State with tray.TrayListener, WindowListe Flexible( child: CachedURLImage( url: capabilitiesData.capabilities!.theming!.logo!, - requestManager: _requestManager, - client: widget.account.client, + account: widget.account, ), ), ], @@ -633,8 +630,7 @@ class _HomePageState extends State with tray.TrayListener, WindowListe child: capabilitiesData?.capabilities?.theming?.logo != null ? CachedURLImage( url: capabilitiesData!.capabilities!.theming!.logo!, - requestManager: _requestManager, - client: widget.account.client, + account: widget.account, ) : null, ) diff --git a/packages/neon/lib/src/widgets/cached_url_image.dart b/packages/neon/lib/src/widgets/cached_url_image.dart index 551ba5dd..ddcd36f1 100644 --- a/packages/neon/lib/src/widgets/cached_url_image.dart +++ b/packages/neon/lib/src/widgets/cached_url_image.dart @@ -1,10 +1,11 @@ part of '../neon.dart'; +final _cacheManager = DefaultCacheManager(); + class CachedURLImage extends StatelessWidget { const CachedURLImage({ required this.url, - required this.requestManager, - required this.client, + required this.account, this.height, this.width, this.fit, @@ -13,8 +14,7 @@ class CachedURLImage extends StatelessWidget { }); final String url; - final RequestManager requestManager; - final NextcloudClient client; + final Account account; final double? height; final double? width; @@ -24,71 +24,59 @@ class CachedURLImage extends StatelessWidget { final Color? color; @override - Widget build(final BuildContext context) => SizedBox( - height: height, - width: width, - child: Center( - child: ResultStreamBuilder( - // TODO: Cache this properly. It was not working in listviews where the old image was still rendered in the same index, until it was scrolled out of view. - stream: requestManager.wrapBytes( - client.id, - 'image-${base64.encode(url.codeUnits)}', - () async => (await http.get( - Uri.parse(url), - headers: client.baseHeaders, - )) - .bodyBytes, - preferCache: true, - ), - builder: ( - final context, - final data, - final error, - final loading, - ) => - Stack( - children: [ - if (data != null) ...[ - SizedBox( - height: height, - width: width, - child: Builder( - builder: (final context) { - try { - // TODO: Is this safe enough? Research in XML spec if a space is allowed between the < and the tag name - if (utf8.decode(data).contains(' FutureBuilder( + // Really weird false positive + // ignore: discarded_futures + future: _cacheManager.getSingleFile( + url, + headers: account.client.baseHeaders, ), + builder: (final context, final fileSnapshot) { + if (fileSnapshot.hasData) { + final content = fileSnapshot.data!.readAsBytesSync(); + + var isSvg = false; + if (Uri.parse(url).path.endsWith('.svg')) { + isSvg = true; + } + if (!isSvg) { + try { + // TODO: Is this safe enough? + if (utf8.decode(content).contains('