From a7f3bb26ad6929725266a5cdf015f16724515435 Mon Sep 17 00:00:00 2001 From: Hank Grabowski Date: Mon, 20 Mar 2023 10:06:44 -0400 Subject: [PATCH] Add logged-in profile aware image control wrapping CachedNetworkImage --- .../gallery_selector_control.dart | 4 +- lib/controls/image_control.dart | 4 +- .../login_aware_cached_network_image.dart | 43 +++++++++++++++++++ lib/controls/standard_app_drawer.dart | 5 ++- .../media_upload_attachment.dart | 5 ++- lib/screens/editor.dart | 5 ++- .../existing_image_selector_screen.dart | 4 +- .../follow_request_adjudication_screen.dart | 4 +- lib/screens/gallery_screen.dart | 4 +- lib/screens/home.dart | 4 +- lib/screens/image_viewer_screen.dart | 4 +- lib/screens/user_profile_screen.dart | 5 ++- .../link_preview_friendica_extensions.dart | 8 +++- lib/utils/string_utils.dart | 5 +++ 14 files changed, 81 insertions(+), 23 deletions(-) create mode 100644 lib/controls/login_aware_cached_network_image.dart diff --git a/lib/controls/entry_media_attachments/gallery_selector_control.dart b/lib/controls/entry_media_attachments/gallery_selector_control.dart index b50081f..8a2bf98 100644 --- a/lib/controls/entry_media_attachments/gallery_selector_control.dart +++ b/lib/controls/entry_media_attachments/gallery_selector_control.dart @@ -1,4 +1,3 @@ -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import '../../globals.dart'; @@ -6,6 +5,7 @@ import '../../models/image_entry.dart'; import '../../screens/existing_image_selector_screen.dart'; import '../../screens/image_viewer_screen.dart'; import '../../serializers/friendica/image_entry_friendica_extensions.dart'; +import '../login_aware_cached_network_image.dart'; import '../padding.dart'; class GallerySelectorControl extends StatefulWidget { @@ -76,7 +76,7 @@ class _GallerySelectorControlState extends State { }); } }, - child: CachedNetworkImage( + child: LoginAwareCachedNetworkImage( width: thumbnailSize, height: thumbnailSize, imageUrl: item.thumbnailUrl, diff --git a/lib/controls/image_control.dart b/lib/controls/image_control.dart index c2394d1..b7500c5 100644 --- a/lib/controls/image_control.dart +++ b/lib/controls/image_control.dart @@ -1,8 +1,8 @@ -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../services/setting_service.dart'; +import 'login_aware_cached_network_image.dart'; final _shownImageUrls = {}; @@ -43,7 +43,7 @@ class _ImageControlState extends State { late final Widget image; if (shown) { _shownImageUrls.add(widget.imageUrl); - image = CachedNetworkImage( + image = LoginAwareCachedNetworkImage( imageUrl: widget.imageUrl, width: widget.width, height: widget.height, diff --git a/lib/controls/login_aware_cached_network_image.dart b/lib/controls/login_aware_cached_network_image.dart new file mode 100644 index 0000000..f8bb5c1 --- /dev/null +++ b/lib/controls/login_aware_cached_network_image.dart @@ -0,0 +1,43 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; +import 'package:logging/logging.dart'; +import 'package:provider/provider.dart'; + +import '../services/auth_service.dart'; + +class LoginAwareCachedNetworkImage extends StatelessWidget { + static final _logger = Logger('$LoginAwareCachedNetworkImage'); + final String imageUrl; + final double? width; + final double? height; + + const LoginAwareCachedNetworkImage({ + super.key, + required this.imageUrl, + this.width, + this.height, + }); + + @override + Widget build(BuildContext context) { + final profile = context.watch().currentProfile; + + Map? headers; + + try { + final imageServer = Uri.parse(imageUrl).host; + if (imageServer == profile.serverName) { + headers = {'Authorization': profile.credentials.authHeaderValue}; + } + } catch (e) { + _logger.severe('Error Parsing ImageURL: $e'); + } + + return CachedNetworkImage( + httpHeaders: headers, + imageUrl: imageUrl, + width: width, + height: height, + ); + } +} diff --git a/lib/controls/standard_app_drawer.dart b/lib/controls/standard_app_drawer.dart index 7933385..bb4f0e4 100644 --- a/lib/controls/standard_app_drawer.dart +++ b/lib/controls/standard_app_drawer.dart @@ -1,10 +1,10 @@ -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import '../globals.dart'; import '../routes.dart'; import '../services/auth_service.dart'; +import 'login_aware_cached_network_image.dart'; class StandardAppDrawer extends StatelessWidget { @override @@ -23,7 +23,8 @@ class StandardAppDrawer extends StatelessWidget { } }, leading: CircleAvatar( - child: CachedNetworkImage(imageUrl: p.avatar)), + child: + LoginAwareCachedNetworkImage(imageUrl: p.avatar)), title: Text( p.username, style: p == getIt().currentProfile diff --git a/lib/models/media_attachment_uploads/media_upload_attachment.dart b/lib/models/media_attachment_uploads/media_upload_attachment.dart index 89401a2..45c5c64 100644 --- a/lib/models/media_attachment_uploads/media_upload_attachment.dart +++ b/lib/models/media_attachment_uploads/media_upload_attachment.dart @@ -1,8 +1,9 @@ import 'dart:io'; -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; +import '../../controls/login_aware_cached_network_image.dart'; + class MediaUploadAttachment { final String localFilePath; @@ -37,7 +38,7 @@ class MediaUploadAttachment { Widget getPreviewImage() { if (isExistingServerItem) { - return CachedNetworkImage(imageUrl: remoteUrl); + return LoginAwareCachedNetworkImage(imageUrl: remoteUrl); } return Image.file(File(localFilePath)); diff --git a/lib/screens/editor.dart b/lib/screens/editor.dart index 0aaac70..8dfecba 100644 --- a/lib/screens/editor.dart +++ b/lib/screens/editor.dart @@ -1,4 +1,3 @@ -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; import 'package:go_router/go_router.dart'; @@ -11,6 +10,7 @@ import '../controls/autocomplete/hashtag_autocomplete_options.dart'; import '../controls/autocomplete/mention_autocomplete_options.dart'; import '../controls/entry_media_attachments/gallery_selector_control.dart'; import '../controls/entry_media_attachments/media_uploads_control.dart'; +import '../controls/login_aware_cached_network_image.dart'; import '../controls/padding.dart'; import '../controls/standard_appbar.dart'; import '../controls/timeline/status_header_control.dart'; @@ -504,7 +504,8 @@ class _EditorScreenState extends State { final currentImage = Container( width: width, height: height, - child: CachedNetworkImage(imageUrl: preview.selectedImageUrl)); + child: + LoginAwareCachedNetworkImage(imageUrl: preview.selectedImageUrl)); if (preview.availableImageUrls.length < 2) { return currentImage; diff --git a/lib/screens/existing_image_selector_screen.dart b/lib/screens/existing_image_selector_screen.dart index ccfc7ed..3aebb25 100644 --- a/lib/screens/existing_image_selector_screen.dart +++ b/lib/screens/existing_image_selector_screen.dart @@ -1,7 +1,7 @@ -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import '../controls/login_aware_cached_network_image.dart'; import '../models/gallery_data.dart'; import '../models/image_entry.dart'; import '../serializers/friendica/image_entry_friendica_extensions.dart'; @@ -118,7 +118,7 @@ class _ExistingImageSelectorScreenState nextPageOnly: true, ); } - final imageWidget = CachedNetworkImage( + final imageWidget = LoginAwareCachedNetworkImage( imageUrl: image.thumbnailUrl, ); final selected = selectedImages.contains(image); diff --git a/lib/screens/follow_request_adjudication_screen.dart b/lib/screens/follow_request_adjudication_screen.dart index 72bc515..00ef74c 100644 --- a/lib/screens/follow_request_adjudication_screen.dart +++ b/lib/screens/follow_request_adjudication_screen.dart @@ -1,9 +1,9 @@ -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import 'package:relatica/utils/active_profile_selector.dart'; +import '../controls/login_aware_cached_network_image.dart'; import '../controls/padding.dart'; import '../models/connection.dart'; import '../services/connections_manager.dart'; @@ -74,7 +74,7 @@ class _FollowRequestAdjudicationScreenState return Column( mainAxisAlignment: MainAxisAlignment.start, children: [ - CachedNetworkImage(imageUrl: contact.avatarUrl.toString()), + LoginAwareCachedNetworkImage(imageUrl: contact.avatarUrl.toString()), Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, diff --git a/lib/screens/gallery_screen.dart b/lib/screens/gallery_screen.dart index 85852ad..2444a41 100644 --- a/lib/screens/gallery_screen.dart +++ b/lib/screens/gallery_screen.dart @@ -1,8 +1,8 @@ -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:logging/logging.dart'; import 'package:provider/provider.dart'; +import '../controls/login_aware_cached_network_image.dart'; import '../controls/standard_appbar.dart'; import '../controls/status_and_refresh_button.dart'; import '../globals.dart'; @@ -122,7 +122,7 @@ class GalleryScreen extends StatelessWidget { ); })); }, - child: CachedNetworkImage( + child: LoginAwareCachedNetworkImage( width: thumbnailDimension, height: thumbnailDimension, imageUrl: image.thumbnailUrl, diff --git a/lib/screens/home.dart b/lib/screens/home.dart index 4ce8766..cd97db0 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -1,4 +1,3 @@ -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:logging/logging.dart'; @@ -6,6 +5,7 @@ import 'package:provider/provider.dart'; import '../controls/app_bottom_nav_bar.dart'; import '../controls/linear_status_indicator.dart'; +import '../controls/login_aware_cached_network_image.dart'; import '../controls/padding.dart'; import '../controls/standard_app_drawer.dart'; import '../controls/timeline/timeline_panel.dart'; @@ -86,7 +86,7 @@ class _HomeScreenState extends State { onPressed: () { Scaffold.of(context).openDrawer(); }, - icon: CachedNetworkImage( + icon: LoginAwareCachedNetworkImage( imageUrl: accountService.currentProfile.avatar)); }) : null, diff --git a/lib/screens/image_viewer_screen.dart b/lib/screens/image_viewer_screen.dart index 60422f2..9050df9 100644 --- a/lib/screens/image_viewer_screen.dart +++ b/lib/screens/image_viewer_screen.dart @@ -1,6 +1,5 @@ import 'dart:io'; -import 'package:cached_network_image/cached_network_image.dart'; import 'package:carousel_slider/carousel_slider.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; @@ -8,6 +7,7 @@ import 'package:flutter_file_dialog/flutter_file_dialog.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; +import '../controls/login_aware_cached_network_image.dart'; import '../friendica_client/friendica_client.dart'; import '../globals.dart'; import '../models/media_attachment.dart'; @@ -101,7 +101,7 @@ class _ImageViewerScreenState extends State { child: InteractiveViewer( maxScale: 10.0, scaleFactor: 400, - child: CachedNetworkImage( + child: LoginAwareCachedNetworkImage( imageUrl: widget.attachments[index].uri.toString()), ), ); diff --git a/lib/screens/user_profile_screen.dart b/lib/screens/user_profile_screen.dart index 222839a..9ed91a0 100644 --- a/lib/screens/user_profile_screen.dart +++ b/lib/screens/user_profile_screen.dart @@ -1,10 +1,10 @@ -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import 'package:relatica/utils/active_profile_selector.dart'; +import '../controls/login_aware_cached_network_image.dart'; import '../controls/padding.dart'; import '../globals.dart'; import '../models/connection.dart'; @@ -59,7 +59,8 @@ class _UserProfileScreenState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, children: [ - CachedNetworkImage(imageUrl: profile.avatarUrl.toString()), + LoginAwareCachedNetworkImage( + imageUrl: profile.avatarUrl.toString()), Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, diff --git a/lib/serializers/friendica/link_preview_friendica_extensions.dart b/lib/serializers/friendica/link_preview_friendica_extensions.dart index 1cd2eb9..52085e4 100644 --- a/lib/serializers/friendica/link_preview_friendica_extensions.dart +++ b/lib/serializers/friendica/link_preview_friendica_extensions.dart @@ -1,3 +1,6 @@ +import 'package:relatica/utils/html_to_edit_text_helper.dart'; +import 'package:relatica/utils/string_utils.dart'; + import '../../models/link_preview_data.dart'; extension LinkPreviewExtension on LinkPreviewData { @@ -6,6 +9,9 @@ extension LinkPreviewExtension on LinkPreviewData { return "[attachment type='link' url='$link' title='$title']$description[/attachment]"; } - return "[attachment type='link' url='$link' title='$title' image='$selectedImageUrl']$description[/attachment]"; + final sanitizedTitle = toEditTextField(title).stripHyperlinks(); + final sanitizedDescription = toEditTextField(description).stripHyperlinks(); + + return "[attachment type='link' url='$link' title='$sanitizedTitle' image='$selectedImageUrl']$sanitizedDescription[/attachment]"; } } diff --git a/lib/utils/string_utils.dart b/lib/utils/string_utils.dart index 019e235..18cc265 100644 --- a/lib/utils/string_utils.dart +++ b/lib/utils/string_utils.dart @@ -6,4 +6,9 @@ extension StringUtils on String { return '${substring(0, length)}...'; } + + String stripHyperlinks() => + replaceAll(RegExp( + r"(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?"), + ""); }