From 8f1119525b70d7a26f8f45fca7747837acbeac7a Mon Sep 17 00:00:00 2001 From: Aman Raj Singh Mourya Date: Mon, 27 May 2024 14:38:48 +0530 Subject: [PATCH 01/22] [mob][photos] placeholder for link 1st draft --- mobile/lib/ui/TEMP/captureImage.dart | 65 ++ mobile/lib/ui/TEMP/show_images_prevew.dart | 790 ++++++++++++++++++ mobile/lib/ui/TEMP/widget_to_image.dart | 19 + .../collection_sharing_actions.dart | 1 + .../file_selection_actions_widget.dart | 36 +- mobile/lib/utils/share_util.dart | 8 + 6 files changed, 918 insertions(+), 1 deletion(-) create mode 100644 mobile/lib/ui/TEMP/captureImage.dart create mode 100644 mobile/lib/ui/TEMP/show_images_prevew.dart create mode 100644 mobile/lib/ui/TEMP/widget_to_image.dart diff --git a/mobile/lib/ui/TEMP/captureImage.dart b/mobile/lib/ui/TEMP/captureImage.dart new file mode 100644 index 0000000000..65aec5a6ad --- /dev/null +++ b/mobile/lib/ui/TEMP/captureImage.dart @@ -0,0 +1,65 @@ +// import "dart:typed_data"; +// import 'dart:ui' as ui; + +// import 'package:flutter/material.dart'; +// import 'package:flutter/rendering.dart'; + +// class Captures { +// static Future capture(GlobalKey key) async { +// final double pixelRatio = +// MediaQuery.of(key.currentContext!).devicePixelRatio; +// final RenderRepaintBoundary boundary = +// key.currentContext!.findRenderObject()! as RenderRepaintBoundary; +// final ui.Image image = await boundary.toImage(pixelRatio: pixelRatio); +// final ByteData? byteData = +// await image.toByteData(format: ui.ImageByteFormat.png); +// final Uint8List pngBytes = byteData!.buffer.asUint8List(); +// print("PNG BYTES ====== ${pngBytes}"); +// return pngBytes; +// } +// } +import "dart:io"; +import 'dart:typed_data'; +import 'dart:ui' as ui; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import "package:path_provider/path_provider.dart"; + +class Captures { + Future capture(GlobalKey key) async { + try { + final double pixelRatio = + MediaQuery.of(key.currentContext!).devicePixelRatio; + final RenderRepaintBoundary boundary = + key.currentContext!.findRenderObject()! as RenderRepaintBoundary; + final ui.Image image = await boundary.toImage(pixelRatio: pixelRatio); + final ByteData? byteData = + await image.toByteData(format: ui.ImageByteFormat.png); + final Uint8List pngBytes = byteData!.buffer.asUint8List(); + print("PNG BYTES ====== ${pngBytes}"); + + return pngBytes; + } catch (e) { + print(e); + } + return null; + } + + Future saveImage(GlobalKey key) async { + String path = ""; + try { + final Uint8List? bytes = await capture(key); + final Directory root = await getTemporaryDirectory(); + final String directoryPath = '${root.path}/enteTempFiles'; + // Create the directory if it doesn't exist + final DateTime timeStamp = DateTime.now(); + await Directory(directoryPath).create(recursive: true); + final String filePath = '$directoryPath/$timeStamp.jpg'; + final file = await File(filePath).writeAsBytes(bytes!); + path = file.path; + } catch (e) { + debugPrint(e.toString()); + } + return path; + } +} diff --git a/mobile/lib/ui/TEMP/show_images_prevew.dart b/mobile/lib/ui/TEMP/show_images_prevew.dart new file mode 100644 index 0000000000..90bdc78c2e --- /dev/null +++ b/mobile/lib/ui/TEMP/show_images_prevew.dart @@ -0,0 +1,790 @@ +import "dart:ui"; + +import "package:figma_squircle/figma_squircle.dart"; +import "package:flutter/material.dart"; +import "package:photos/models/file/file.dart"; +import "package:photos/ui/TEMP/captureImage.dart"; +import "package:photos/ui/TEMP/widget_to_image.dart"; +import "package:photos/ui/viewer/file/thumbnail_widget.dart"; + +class ShowImagePreviewFromTap extends StatefulWidget { + const ShowImagePreviewFromTap({ + required this.tempEnteFile, + super.key, + }); + final List tempEnteFile; + @override + State createState() => + _ShowImagePreviewFromTapState(); +} + +class _ShowImagePreviewFromTapState extends State { + // late String tempImagePath; + // final ValueNotifier bytesNotifier = + // ValueNotifier(null); + + late GlobalKey _widgetImageKey; + final ValueNotifier tempImagePath = ValueNotifier(null); + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) async { + //delay of 1 second before capturing the image + await Future.delayed(const Duration(milliseconds: 100)); + + tempImagePath.value = await Captures().saveImage(_widgetImageKey); + + Navigator.of(context).pop(tempImagePath.value); + }); + } + + @override + Widget build(BuildContext context) { + final int length = widget.tempEnteFile.length; + Widget placeholderWidget = const SizedBox( + height: 250, + width: 250, + ); + + if (length == 1) { + placeholderWidget = BackDrop( + backDropImage: widget.tempEnteFile[0], + children: [ + Padding( + padding: const EdgeInsets.all(18.0), + child: ClipSmoothRect( + radius: SmoothBorderRadius( + cornerRadius: 7.5, + cornerSmoothing: 1, + ), + child: ThumbnailWidget( + widget.tempEnteFile[0], + shouldShowArchiveStatus: false, + shouldShowSyncStatus: false, + ), + ), + ), + ], + ); + } else if (length == 2) { + placeholderWidget = BackDrop( + backDropImage: widget.tempEnteFile[0], + children: [ + Positioned( + top: 65, + left: 90, + child: CustomImage( + height: 100, + width: 100, + collages: widget.tempEnteFile[0], + zIndex: 0.2, + ), + ), + Positioned( + top: 20, + left: 0, + child: CustomImage( + height: 100, + width: 100, + collages: widget.tempEnteFile[1], + zIndex: -0.2, + ), + ), + ], + ); + } else if (length == 3) { + placeholderWidget = BackDrop( + backDropImage: widget.tempEnteFile[0], + children: [ + Positioned( + top: 30, + left: 0, + child: CustomImage( + height: 80, + width: 80, + collages: widget.tempEnteFile[1], + zIndex: -0.4, + ), + ), + Positioned( + top: 80, + left: 110, + child: CustomImage( + height: 80, + width: 80, + collages: widget.tempEnteFile[2], + zIndex: 0.4, + ), + ), + Positioned( + top: 40, + left: 40, + child: CustomImage( + height: 100, + width: 100, + collages: widget.tempEnteFile[0], + zIndex: 0.0, + ), + ), + ], + ); + } else if (length > 3) { + placeholderWidget = BackDrop( + backDropImage: widget.tempEnteFile[0], + children: [ + Positioned( + top: 10, + left: 10, + child: CustomImage( + height: 80, + width: 80, + collages: widget.tempEnteFile[1], + zIndex: 0, + ), + ), + Positioned( + top: 95, + left: 30, + child: CustomImage( + height: 80, + width: 80, + collages: widget.tempEnteFile[2], + zIndex: 0, + ), + ), + Positioned( + top: 35, + left: 60, + child: CustomImage( + height: 100, + width: 100, + collages: widget.tempEnteFile[0], + zIndex: 0.0, + ), + ), + Positioned( + top: 15, + left: 140, + child: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + ), + child: Text( + "+" "$length", + style: const TextStyle( + fontWeight: FontWeight.w600, + color: Colors.black, + ), + ), + ), + ), + ], + ); + } + return Offstage( + offstage: false, + child: Center( + child: Column( + children: [ + WidgetToImage( + builder: (key) { + _widgetImageKey = key; + return placeholderWidget; + }, + ), + ], + ), + ), + ); + } +} + +class BackDrop extends StatelessWidget { + const BackDrop({ + super.key, + required this.backDropImage, + required this.children, + }); + final List children; + final EnteFile backDropImage; + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(4.0), + height: 200, + width: 200, + child: Stack( + children: [ + ClipSmoothRect( + radius: SmoothBorderRadius( + cornerRadius: 7.5, + cornerSmoothing: 1, + ), + child: ThumbnailWidget( + backDropImage, + shouldShowArchiveStatus: false, + shouldShowSyncStatus: false, + ), + ), + BackdropFilter( + filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), + child: Container( + color: Colors.transparent, + ), + ), + ...children, + ], + ), + ); + } +} + +class CustomImage extends StatelessWidget { + const CustomImage({ + required this.width, + required this.height, + super.key, + required this.collages, + required this.zIndex, + }); + final EnteFile collages; + final double zIndex; + final double height; + final double width; + @override + Widget build(BuildContext context) { + return Container( + transform: Matrix4.rotationZ(zIndex), + height: height, + width: width, + child: ClipSmoothRect( + radius: SmoothBorderRadius( + cornerRadius: 7.5, + cornerSmoothing: 1, + ), + clipBehavior: Clip.antiAliasWithSaveLayer, + child: ThumbnailWidget( + collages, + shouldShowArchiveStatus: false, + shouldShowSyncStatus: false, + ), + ), + ); + } +} + +// import "dart:ui"; + +// import "package:figma_squircle/figma_squircle.dart"; +// import "package:flutter/material.dart"; +// import "package:photos/models/file/file.dart"; +// import "package:photos/ui/TEMP/captureImage.dart"; +// import "package:photos/ui/TEMP/widget_to_image.dart"; +// import "package:photos/ui/viewer/file/thumbnail_widget.dart"; + +// class ShowImagePrev { +// late GlobalKey _widgetImageKey; +// final ValueNotifier tempImagePath = ValueNotifier(null); +// Future imageToWidgetFunction(List tempEnteFile) async { +// showImagePreviewFromTap(tempEnteFile); +// await Future.delayed(const Duration(milliseconds: 100)); +// tempImagePath.value = await Captures().saveImage(_widgetImageKey); + +// print("VALUE IS ==================${tempImagePath.value}"); +// if (tempImagePath.value != null) { +// return tempImagePath.value; +// } +// return null; +// } + +// Widget showImagePreviewFromTap(List tempEnteFile) { +// final int length = tempEnteFile.length; +// Widget placeholderWidget = const SizedBox( +// height: 250, +// width: 250, +// ); + +// if (length == 1) { +// placeholderWidget = BackDrop( +// backDropImage: tempEnteFile[0], +// children: [ +// Padding( +// padding: const EdgeInsets.all(18.0), +// child: ClipSmoothRect( +// radius: SmoothBorderRadius( +// cornerRadius: 7.5, +// cornerSmoothing: 1, +// ), +// child: ThumbnailWidget( +// tempEnteFile[0], +// shouldShowArchiveStatus: false, +// shouldShowSyncStatus: false, +// ), +// ), +// ), +// ], +// ); +// } else if (length == 2) { +// placeholderWidget = BackDrop( +// backDropImage: tempEnteFile[0], +// children: [ +// Positioned( +// top: 65, +// left: 90, +// child: CustomImage( +// height: 100, +// width: 100, +// collages: tempEnteFile[0], +// zIndex: 0.2, +// ), +// ), +// Positioned( +// top: 20, +// left: 0, +// child: CustomImage( +// height: 100, +// width: 100, +// collages: tempEnteFile[1], +// zIndex: -0.2, +// ), +// ), +// ], +// ); +// } else if (length == 3) { +// placeholderWidget = BackDrop( +// backDropImage: tempEnteFile[0], +// children: [ +// Positioned( +// top: 30, +// left: 0, +// child: CustomImage( +// height: 80, +// width: 80, +// collages: tempEnteFile[1], +// zIndex: -0.4, +// ), +// ), +// Positioned( +// top: 80, +// left: 110, +// child: CustomImage( +// height: 80, +// width: 80, +// collages: tempEnteFile[2], +// zIndex: 0.4, +// ), +// ), +// Positioned( +// top: 40, +// left: 40, +// child: CustomImage( +// height: 100, +// width: 100, +// collages: tempEnteFile[0], +// zIndex: 0.0, +// ), +// ), +// ], +// ); +// } else if (length > 3) { +// placeholderWidget = BackDrop( +// backDropImage: tempEnteFile[0], +// children: [ +// Positioned( +// top: 10, +// left: 10, +// child: CustomImage( +// height: 80, +// width: 80, +// collages: tempEnteFile[1], +// zIndex: 0, +// ), +// ), +// Positioned( +// top: 95, +// left: 30, +// child: CustomImage( +// height: 80, +// width: 80, +// collages: tempEnteFile[2], +// zIndex: 0, +// ), +// ), +// Positioned( +// top: 35, +// left: 60, +// child: CustomImage( +// height: 100, +// width: 100, +// collages: tempEnteFile[0], +// zIndex: 0.0, +// ), +// ), +// Positioned( +// top: 15, +// left: 140, +// child: Container( +// padding: const EdgeInsets.all(8), +// decoration: BoxDecoration( +// color: Colors.white, +// borderRadius: BorderRadius.circular(12), +// ), +// child: Text( +// "+ $length", +// style: const TextStyle( +// fontWeight: FontWeight.w600, +// color: Colors.black, +// ), +// ), +// ), +// ), +// ], +// ); +// } + +// return Center( +// child: WidgetToImage( +// builder: (key) { +// _widgetImageKey = key; +// return placeholderWidget; +// }, +// ), +// ); +// } +// } + +// class BackDrop extends StatelessWidget { +// const BackDrop({ +// super.key, +// required this.backDropImage, +// required this.children, +// }); +// final List children; +// final EnteFile backDropImage; + +// @override +// Widget build(BuildContext context) { +// return Container( +// padding: const EdgeInsets.all(4.0), +// height: 200, +// width: 200, +// child: Stack( +// children: [ +// ClipSmoothRect( +// radius: SmoothBorderRadius( +// cornerRadius: 7.5, +// cornerSmoothing: 1, +// ), +// child: ThumbnailWidget( +// backDropImage, +// shouldShowArchiveStatus: false, +// shouldShowSyncStatus: false, +// ), +// ), +// BackdropFilter( +// filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), +// child: Container( +// color: Colors.transparent, +// ), +// ), +// ...children, +// ], +// ), +// ); +// } +// } + +// class CustomImage extends StatelessWidget { +// const CustomImage({ +// required this.width, +// required this.height, +// super.key, +// required this.collages, +// required this.zIndex, +// }); +// final EnteFile collages; +// final double zIndex; +// final double height; +// final double width; +// @override +// Widget build(BuildContext context) { +// return Container( +// transform: Matrix4.rotationZ(zIndex), +// height: height, +// width: width, +// child: ClipSmoothRect( +// radius: SmoothBorderRadius( +// cornerRadius: 7.5, +// cornerSmoothing: 1, +// ), +// clipBehavior: Clip.antiAliasWithSaveLayer, +// child: ThumbnailWidget( +// collages, +// shouldShowArchiveStatus: false, +// shouldShowSyncStatus: false, +// ), +// ), +// ); +// } +// } +// import "dart:ui"; + +// import "package:figma_squircle/figma_squircle.dart"; +// import "package:flutter/material.dart"; +// import "package:photos/models/file/file.dart"; +// import "package:photos/ui/TEMP/captureImage.dart"; +// import "package:photos/ui/TEMP/widget_to_image.dart"; +// import "package:photos/ui/viewer/file/thumbnail_widget.dart"; + +// class ShowImagePrev { +// late GlobalKey _widgetImageKey; +// final ValueNotifier tempImagePath = ValueNotifier(null); + +// ShowImagePrev() { +// _widgetImageKey = GlobalKey(); +// } + +// Future imageToWidgetFunction(List tempEnteFile) async { +// showImagePreviewFromTap(tempEnteFile); +// // Build the widget to ensure the GlobalKey is assigned correctly +// WidgetsBinding.instance.addPostFrameCallback((_) async { +// await Future.delayed(const Duration(milliseconds: 100)); +// tempImagePath.value = await Captures().saveImage(_widgetImageKey); +// print("VALUE IS ==================${tempImagePath.value}"); +// }); + +// return tempImagePath.value; +// } + +// Widget showImagePreviewFromTap(List tempEnteFile) { +// final int length = tempEnteFile.length; +// Widget placeholderWidget = const SizedBox( +// height: 250, +// width: 250, +// ); + +// if (length == 1) { +// placeholderWidget = BackDrop( +// backDropImage: tempEnteFile[0], +// children: [ +// Padding( +// padding: const EdgeInsets.all(18.0), +// child: ClipSmoothRect( +// radius: SmoothBorderRadius( +// cornerRadius: 7.5, +// cornerSmoothing: 1, +// ), +// child: ThumbnailWidget( +// tempEnteFile[0], +// shouldShowArchiveStatus: false, +// shouldShowSyncStatus: false, +// ), +// ), +// ), +// ], +// ); +// } else if (length == 2) { +// placeholderWidget = BackDrop( +// backDropImage: tempEnteFile[0], +// children: [ +// Positioned( +// top: 65, +// left: 90, +// child: CustomImage( +// height: 100, +// width: 100, +// collages: tempEnteFile[0], +// zIndex: 0.2, +// ), +// ), +// Positioned( +// top: 20, +// left: 0, +// child: CustomImage( +// height: 100, +// width: 100, +// collages: tempEnteFile[1], +// zIndex: -0.2, +// ), +// ), +// ], +// ); +// } else if (length == 3) { +// placeholderWidget = BackDrop( +// backDropImage: tempEnteFile[0], +// children: [ +// Positioned( +// top: 30, +// left: 0, +// child: CustomImage( +// height: 80, +// width: 80, +// collages: tempEnteFile[1], +// zIndex: -0.4, +// ), +// ), +// Positioned( +// top: 80, +// left: 110, +// child: CustomImage( +// height: 80, +// width: 80, +// collages: tempEnteFile[2], +// zIndex: 0.4, +// ), +// ), +// Positioned( +// top: 40, +// left: 40, +// child: CustomImage( +// height: 100, +// width: 100, +// collages: tempEnteFile[0], +// zIndex: 0.0, +// ), +// ), +// ], +// ); +// } else if (length > 3) { +// placeholderWidget = BackDrop( +// backDropImage: tempEnteFile[0], +// children: [ +// Positioned( +// top: 10, +// left: 10, +// child: CustomImage( +// height: 80, +// width: 80, +// collages: tempEnteFile[1], +// zIndex: 0, +// ), +// ), +// Positioned( +// top: 95, +// left: 30, +// child: CustomImage( +// height: 80, +// width: 80, +// collages: tempEnteFile[2], +// zIndex: 0, +// ), +// ), +// Positioned( +// top: 35, +// left: 60, +// child: CustomImage( +// height: 100, +// width: 100, +// collages: tempEnteFile[0], +// zIndex: 0.0, +// ), +// ), +// Positioned( +// top: 15, +// left: 140, +// child: Container( +// padding: const EdgeInsets.all(8), +// decoration: BoxDecoration( +// color: Colors.white, +// borderRadius: BorderRadius.circular(12), +// ), +// child: Text( +// "+ $length", +// style: const TextStyle( +// fontWeight: FontWeight.w600, +// color: Colors.black, +// ), +// ), +// ), +// ), +// ], +// ); +// } + +// return Center( +// child: WidgetToImage( +// builder: (key) { +// _widgetImageKey = key; +// return placeholderWidget; +// }, +// ), +// ); +// } +// } + +// class BackDrop extends StatelessWidget { +// const BackDrop({ +// super.key, +// required this.backDropImage, +// required this.children, +// }); +// final List children; +// final EnteFile backDropImage; + +// @override +// Widget build(BuildContext context) { +// return Container( +// padding: const EdgeInsets.all(4.0), +// height: 200, +// width: 200, +// child: Stack( +// children: [ +// ClipSmoothRect( +// radius: SmoothBorderRadius( +// cornerRadius: 7.5, +// cornerSmoothing: 1, +// ), +// child: ThumbnailWidget( +// backDropImage, +// shouldShowArchiveStatus: false, +// shouldShowSyncStatus: false, +// ), +// ), +// BackdropFilter( +// filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), +// child: Container( +// color: Colors.transparent, +// ), +// ), +// ...children, +// ], +// ), +// ); +// } +// } + +// class CustomImage extends StatelessWidget { +// const CustomImage({ +// required this.width, +// required this.height, +// super.key, +// required this.collages, +// required this.zIndex, +// }); +// final EnteFile collages; +// final double zIndex; +// final double height; +// final double width; +// @override +// Widget build(BuildContext context) { +// return Container( +// transform: Matrix4.rotationZ(zIndex), +// height: height, +// width: width, +// child: ClipSmoothRect( +// radius: SmoothBorderRadius( +// cornerRadius: 7.5, +// cornerSmoothing: 1, +// ), +// clipBehavior: Clip.antiAliasWithSaveLayer, +// child: ThumbnailWidget( +// collages, +// shouldShowArchiveStatus: false, +// shouldShowSyncStatus: false, +// ), +// ), +// ); +// } +// } diff --git a/mobile/lib/ui/TEMP/widget_to_image.dart b/mobile/lib/ui/TEMP/widget_to_image.dart new file mode 100644 index 0000000000..b00818b0da --- /dev/null +++ b/mobile/lib/ui/TEMP/widget_to_image.dart @@ -0,0 +1,19 @@ +import "package:flutter/material.dart"; + +class WidgetToImage extends StatefulWidget { + const WidgetToImage({super.key, required this.builder}); + final Function(GlobalKey key) builder; + @override + State createState() => _WidgetToImageState(); +} + +class _WidgetToImageState extends State { + final globalKey = GlobalKey(); + @override + Widget build(BuildContext context) { + return RepaintBoundary( + key: globalKey, + child: widget.builder(globalKey), + ); + } +} diff --git a/mobile/lib/ui/actions/collection/collection_sharing_actions.dart b/mobile/lib/ui/actions/collection/collection_sharing_actions.dart index 3328722dbe..0d571c2d87 100644 --- a/mobile/lib/ui/actions/collection/collection_sharing_actions.dart +++ b/mobile/lib/ui/actions/collection/collection_sharing_actions.dart @@ -110,6 +110,7 @@ class CollectionActions { BuildContext context, List files, ) async { + print("CREATED LINK"); final dialog = createProgressDialog( context, S.of(context).creatingLink, diff --git a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart index e805927a64..3fbc42ff7e 100644 --- a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart +++ b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart @@ -19,6 +19,7 @@ import 'package:photos/services/collections_service.dart'; import 'package:photos/services/hidden_service.dart'; import "package:photos/theme/colors.dart"; import "package:photos/theme/ente_theme.dart"; +import "package:photos/ui/TEMP/show_images_prevew.dart"; import 'package:photos/ui/actions/collection/collection_file_actions.dart'; import 'package:photos/ui/actions/collection/collection_sharing_actions.dart'; import 'package:photos/ui/collections/collection_action_sheet.dart'; @@ -561,6 +562,25 @@ class _FileSelectionActionsWidgetState } } + ValueNotifier generatedPathNotifier = ValueNotifier(null); +//Future function to go to next page + Future _nextPageForTesting(List tempfile) async { + final String? tempImagePath = await Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => ShowImagePreviewFromTap( + tempEnteFile: tempfile, + ), + ), + ); + + if (tempImagePath != null) { + print("Temp image path: $tempImagePath"); + + return tempImagePath; + } + return tempImagePath; + } + Future _onCreatedSharedLinkClicked() async { if (split.ownedByCurrentUser.isEmpty) { showShortToast( @@ -571,16 +591,26 @@ class _FileSelectionActionsWidgetState } _cachedCollectionForSharedLink ??= await collectionActions .createSharedCollectionLink(context, split.ownedByCurrentUser); + + final List tempEnteFile = split.ownedByCurrentUser; + final actionResult = await showActionSheet( context: context, buttons: [ ButtonWidget( - labelText: S.of(context).copyLink, + labelText: S.of(context).shareLink, buttonType: ButtonType.neutral, buttonSize: ButtonSize.large, shouldStickToDarkTheme: true, buttonAction: ButtonAction.first, isInAlert: true, + // onTap: () async { + // // Add a return statement at the end of the function + // generatedPathNotifier.value = + // await _nextPageForTesting(tempEnteFile); + // await shareText(generatedPathNotifier.value!); + // return Future.value(); + // }, ), ButtonWidget( labelText: S.of(context).manageLink, @@ -605,6 +635,7 @@ class _FileSelectionActionsWidgetState ); if (actionResult?.action != null) { if (actionResult!.action == ButtonAction.first) { + //generatedPathNotifier.value = await _nextPageForTesting(tempEnteFile); await _copyLink(); } if (actionResult.action == ButtonAction.second) { @@ -621,6 +652,7 @@ class _FileSelectionActionsWidgetState } Future _copyLink() async { + print("INSIDE COPY LINK"); if (_cachedCollectionForSharedLink != null) { final String collectionKey = Base58Encode( CollectionsService.instance @@ -628,6 +660,8 @@ class _FileSelectionActionsWidgetState ); final String url = "${_cachedCollectionForSharedLink!.publicURLs?.first?.url}#$collectionKey"; + await shareText(url); + //await shareImageAndUrl(context, generatedPathNotifier.value!, url); await Clipboard.setData(ClipboardData(text: url)); showShortToast(context, S.of(context).linkCopiedToClipboard); } diff --git a/mobile/lib/utils/share_util.dart b/mobile/lib/utils/share_util.dart index ff9f691bd6..b94ac33235 100644 --- a/mobile/lib/utils/share_util.dart +++ b/mobile/lib/utils/share_util.dart @@ -218,3 +218,11 @@ void shareSelected( shareButtonKey: shareButtonKey, ); } + +Future shareImageAndUrl( + BuildContext context, + String imagePath, + String url, +) async { + await Share.shareFiles([imagePath], text: url); +} From b5eae21ae77b0a8dc4d88b70e8727e81f8a2193e Mon Sep 17 00:00:00 2001 From: Aman Raj Singh Mourya Date: Wed, 29 May 2024 13:02:45 +0530 Subject: [PATCH 02/22] [mob][photos] send placeholder with link when sharing --- mobile/lib/ui/TEMP/captureImage.dart | 65 -- mobile/lib/ui/TEMP/show_images_prevew.dart | 790 ------------------ mobile/lib/ui/TEMP/widget_to_image.dart | 19 - mobile/lib/ui/sharing/show_images_prevew.dart | 293 +++++++ .../file_selection_actions_widget.dart | 59 +- mobile/pubspec.lock | 8 + mobile/pubspec.yaml | 3 +- 7 files changed, 339 insertions(+), 898 deletions(-) delete mode 100644 mobile/lib/ui/TEMP/captureImage.dart delete mode 100644 mobile/lib/ui/TEMP/show_images_prevew.dart delete mode 100644 mobile/lib/ui/TEMP/widget_to_image.dart create mode 100644 mobile/lib/ui/sharing/show_images_prevew.dart diff --git a/mobile/lib/ui/TEMP/captureImage.dart b/mobile/lib/ui/TEMP/captureImage.dart deleted file mode 100644 index 65aec5a6ad..0000000000 --- a/mobile/lib/ui/TEMP/captureImage.dart +++ /dev/null @@ -1,65 +0,0 @@ -// import "dart:typed_data"; -// import 'dart:ui' as ui; - -// import 'package:flutter/material.dart'; -// import 'package:flutter/rendering.dart'; - -// class Captures { -// static Future capture(GlobalKey key) async { -// final double pixelRatio = -// MediaQuery.of(key.currentContext!).devicePixelRatio; -// final RenderRepaintBoundary boundary = -// key.currentContext!.findRenderObject()! as RenderRepaintBoundary; -// final ui.Image image = await boundary.toImage(pixelRatio: pixelRatio); -// final ByteData? byteData = -// await image.toByteData(format: ui.ImageByteFormat.png); -// final Uint8List pngBytes = byteData!.buffer.asUint8List(); -// print("PNG BYTES ====== ${pngBytes}"); -// return pngBytes; -// } -// } -import "dart:io"; -import 'dart:typed_data'; -import 'dart:ui' as ui; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import "package:path_provider/path_provider.dart"; - -class Captures { - Future capture(GlobalKey key) async { - try { - final double pixelRatio = - MediaQuery.of(key.currentContext!).devicePixelRatio; - final RenderRepaintBoundary boundary = - key.currentContext!.findRenderObject()! as RenderRepaintBoundary; - final ui.Image image = await boundary.toImage(pixelRatio: pixelRatio); - final ByteData? byteData = - await image.toByteData(format: ui.ImageByteFormat.png); - final Uint8List pngBytes = byteData!.buffer.asUint8List(); - print("PNG BYTES ====== ${pngBytes}"); - - return pngBytes; - } catch (e) { - print(e); - } - return null; - } - - Future saveImage(GlobalKey key) async { - String path = ""; - try { - final Uint8List? bytes = await capture(key); - final Directory root = await getTemporaryDirectory(); - final String directoryPath = '${root.path}/enteTempFiles'; - // Create the directory if it doesn't exist - final DateTime timeStamp = DateTime.now(); - await Directory(directoryPath).create(recursive: true); - final String filePath = '$directoryPath/$timeStamp.jpg'; - final file = await File(filePath).writeAsBytes(bytes!); - path = file.path; - } catch (e) { - debugPrint(e.toString()); - } - return path; - } -} diff --git a/mobile/lib/ui/TEMP/show_images_prevew.dart b/mobile/lib/ui/TEMP/show_images_prevew.dart deleted file mode 100644 index 90bdc78c2e..0000000000 --- a/mobile/lib/ui/TEMP/show_images_prevew.dart +++ /dev/null @@ -1,790 +0,0 @@ -import "dart:ui"; - -import "package:figma_squircle/figma_squircle.dart"; -import "package:flutter/material.dart"; -import "package:photos/models/file/file.dart"; -import "package:photos/ui/TEMP/captureImage.dart"; -import "package:photos/ui/TEMP/widget_to_image.dart"; -import "package:photos/ui/viewer/file/thumbnail_widget.dart"; - -class ShowImagePreviewFromTap extends StatefulWidget { - const ShowImagePreviewFromTap({ - required this.tempEnteFile, - super.key, - }); - final List tempEnteFile; - @override - State createState() => - _ShowImagePreviewFromTapState(); -} - -class _ShowImagePreviewFromTapState extends State { - // late String tempImagePath; - // final ValueNotifier bytesNotifier = - // ValueNotifier(null); - - late GlobalKey _widgetImageKey; - final ValueNotifier tempImagePath = ValueNotifier(null); - @override - void initState() { - super.initState(); - WidgetsBinding.instance.addPostFrameCallback((_) async { - //delay of 1 second before capturing the image - await Future.delayed(const Duration(milliseconds: 100)); - - tempImagePath.value = await Captures().saveImage(_widgetImageKey); - - Navigator.of(context).pop(tempImagePath.value); - }); - } - - @override - Widget build(BuildContext context) { - final int length = widget.tempEnteFile.length; - Widget placeholderWidget = const SizedBox( - height: 250, - width: 250, - ); - - if (length == 1) { - placeholderWidget = BackDrop( - backDropImage: widget.tempEnteFile[0], - children: [ - Padding( - padding: const EdgeInsets.all(18.0), - child: ClipSmoothRect( - radius: SmoothBorderRadius( - cornerRadius: 7.5, - cornerSmoothing: 1, - ), - child: ThumbnailWidget( - widget.tempEnteFile[0], - shouldShowArchiveStatus: false, - shouldShowSyncStatus: false, - ), - ), - ), - ], - ); - } else if (length == 2) { - placeholderWidget = BackDrop( - backDropImage: widget.tempEnteFile[0], - children: [ - Positioned( - top: 65, - left: 90, - child: CustomImage( - height: 100, - width: 100, - collages: widget.tempEnteFile[0], - zIndex: 0.2, - ), - ), - Positioned( - top: 20, - left: 0, - child: CustomImage( - height: 100, - width: 100, - collages: widget.tempEnteFile[1], - zIndex: -0.2, - ), - ), - ], - ); - } else if (length == 3) { - placeholderWidget = BackDrop( - backDropImage: widget.tempEnteFile[0], - children: [ - Positioned( - top: 30, - left: 0, - child: CustomImage( - height: 80, - width: 80, - collages: widget.tempEnteFile[1], - zIndex: -0.4, - ), - ), - Positioned( - top: 80, - left: 110, - child: CustomImage( - height: 80, - width: 80, - collages: widget.tempEnteFile[2], - zIndex: 0.4, - ), - ), - Positioned( - top: 40, - left: 40, - child: CustomImage( - height: 100, - width: 100, - collages: widget.tempEnteFile[0], - zIndex: 0.0, - ), - ), - ], - ); - } else if (length > 3) { - placeholderWidget = BackDrop( - backDropImage: widget.tempEnteFile[0], - children: [ - Positioned( - top: 10, - left: 10, - child: CustomImage( - height: 80, - width: 80, - collages: widget.tempEnteFile[1], - zIndex: 0, - ), - ), - Positioned( - top: 95, - left: 30, - child: CustomImage( - height: 80, - width: 80, - collages: widget.tempEnteFile[2], - zIndex: 0, - ), - ), - Positioned( - top: 35, - left: 60, - child: CustomImage( - height: 100, - width: 100, - collages: widget.tempEnteFile[0], - zIndex: 0.0, - ), - ), - Positioned( - top: 15, - left: 140, - child: Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - ), - child: Text( - "+" "$length", - style: const TextStyle( - fontWeight: FontWeight.w600, - color: Colors.black, - ), - ), - ), - ), - ], - ); - } - return Offstage( - offstage: false, - child: Center( - child: Column( - children: [ - WidgetToImage( - builder: (key) { - _widgetImageKey = key; - return placeholderWidget; - }, - ), - ], - ), - ), - ); - } -} - -class BackDrop extends StatelessWidget { - const BackDrop({ - super.key, - required this.backDropImage, - required this.children, - }); - final List children; - final EnteFile backDropImage; - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(4.0), - height: 200, - width: 200, - child: Stack( - children: [ - ClipSmoothRect( - radius: SmoothBorderRadius( - cornerRadius: 7.5, - cornerSmoothing: 1, - ), - child: ThumbnailWidget( - backDropImage, - shouldShowArchiveStatus: false, - shouldShowSyncStatus: false, - ), - ), - BackdropFilter( - filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), - child: Container( - color: Colors.transparent, - ), - ), - ...children, - ], - ), - ); - } -} - -class CustomImage extends StatelessWidget { - const CustomImage({ - required this.width, - required this.height, - super.key, - required this.collages, - required this.zIndex, - }); - final EnteFile collages; - final double zIndex; - final double height; - final double width; - @override - Widget build(BuildContext context) { - return Container( - transform: Matrix4.rotationZ(zIndex), - height: height, - width: width, - child: ClipSmoothRect( - radius: SmoothBorderRadius( - cornerRadius: 7.5, - cornerSmoothing: 1, - ), - clipBehavior: Clip.antiAliasWithSaveLayer, - child: ThumbnailWidget( - collages, - shouldShowArchiveStatus: false, - shouldShowSyncStatus: false, - ), - ), - ); - } -} - -// import "dart:ui"; - -// import "package:figma_squircle/figma_squircle.dart"; -// import "package:flutter/material.dart"; -// import "package:photos/models/file/file.dart"; -// import "package:photos/ui/TEMP/captureImage.dart"; -// import "package:photos/ui/TEMP/widget_to_image.dart"; -// import "package:photos/ui/viewer/file/thumbnail_widget.dart"; - -// class ShowImagePrev { -// late GlobalKey _widgetImageKey; -// final ValueNotifier tempImagePath = ValueNotifier(null); -// Future imageToWidgetFunction(List tempEnteFile) async { -// showImagePreviewFromTap(tempEnteFile); -// await Future.delayed(const Duration(milliseconds: 100)); -// tempImagePath.value = await Captures().saveImage(_widgetImageKey); - -// print("VALUE IS ==================${tempImagePath.value}"); -// if (tempImagePath.value != null) { -// return tempImagePath.value; -// } -// return null; -// } - -// Widget showImagePreviewFromTap(List tempEnteFile) { -// final int length = tempEnteFile.length; -// Widget placeholderWidget = const SizedBox( -// height: 250, -// width: 250, -// ); - -// if (length == 1) { -// placeholderWidget = BackDrop( -// backDropImage: tempEnteFile[0], -// children: [ -// Padding( -// padding: const EdgeInsets.all(18.0), -// child: ClipSmoothRect( -// radius: SmoothBorderRadius( -// cornerRadius: 7.5, -// cornerSmoothing: 1, -// ), -// child: ThumbnailWidget( -// tempEnteFile[0], -// shouldShowArchiveStatus: false, -// shouldShowSyncStatus: false, -// ), -// ), -// ), -// ], -// ); -// } else if (length == 2) { -// placeholderWidget = BackDrop( -// backDropImage: tempEnteFile[0], -// children: [ -// Positioned( -// top: 65, -// left: 90, -// child: CustomImage( -// height: 100, -// width: 100, -// collages: tempEnteFile[0], -// zIndex: 0.2, -// ), -// ), -// Positioned( -// top: 20, -// left: 0, -// child: CustomImage( -// height: 100, -// width: 100, -// collages: tempEnteFile[1], -// zIndex: -0.2, -// ), -// ), -// ], -// ); -// } else if (length == 3) { -// placeholderWidget = BackDrop( -// backDropImage: tempEnteFile[0], -// children: [ -// Positioned( -// top: 30, -// left: 0, -// child: CustomImage( -// height: 80, -// width: 80, -// collages: tempEnteFile[1], -// zIndex: -0.4, -// ), -// ), -// Positioned( -// top: 80, -// left: 110, -// child: CustomImage( -// height: 80, -// width: 80, -// collages: tempEnteFile[2], -// zIndex: 0.4, -// ), -// ), -// Positioned( -// top: 40, -// left: 40, -// child: CustomImage( -// height: 100, -// width: 100, -// collages: tempEnteFile[0], -// zIndex: 0.0, -// ), -// ), -// ], -// ); -// } else if (length > 3) { -// placeholderWidget = BackDrop( -// backDropImage: tempEnteFile[0], -// children: [ -// Positioned( -// top: 10, -// left: 10, -// child: CustomImage( -// height: 80, -// width: 80, -// collages: tempEnteFile[1], -// zIndex: 0, -// ), -// ), -// Positioned( -// top: 95, -// left: 30, -// child: CustomImage( -// height: 80, -// width: 80, -// collages: tempEnteFile[2], -// zIndex: 0, -// ), -// ), -// Positioned( -// top: 35, -// left: 60, -// child: CustomImage( -// height: 100, -// width: 100, -// collages: tempEnteFile[0], -// zIndex: 0.0, -// ), -// ), -// Positioned( -// top: 15, -// left: 140, -// child: Container( -// padding: const EdgeInsets.all(8), -// decoration: BoxDecoration( -// color: Colors.white, -// borderRadius: BorderRadius.circular(12), -// ), -// child: Text( -// "+ $length", -// style: const TextStyle( -// fontWeight: FontWeight.w600, -// color: Colors.black, -// ), -// ), -// ), -// ), -// ], -// ); -// } - -// return Center( -// child: WidgetToImage( -// builder: (key) { -// _widgetImageKey = key; -// return placeholderWidget; -// }, -// ), -// ); -// } -// } - -// class BackDrop extends StatelessWidget { -// const BackDrop({ -// super.key, -// required this.backDropImage, -// required this.children, -// }); -// final List children; -// final EnteFile backDropImage; - -// @override -// Widget build(BuildContext context) { -// return Container( -// padding: const EdgeInsets.all(4.0), -// height: 200, -// width: 200, -// child: Stack( -// children: [ -// ClipSmoothRect( -// radius: SmoothBorderRadius( -// cornerRadius: 7.5, -// cornerSmoothing: 1, -// ), -// child: ThumbnailWidget( -// backDropImage, -// shouldShowArchiveStatus: false, -// shouldShowSyncStatus: false, -// ), -// ), -// BackdropFilter( -// filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), -// child: Container( -// color: Colors.transparent, -// ), -// ), -// ...children, -// ], -// ), -// ); -// } -// } - -// class CustomImage extends StatelessWidget { -// const CustomImage({ -// required this.width, -// required this.height, -// super.key, -// required this.collages, -// required this.zIndex, -// }); -// final EnteFile collages; -// final double zIndex; -// final double height; -// final double width; -// @override -// Widget build(BuildContext context) { -// return Container( -// transform: Matrix4.rotationZ(zIndex), -// height: height, -// width: width, -// child: ClipSmoothRect( -// radius: SmoothBorderRadius( -// cornerRadius: 7.5, -// cornerSmoothing: 1, -// ), -// clipBehavior: Clip.antiAliasWithSaveLayer, -// child: ThumbnailWidget( -// collages, -// shouldShowArchiveStatus: false, -// shouldShowSyncStatus: false, -// ), -// ), -// ); -// } -// } -// import "dart:ui"; - -// import "package:figma_squircle/figma_squircle.dart"; -// import "package:flutter/material.dart"; -// import "package:photos/models/file/file.dart"; -// import "package:photos/ui/TEMP/captureImage.dart"; -// import "package:photos/ui/TEMP/widget_to_image.dart"; -// import "package:photos/ui/viewer/file/thumbnail_widget.dart"; - -// class ShowImagePrev { -// late GlobalKey _widgetImageKey; -// final ValueNotifier tempImagePath = ValueNotifier(null); - -// ShowImagePrev() { -// _widgetImageKey = GlobalKey(); -// } - -// Future imageToWidgetFunction(List tempEnteFile) async { -// showImagePreviewFromTap(tempEnteFile); -// // Build the widget to ensure the GlobalKey is assigned correctly -// WidgetsBinding.instance.addPostFrameCallback((_) async { -// await Future.delayed(const Duration(milliseconds: 100)); -// tempImagePath.value = await Captures().saveImage(_widgetImageKey); -// print("VALUE IS ==================${tempImagePath.value}"); -// }); - -// return tempImagePath.value; -// } - -// Widget showImagePreviewFromTap(List tempEnteFile) { -// final int length = tempEnteFile.length; -// Widget placeholderWidget = const SizedBox( -// height: 250, -// width: 250, -// ); - -// if (length == 1) { -// placeholderWidget = BackDrop( -// backDropImage: tempEnteFile[0], -// children: [ -// Padding( -// padding: const EdgeInsets.all(18.0), -// child: ClipSmoothRect( -// radius: SmoothBorderRadius( -// cornerRadius: 7.5, -// cornerSmoothing: 1, -// ), -// child: ThumbnailWidget( -// tempEnteFile[0], -// shouldShowArchiveStatus: false, -// shouldShowSyncStatus: false, -// ), -// ), -// ), -// ], -// ); -// } else if (length == 2) { -// placeholderWidget = BackDrop( -// backDropImage: tempEnteFile[0], -// children: [ -// Positioned( -// top: 65, -// left: 90, -// child: CustomImage( -// height: 100, -// width: 100, -// collages: tempEnteFile[0], -// zIndex: 0.2, -// ), -// ), -// Positioned( -// top: 20, -// left: 0, -// child: CustomImage( -// height: 100, -// width: 100, -// collages: tempEnteFile[1], -// zIndex: -0.2, -// ), -// ), -// ], -// ); -// } else if (length == 3) { -// placeholderWidget = BackDrop( -// backDropImage: tempEnteFile[0], -// children: [ -// Positioned( -// top: 30, -// left: 0, -// child: CustomImage( -// height: 80, -// width: 80, -// collages: tempEnteFile[1], -// zIndex: -0.4, -// ), -// ), -// Positioned( -// top: 80, -// left: 110, -// child: CustomImage( -// height: 80, -// width: 80, -// collages: tempEnteFile[2], -// zIndex: 0.4, -// ), -// ), -// Positioned( -// top: 40, -// left: 40, -// child: CustomImage( -// height: 100, -// width: 100, -// collages: tempEnteFile[0], -// zIndex: 0.0, -// ), -// ), -// ], -// ); -// } else if (length > 3) { -// placeholderWidget = BackDrop( -// backDropImage: tempEnteFile[0], -// children: [ -// Positioned( -// top: 10, -// left: 10, -// child: CustomImage( -// height: 80, -// width: 80, -// collages: tempEnteFile[1], -// zIndex: 0, -// ), -// ), -// Positioned( -// top: 95, -// left: 30, -// child: CustomImage( -// height: 80, -// width: 80, -// collages: tempEnteFile[2], -// zIndex: 0, -// ), -// ), -// Positioned( -// top: 35, -// left: 60, -// child: CustomImage( -// height: 100, -// width: 100, -// collages: tempEnteFile[0], -// zIndex: 0.0, -// ), -// ), -// Positioned( -// top: 15, -// left: 140, -// child: Container( -// padding: const EdgeInsets.all(8), -// decoration: BoxDecoration( -// color: Colors.white, -// borderRadius: BorderRadius.circular(12), -// ), -// child: Text( -// "+ $length", -// style: const TextStyle( -// fontWeight: FontWeight.w600, -// color: Colors.black, -// ), -// ), -// ), -// ), -// ], -// ); -// } - -// return Center( -// child: WidgetToImage( -// builder: (key) { -// _widgetImageKey = key; -// return placeholderWidget; -// }, -// ), -// ); -// } -// } - -// class BackDrop extends StatelessWidget { -// const BackDrop({ -// super.key, -// required this.backDropImage, -// required this.children, -// }); -// final List children; -// final EnteFile backDropImage; - -// @override -// Widget build(BuildContext context) { -// return Container( -// padding: const EdgeInsets.all(4.0), -// height: 200, -// width: 200, -// child: Stack( -// children: [ -// ClipSmoothRect( -// radius: SmoothBorderRadius( -// cornerRadius: 7.5, -// cornerSmoothing: 1, -// ), -// child: ThumbnailWidget( -// backDropImage, -// shouldShowArchiveStatus: false, -// shouldShowSyncStatus: false, -// ), -// ), -// BackdropFilter( -// filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), -// child: Container( -// color: Colors.transparent, -// ), -// ), -// ...children, -// ], -// ), -// ); -// } -// } - -// class CustomImage extends StatelessWidget { -// const CustomImage({ -// required this.width, -// required this.height, -// super.key, -// required this.collages, -// required this.zIndex, -// }); -// final EnteFile collages; -// final double zIndex; -// final double height; -// final double width; -// @override -// Widget build(BuildContext context) { -// return Container( -// transform: Matrix4.rotationZ(zIndex), -// height: height, -// width: width, -// child: ClipSmoothRect( -// radius: SmoothBorderRadius( -// cornerRadius: 7.5, -// cornerSmoothing: 1, -// ), -// clipBehavior: Clip.antiAliasWithSaveLayer, -// child: ThumbnailWidget( -// collages, -// shouldShowArchiveStatus: false, -// shouldShowSyncStatus: false, -// ), -// ), -// ); -// } -// } diff --git a/mobile/lib/ui/TEMP/widget_to_image.dart b/mobile/lib/ui/TEMP/widget_to_image.dart deleted file mode 100644 index b00818b0da..0000000000 --- a/mobile/lib/ui/TEMP/widget_to_image.dart +++ /dev/null @@ -1,19 +0,0 @@ -import "package:flutter/material.dart"; - -class WidgetToImage extends StatefulWidget { - const WidgetToImage({super.key, required this.builder}); - final Function(GlobalKey key) builder; - @override - State createState() => _WidgetToImageState(); -} - -class _WidgetToImageState extends State { - final globalKey = GlobalKey(); - @override - Widget build(BuildContext context) { - return RepaintBoundary( - key: globalKey, - child: widget.builder(globalKey), - ); - } -} diff --git a/mobile/lib/ui/sharing/show_images_prevew.dart b/mobile/lib/ui/sharing/show_images_prevew.dart new file mode 100644 index 0000000000..7b0632554a --- /dev/null +++ b/mobile/lib/ui/sharing/show_images_prevew.dart @@ -0,0 +1,293 @@ +import "dart:ui"; + +import "package:figma_squircle/figma_squircle.dart"; +import "package:flutter/material.dart"; +import "package:photos/models/file/file.dart"; +import "package:photos/ui/viewer/file/thumbnail_widget.dart"; + +class ShowImagePreviewFromTap extends StatelessWidget { + const ShowImagePreviewFromTap({ + required this.tempEnteFile, + super.key, + }); + + final List tempEnteFile; + + @override + Widget build(BuildContext context) { + final int length = tempEnteFile.length; + Widget placeholderWidget = const SizedBox( + height: 300, // Adjusted height + width: 300, // Adjusted width + ); + + if (length == 1) { + placeholderWidget = AspectRatio( + aspectRatio: 1, + child: BackDrop( + backDropImage: tempEnteFile[0], + children: [ + Padding( + padding: const EdgeInsets.all(18.0), + child: Container( + decoration: BoxDecoration( + borderRadius: + BorderRadius.circular(20.0), // Increased border radius + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.5), + spreadRadius: 1, + blurRadius: 1, + offset: const Offset(1, 1), + ), + BoxShadow( + color: Colors.black.withOpacity(0.5), + spreadRadius: 1, + blurRadius: 1, + offset: const Offset(-1, -1), + ), + ], + ), + child: ClipSmoothRect( + radius: SmoothBorderRadius( + cornerRadius: 15, + cornerSmoothing: 1, + ), + child: ThumbnailWidget( + tempEnteFile[0], + shouldShowArchiveStatus: false, + shouldShowSyncStatus: false, + ), + ), + ), + ), + ], + ), + ); + } else if (length == 2) { + placeholderWidget = AspectRatio( + aspectRatio: 1, + child: BackDrop( + backDropImage: tempEnteFile[0], + children: [ + Positioned( + right: 20, + bottom: 50, + child: CustomImage( + height: 190, + width: 190, + collages: tempEnteFile[1], + zIndex: 0.2, + ), + ), + Positioned( + top: 50, + left: 20, + child: CustomImage( + height: 190, + width: 190, + collages: tempEnteFile[0], + zIndex: -0.2, + ), + ), + ], + ), + ); + } else if (length == 3) { + placeholderWidget = AspectRatio( + aspectRatio: 1, + child: BackDrop( + backDropImage: tempEnteFile[0], + children: [ + //left image + Positioned( + top: 55, + left: 10, + child: CustomImage( + height: 160, + width: 160, + collages: tempEnteFile[1], + zIndex: -0.3, + ), + ), + //right image + Positioned( + right: 10, + bottom: 50, + child: CustomImage( + height: 160, + width: 160, + collages: tempEnteFile[2], + zIndex: 0.3, + ), + ), + //center image + Positioned( + top: 100, + left: 100, + child: CustomImage( + height: 175, + width: 175, + collages: tempEnteFile[0], + zIndex: 0.0, + ), + ), + ], + ), + ); + } else if (length > 3) { + placeholderWidget = Padding( + padding: const EdgeInsets.all(8.0), + child: AspectRatio( + aspectRatio: 1, + child: BackDrop( + backDropImage: tempEnteFile[0], + children: [ + Positioned( + top: 20, + left: 20, + child: CustomImage( + height: 160, + width: 160, + collages: tempEnteFile[1], + zIndex: 0, + ), + ), + Positioned( + bottom: 15, + left: 40, + child: CustomImage( + height: 160, + width: 160, + collages: tempEnteFile[2], + zIndex: 0, + ), + ), + Positioned( + top: 75, + right: 30, + child: CustomImage( + height: 175, + width: 175, + collages: tempEnteFile[0], + zIndex: 0.0, + ), + ), + Positioned( + bottom: 30, + right: 40, + child: ClipSmoothRect( + radius: SmoothBorderRadius( + cornerRadius: 7.5, + cornerSmoothing: 1, + ), + child: Container( + color: Colors.white, + height: 50, + width: 50, + child: Center( + child: Text( + "+" "$length", + style: const TextStyle( + fontWeight: FontWeight.w600, + fontSize: 24, + color: Colors.black, + ), + ), + ), + ), + ), + ), + ], + ), + ), + ); + } + + return placeholderWidget; + } +} + +class BackDrop extends StatelessWidget { + const BackDrop({ + super.key, + required this.backDropImage, + required this.children, + }); + + final List children; + final EnteFile backDropImage; + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + ThumbnailWidget( + backDropImage, + shouldShowArchiveStatus: false, + shouldShowSyncStatus: false, + ), + BackdropFilter( + filter: ImageFilter.blur(sigmaX: 12, sigmaY: 12), // Increased blur + child: Container( + color: Colors.transparent, + ), + ), + ...children, + ], + ); + } +} + +class CustomImage extends StatelessWidget { + const CustomImage({ + required this.width, + required this.height, + super.key, + required this.collages, + required this.zIndex, + }); + + final EnteFile collages; + final double zIndex; + final double height; + final double width; + + @override + Widget build(BuildContext context) { + return Container( + transform: Matrix4.rotationZ(zIndex), + height: height, + width: width, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20.0), // Increased border radius + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.5), + spreadRadius: 1, + blurRadius: 1, + offset: const Offset(1, 1), + ), + BoxShadow( + color: Colors.black.withOpacity(0.5), + spreadRadius: 1, + blurRadius: 1, + offset: const Offset(-1, -1), + ), + ], + ), + child: ClipSmoothRect( + radius: SmoothBorderRadius( + cornerRadius: 20.0, // Increased corner radius + cornerSmoothing: 1, + ), + clipBehavior: Clip.antiAliasWithSaveLayer, + child: ThumbnailWidget( + collages, + shouldShowArchiveStatus: false, + shouldShowSyncStatus: false, + ), + ), + ); + } +} diff --git a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart index 6c17ededbc..a6ad143d28 100644 --- a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart +++ b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart @@ -1,4 +1,5 @@ import "dart:async"; +import "dart:io"; import 'package:fast_base58/fast_base58.dart'; import "package:flutter/cupertino.dart"; @@ -6,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import "package:logging/logging.dart"; import "package:modal_bottom_sheet/modal_bottom_sheet.dart"; +import "package:path_provider/path_provider.dart"; import 'package:photos/core/configuration.dart'; import "package:photos/core/event_bus.dart"; import "package:photos/events/people_changed_event.dart"; @@ -25,7 +27,6 @@ import 'package:photos/services/machine_learning/face_ml/feedback/cluster_feedba import "package:photos/services/machine_learning/face_ml/person/person_service.dart"; import "package:photos/theme/colors.dart"; import "package:photos/theme/ente_theme.dart"; -import "package:photos/ui/TEMP/show_images_prevew.dart"; import 'package:photos/ui/actions/collection/collection_file_actions.dart'; import 'package:photos/ui/actions/collection/collection_sharing_actions.dart'; import 'package:photos/ui/collections/collection_action_sheet.dart'; @@ -34,6 +35,7 @@ import "package:photos/ui/components/bottom_action_bar/selection_action_button_w import 'package:photos/ui/components/buttons/button_widget.dart'; import 'package:photos/ui/components/models/button_type.dart'; import 'package:photos/ui/sharing/manage_links_widget.dart'; +import "package:photos/ui/sharing/show_images_prevew.dart"; import "package:photos/ui/tools/collage/collage_creator_page.dart"; import "package:photos/ui/viewer/location/update_location_data_widget.dart"; import 'package:photos/utils/delete_file_util.dart'; @@ -43,6 +45,7 @@ import 'package:photos/utils/magic_util.dart'; import 'package:photos/utils/navigation_util.dart'; import "package:photos/utils/share_util.dart"; import 'package:photos/utils/toast_util.dart'; +import "package:screenshot/screenshot.dart"; class FileSelectionActionsWidget extends StatefulWidget { final GalleryType type; @@ -74,7 +77,7 @@ class _FileSelectionActionsWidgetState late FilesSplit split; late CollectionActions collectionActions; late bool isCollectionOwner; - + ScreenshotController screenshotController = ScreenshotController(); // _cachedCollectionForSharedLink is primarily used to avoid creating duplicate // links if user keeps on creating Create link button after selecting // few files. This link is reset on any selection changed; @@ -603,22 +606,39 @@ class _FileSelectionActionsWidgetState } } + Future saveImage(Uint8List bytes) async { + String path = ""; + try { + final Directory root = await getTemporaryDirectory(); + final String directoryPath = '${root.path}/enteTempFiles'; + // Create the directory if it doesn't exist + final DateTime timeStamp = DateTime.now(); + await Directory(directoryPath).create(recursive: true); + final String filePath = '$directoryPath/$timeStamp.jpg'; + final file = await File(filePath).writeAsBytes(bytes!); + path = file.path; + } catch (e) { + debugPrint(e.toString()); + } + return path; + } + ValueNotifier generatedPathNotifier = ValueNotifier(null); //Future function to go to next page Future _nextPageForTesting(List tempfile) async { - final String? tempImagePath = await Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => ShowImagePreviewFromTap( - tempEnteFile: tempfile, - ), - ), + final Widget imageWidget = ShowImagePreviewFromTap( + tempEnteFile: tempfile, + ); + await Future.delayed(const Duration(milliseconds: 100)); + final double pixelRatio = MediaQuery.of(context).devicePixelRatio; + final bytesOfImageToWidget = await screenshotController.captureFromWidget( + imageWidget, + pixelRatio: pixelRatio, + targetSize: MediaQuery.of(context).size, + delay: const Duration(milliseconds: 100), ); - if (tempImagePath != null) { - print("Temp image path: $tempImagePath"); - - return tempImagePath; - } + final String tempImagePath = await saveImage(bytesOfImageToWidget); return tempImagePath; } @@ -645,13 +665,6 @@ class _FileSelectionActionsWidgetState shouldStickToDarkTheme: true, buttonAction: ButtonAction.first, isInAlert: true, - // onTap: () async { - // // Add a return statement at the end of the function - // generatedPathNotifier.value = - // await _nextPageForTesting(tempEnteFile); - // await shareText(generatedPathNotifier.value!); - // return Future.value(); - // }, ), ButtonWidget( labelText: S.of(context).manageLink, @@ -676,7 +689,7 @@ class _FileSelectionActionsWidgetState ); if (actionResult?.action != null) { if (actionResult!.action == ButtonAction.first) { - //generatedPathNotifier.value = await _nextPageForTesting(tempEnteFile); + generatedPathNotifier.value = await _nextPageForTesting(tempEnteFile); await _copyLink(); } if (actionResult.action == ButtonAction.second) { @@ -796,8 +809,8 @@ class _FileSelectionActionsWidgetState ); final String url = "${_cachedCollectionForSharedLink!.publicURLs?.first?.url}#$collectionKey"; - await shareText(url); - //await shareImageAndUrl(context, generatedPathNotifier.value!, url); + //await shareText(url); + await shareImageAndUrl(context, generatedPathNotifier.value!, url); await Clipboard.setData(ClipboardData(text: url)); showShortToast(context, S.of(context).linkCopiedToClipboard); } diff --git a/mobile/pubspec.lock b/mobile/pubspec.lock index 1d1082bfd3..6d6d0621d8 100644 --- a/mobile/pubspec.lock +++ b/mobile/pubspec.lock @@ -1863,6 +1863,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.3" + screenshot: + dependency: "direct main" + description: + name: screenshot + sha256: d448f43130f49bc7eead1b267b3ea0291cb2450f037bb0a0ecce7aa4c65e2aee + url: "https://pub.dev" + source: hosted + version: "2.5.0" scrollable_positioned_list: dependency: "direct main" description: diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index 211d744ccc..f8d9c67c54 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -141,10 +141,11 @@ dependencies: provider: ^6.0.0 quiver: ^3.0.1 receive_sharing_intent: ^1.7.0 + screenshot: ^2.4.0 scrollable_positioned_list: ^0.3.5 sentry: ^7.9.0 sentry_flutter: ^7.9.0 - share_plus: 7.2.2 + share_plus: 7.2.2 shared_preferences: ^2.0.5 simple_cluster: ^0.3.0 sqflite: ^2.3.0 From 7f816e80a2f25fd8fcaecbfce9d7c5a2c5d00102 Mon Sep 17 00:00:00 2001 From: Aman Raj Singh Mourya Date: Thu, 30 May 2024 12:48:07 +0530 Subject: [PATCH 03/22] [mob][photos] share placeholder with link when sharing 2nd draft --- .../collection_sharing_actions.dart | 1 - mobile/lib/ui/sharing/show_images_prevew.dart | 32 +++++++++---------- .../file_selection_actions_widget.dart | 26 ++++++++------- mobile/lib/utils/share_util.dart | 1 - 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/mobile/lib/ui/actions/collection/collection_sharing_actions.dart b/mobile/lib/ui/actions/collection/collection_sharing_actions.dart index 0d571c2d87..3328722dbe 100644 --- a/mobile/lib/ui/actions/collection/collection_sharing_actions.dart +++ b/mobile/lib/ui/actions/collection/collection_sharing_actions.dart @@ -110,7 +110,6 @@ class CollectionActions { BuildContext context, List files, ) async { - print("CREATED LINK"); final dialog = createProgressDialog( context, S.of(context).creatingLink, diff --git a/mobile/lib/ui/sharing/show_images_prevew.dart b/mobile/lib/ui/sharing/show_images_prevew.dart index 7b0632554a..e779df80d1 100644 --- a/mobile/lib/ui/sharing/show_images_prevew.dart +++ b/mobile/lib/ui/sharing/show_images_prevew.dart @@ -7,15 +7,15 @@ import "package:photos/ui/viewer/file/thumbnail_widget.dart"; class ShowImagePreviewFromTap extends StatelessWidget { const ShowImagePreviewFromTap({ - required this.tempEnteFile, + required this.ownedSelectedFiles, super.key, }); - final List tempEnteFile; + final List ownedSelectedFiles; @override Widget build(BuildContext context) { - final int length = tempEnteFile.length; + final int length = ownedSelectedFiles.length; Widget placeholderWidget = const SizedBox( height: 300, // Adjusted height width: 300, // Adjusted width @@ -25,7 +25,7 @@ class ShowImagePreviewFromTap extends StatelessWidget { placeholderWidget = AspectRatio( aspectRatio: 1, child: BackDrop( - backDropImage: tempEnteFile[0], + backDropImage: ownedSelectedFiles[0], children: [ Padding( padding: const EdgeInsets.all(18.0), @@ -54,7 +54,7 @@ class ShowImagePreviewFromTap extends StatelessWidget { cornerSmoothing: 1, ), child: ThumbnailWidget( - tempEnteFile[0], + ownedSelectedFiles[0], shouldShowArchiveStatus: false, shouldShowSyncStatus: false, ), @@ -68,7 +68,7 @@ class ShowImagePreviewFromTap extends StatelessWidget { placeholderWidget = AspectRatio( aspectRatio: 1, child: BackDrop( - backDropImage: tempEnteFile[0], + backDropImage: ownedSelectedFiles[0], children: [ Positioned( right: 20, @@ -76,7 +76,7 @@ class ShowImagePreviewFromTap extends StatelessWidget { child: CustomImage( height: 190, width: 190, - collages: tempEnteFile[1], + collages: ownedSelectedFiles[1], zIndex: 0.2, ), ), @@ -86,7 +86,7 @@ class ShowImagePreviewFromTap extends StatelessWidget { child: CustomImage( height: 190, width: 190, - collages: tempEnteFile[0], + collages: ownedSelectedFiles[0], zIndex: -0.2, ), ), @@ -97,7 +97,7 @@ class ShowImagePreviewFromTap extends StatelessWidget { placeholderWidget = AspectRatio( aspectRatio: 1, child: BackDrop( - backDropImage: tempEnteFile[0], + backDropImage: ownedSelectedFiles[0], children: [ //left image Positioned( @@ -106,7 +106,7 @@ class ShowImagePreviewFromTap extends StatelessWidget { child: CustomImage( height: 160, width: 160, - collages: tempEnteFile[1], + collages: ownedSelectedFiles[1], zIndex: -0.3, ), ), @@ -117,7 +117,7 @@ class ShowImagePreviewFromTap extends StatelessWidget { child: CustomImage( height: 160, width: 160, - collages: tempEnteFile[2], + collages: ownedSelectedFiles[2], zIndex: 0.3, ), ), @@ -128,7 +128,7 @@ class ShowImagePreviewFromTap extends StatelessWidget { child: CustomImage( height: 175, width: 175, - collages: tempEnteFile[0], + collages: ownedSelectedFiles[0], zIndex: 0.0, ), ), @@ -141,7 +141,7 @@ class ShowImagePreviewFromTap extends StatelessWidget { child: AspectRatio( aspectRatio: 1, child: BackDrop( - backDropImage: tempEnteFile[0], + backDropImage: ownedSelectedFiles[0], children: [ Positioned( top: 20, @@ -149,7 +149,7 @@ class ShowImagePreviewFromTap extends StatelessWidget { child: CustomImage( height: 160, width: 160, - collages: tempEnteFile[1], + collages: ownedSelectedFiles[1], zIndex: 0, ), ), @@ -159,7 +159,7 @@ class ShowImagePreviewFromTap extends StatelessWidget { child: CustomImage( height: 160, width: 160, - collages: tempEnteFile[2], + collages: ownedSelectedFiles[2], zIndex: 0, ), ), @@ -169,7 +169,7 @@ class ShowImagePreviewFromTap extends StatelessWidget { child: CustomImage( height: 175, width: 175, - collages: tempEnteFile[0], + collages: ownedSelectedFiles[0], zIndex: 0.0, ), ), diff --git a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart index a6ad143d28..274ef87cd7 100644 --- a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart +++ b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart @@ -99,6 +99,7 @@ class _FileSelectionActionsWidgetState @override void dispose() { widget.selectedFiles.removeListener(_selectFileChangeListener); + generatedPathNotifier.dispose(); super.dispose(); } @@ -615,7 +616,7 @@ class _FileSelectionActionsWidgetState final DateTime timeStamp = DateTime.now(); await Directory(directoryPath).create(recursive: true); final String filePath = '$directoryPath/$timeStamp.jpg'; - final file = await File(filePath).writeAsBytes(bytes!); + final file = await File(filePath).writeAsBytes(bytes); path = file.path; } catch (e) { debugPrint(e.toString()); @@ -624,22 +625,24 @@ class _FileSelectionActionsWidgetState } ValueNotifier generatedPathNotifier = ValueNotifier(null); -//Future function to go to next page - Future _nextPageForTesting(List tempfile) async { + + Future _selectedFilePlaceholderPath( + List ownedSelectedFiles, + ) async { final Widget imageWidget = ShowImagePreviewFromTap( - tempEnteFile: tempfile, + ownedSelectedFiles: ownedSelectedFiles, ); await Future.delayed(const Duration(milliseconds: 100)); final double pixelRatio = MediaQuery.of(context).devicePixelRatio; final bytesOfImageToWidget = await screenshotController.captureFromWidget( imageWidget, pixelRatio: pixelRatio, - targetSize: MediaQuery.of(context).size, + targetSize: MediaQuery.sizeOf(context), delay: const Duration(milliseconds: 100), ); - final String tempImagePath = await saveImage(bytesOfImageToWidget); - return tempImagePath; + final String onCreateLinkTapped = await saveImage(bytesOfImageToWidget); + return onCreateLinkTapped; } Future _onCreatedSharedLinkClicked() async { @@ -653,7 +656,7 @@ class _FileSelectionActionsWidgetState _cachedCollectionForSharedLink ??= await collectionActions .createSharedCollectionLink(context, split.ownedByCurrentUser); - final List tempEnteFile = split.ownedByCurrentUser; + final List ownedSelectedFiles = split.ownedByCurrentUser; final actionResult = await showActionSheet( context: context, @@ -689,7 +692,8 @@ class _FileSelectionActionsWidgetState ); if (actionResult?.action != null) { if (actionResult!.action == ButtonAction.first) { - generatedPathNotifier.value = await _nextPageForTesting(tempEnteFile); + generatedPathNotifier.value = + await _selectedFilePlaceholderPath(ownedSelectedFiles); await _copyLink(); } if (actionResult.action == ButtonAction.second) { @@ -801,7 +805,6 @@ class _FileSelectionActionsWidgetState } Future _copyLink() async { - print("INSIDE COPY LINK"); if (_cachedCollectionForSharedLink != null) { final String collectionKey = Base58Encode( CollectionsService.instance @@ -809,8 +812,7 @@ class _FileSelectionActionsWidgetState ); final String url = "${_cachedCollectionForSharedLink!.publicURLs?.first?.url}#$collectionKey"; - //await shareText(url); - await shareImageAndUrl(context, generatedPathNotifier.value!, url); + await shareImageAndUrl(generatedPathNotifier.value!, url); await Clipboard.setData(ClipboardData(text: url)); showShortToast(context, S.of(context).linkCopiedToClipboard); } diff --git a/mobile/lib/utils/share_util.dart b/mobile/lib/utils/share_util.dart index b94ac33235..aeb1e6bdab 100644 --- a/mobile/lib/utils/share_util.dart +++ b/mobile/lib/utils/share_util.dart @@ -220,7 +220,6 @@ void shareSelected( } Future shareImageAndUrl( - BuildContext context, String imagePath, String url, ) async { From 5099dfdd743221c8ad7cf4ad0033e51383aa8811 Mon Sep 17 00:00:00 2001 From: Aman Raj Singh Mourya Date: Thu, 30 May 2024 14:03:40 +0530 Subject: [PATCH 04/22] [mob][photos] added delete function for placeholder image --- mobile/lib/ui/sharing/show_images_prevew.dart | 84 +++++++++---------- .../file_selection_actions_widget.dart | 21 +++-- 2 files changed, 56 insertions(+), 49 deletions(-) diff --git a/mobile/lib/ui/sharing/show_images_prevew.dart b/mobile/lib/ui/sharing/show_images_prevew.dart index e779df80d1..b95700bd9e 100644 --- a/mobile/lib/ui/sharing/show_images_prevew.dart +++ b/mobile/lib/ui/sharing/show_images_prevew.dart @@ -5,34 +5,33 @@ import "package:flutter/material.dart"; import "package:photos/models/file/file.dart"; import "package:photos/ui/viewer/file/thumbnail_widget.dart"; -class ShowImagePreviewFromTap extends StatelessWidget { - const ShowImagePreviewFromTap({ - required this.ownedSelectedFiles, +class LinkPlaceholder extends StatelessWidget { + const LinkPlaceholder({ + required this.files, super.key, }); - final List ownedSelectedFiles; + final List files; @override Widget build(BuildContext context) { - final int length = ownedSelectedFiles.length; + final int length = files.length; Widget placeholderWidget = const SizedBox( - height: 300, // Adjusted height - width: 300, // Adjusted width + height: 300, + width: 300, ); if (length == 1) { placeholderWidget = AspectRatio( aspectRatio: 1, - child: BackDrop( - backDropImage: ownedSelectedFiles[0], + child: _BackDrop( + backDropImage: files[0], children: [ Padding( padding: const EdgeInsets.all(18.0), child: Container( decoration: BoxDecoration( - borderRadius: - BorderRadius.circular(20.0), // Increased border radius + borderRadius: BorderRadius.circular(20.0), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.5), @@ -54,7 +53,7 @@ class ShowImagePreviewFromTap extends StatelessWidget { cornerSmoothing: 1, ), child: ThumbnailWidget( - ownedSelectedFiles[0], + files[0], shouldShowArchiveStatus: false, shouldShowSyncStatus: false, ), @@ -67,26 +66,26 @@ class ShowImagePreviewFromTap extends StatelessWidget { } else if (length == 2) { placeholderWidget = AspectRatio( aspectRatio: 1, - child: BackDrop( - backDropImage: ownedSelectedFiles[0], + child: _BackDrop( + backDropImage: files[0], children: [ Positioned( right: 20, bottom: 50, - child: CustomImage( + child: _CustomImage( height: 190, width: 190, - collages: ownedSelectedFiles[1], + collages: files[1], zIndex: 0.2, ), ), Positioned( top: 50, left: 20, - child: CustomImage( + child: _CustomImage( height: 190, width: 190, - collages: ownedSelectedFiles[0], + collages: files[0], zIndex: -0.2, ), ), @@ -96,39 +95,36 @@ class ShowImagePreviewFromTap extends StatelessWidget { } else if (length == 3) { placeholderWidget = AspectRatio( aspectRatio: 1, - child: BackDrop( - backDropImage: ownedSelectedFiles[0], + child: _BackDrop( + backDropImage: files[0], children: [ - //left image Positioned( top: 55, left: 10, - child: CustomImage( + child: _CustomImage( height: 160, width: 160, - collages: ownedSelectedFiles[1], + collages: files[1], zIndex: -0.3, ), ), - //right image Positioned( right: 10, bottom: 50, - child: CustomImage( + child: _CustomImage( height: 160, width: 160, - collages: ownedSelectedFiles[2], + collages: files[2], zIndex: 0.3, ), ), - //center image Positioned( top: 100, left: 100, - child: CustomImage( + child: _CustomImage( height: 175, width: 175, - collages: ownedSelectedFiles[0], + collages: files[0], zIndex: 0.0, ), ), @@ -140,36 +136,36 @@ class ShowImagePreviewFromTap extends StatelessWidget { padding: const EdgeInsets.all(8.0), child: AspectRatio( aspectRatio: 1, - child: BackDrop( - backDropImage: ownedSelectedFiles[0], + child: _BackDrop( + backDropImage: files[0], children: [ Positioned( top: 20, left: 20, - child: CustomImage( + child: _CustomImage( height: 160, width: 160, - collages: ownedSelectedFiles[1], + collages: files[1], zIndex: 0, ), ), Positioned( bottom: 15, left: 40, - child: CustomImage( + child: _CustomImage( height: 160, width: 160, - collages: ownedSelectedFiles[2], + collages: files[2], zIndex: 0, ), ), Positioned( top: 75, right: 30, - child: CustomImage( + child: _CustomImage( height: 175, width: 175, - collages: ownedSelectedFiles[0], + collages: files[0], zIndex: 0.0, ), ), @@ -208,8 +204,8 @@ class ShowImagePreviewFromTap extends StatelessWidget { } } -class BackDrop extends StatelessWidget { - const BackDrop({ +class _BackDrop extends StatelessWidget { + const _BackDrop({ super.key, required this.backDropImage, required this.children, @@ -228,7 +224,7 @@ class BackDrop extends StatelessWidget { shouldShowSyncStatus: false, ), BackdropFilter( - filter: ImageFilter.blur(sigmaX: 12, sigmaY: 12), // Increased blur + filter: ImageFilter.blur(sigmaX: 12, sigmaY: 12), child: Container( color: Colors.transparent, ), @@ -239,8 +235,8 @@ class BackDrop extends StatelessWidget { } } -class CustomImage extends StatelessWidget { - const CustomImage({ +class _CustomImage extends StatelessWidget { + const _CustomImage({ required this.width, required this.height, super.key, @@ -260,7 +256,7 @@ class CustomImage extends StatelessWidget { height: height, width: width, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20.0), // Increased border radius + borderRadius: BorderRadius.circular(20.0), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.5), @@ -278,7 +274,7 @@ class CustomImage extends StatelessWidget { ), child: ClipSmoothRect( radius: SmoothBorderRadius( - cornerRadius: 20.0, // Increased corner radius + cornerRadius: 20.0, cornerSmoothing: 1, ), clipBehavior: Clip.antiAliasWithSaveLayer, diff --git a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart index 274ef87cd7..7a44b37075 100644 --- a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart +++ b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart @@ -170,7 +170,7 @@ class _FileSelectionActionsWidgetState SelectionActionButton( icon: Icons.link_outlined, labelText: S.of(context).shareLink, - onTap: anyUploadedFiles ? _onCreatedSharedLinkClicked : null, + onTap: anyUploadedFiles ? _onCreateLinkTapped : null, shouldShow: ownedFilesCount > 0, ), ); @@ -612,7 +612,6 @@ class _FileSelectionActionsWidgetState try { final Directory root = await getTemporaryDirectory(); final String directoryPath = '${root.path}/enteTempFiles'; - // Create the directory if it doesn't exist final DateTime timeStamp = DateTime.now(); await Directory(directoryPath).create(recursive: true); final String filePath = '$directoryPath/$timeStamp.jpg'; @@ -629,8 +628,8 @@ class _FileSelectionActionsWidgetState Future _selectedFilePlaceholderPath( List ownedSelectedFiles, ) async { - final Widget imageWidget = ShowImagePreviewFromTap( - ownedSelectedFiles: ownedSelectedFiles, + final Widget imageWidget = LinkPlaceholder( + files: ownedSelectedFiles, ); await Future.delayed(const Duration(milliseconds: 100)); final double pixelRatio = MediaQuery.of(context).devicePixelRatio; @@ -645,7 +644,7 @@ class _FileSelectionActionsWidgetState return onCreateLinkTapped; } - Future _onCreatedSharedLinkClicked() async { + Future _onCreateLinkTapped() async { if (split.ownedByCurrentUser.isEmpty) { showShortToast( context, @@ -815,6 +814,18 @@ class _FileSelectionActionsWidgetState await shareImageAndUrl(generatedPathNotifier.value!, url); await Clipboard.setData(ClipboardData(text: url)); showShortToast(context, S.of(context).linkCopiedToClipboard); + if (generatedPathNotifier.value != null) { + final file = File(generatedPathNotifier.value!); + try { + if (await file.exists()) { + await file.delete(); + } + } catch (e) { + debugPrint("Failed to delete the file: $e"); + } finally { + generatedPathNotifier.value = null; + } + } } } From 3c5ba5b94ead7d85945499397fc0b851b284bac0 Mon Sep 17 00:00:00 2001 From: Aman Raj Singh Mourya Date: Thu, 30 May 2024 19:18:00 +0530 Subject: [PATCH 05/22] [mob][photos] changed variable and function name --- .../file_selection_actions_widget.dart | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart index 7a44b37075..ac9cdfc38b 100644 --- a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart +++ b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart @@ -77,7 +77,8 @@ class _FileSelectionActionsWidgetState late FilesSplit split; late CollectionActions collectionActions; late bool isCollectionOwner; - ScreenshotController screenshotController = ScreenshotController(); + final ScreenshotController screenshotController = ScreenshotController(); + late String? placeholderPath; // _cachedCollectionForSharedLink is primarily used to avoid creating duplicate // links if user keeps on creating Create link button after selecting // few files. This link is reset on any selection changed; @@ -99,7 +100,6 @@ class _FileSelectionActionsWidgetState @override void dispose() { widget.selectedFiles.removeListener(_selectFileChangeListener); - generatedPathNotifier.dispose(); super.dispose(); } @@ -162,7 +162,7 @@ class _FileSelectionActionsWidgetState SelectionActionButton( icon: Icons.copy_outlined, labelText: S.of(context).copyLink, - onTap: anyUploadedFiles ? _copyLink : null, + onTap: anyUploadedFiles ? _sendLink : null, ), ); } else { @@ -618,14 +618,12 @@ class _FileSelectionActionsWidgetState final file = await File(filePath).writeAsBytes(bytes); path = file.path; } catch (e) { - debugPrint(e.toString()); + _logger.severe("Failed to save placeholder image", e); } return path; } - ValueNotifier generatedPathNotifier = ValueNotifier(null); - - Future _selectedFilePlaceholderPath( + Future _selectedFilesPlaceholderPath( List ownedSelectedFiles, ) async { final Widget imageWidget = LinkPlaceholder( @@ -640,8 +638,9 @@ class _FileSelectionActionsWidgetState delay: const Duration(milliseconds: 100), ); - final String onCreateLinkTapped = await saveImage(bytesOfImageToWidget); - return onCreateLinkTapped; + final String onCreatedPlaceholderPath = + await saveImage(bytesOfImageToWidget); + return onCreatedPlaceholderPath; } Future _onCreateLinkTapped() async { @@ -691,9 +690,9 @@ class _FileSelectionActionsWidgetState ); if (actionResult?.action != null) { if (actionResult!.action == ButtonAction.first) { - generatedPathNotifier.value = - await _selectedFilePlaceholderPath(ownedSelectedFiles); - await _copyLink(); + placeholderPath = + await _selectedFilesPlaceholderPath(ownedSelectedFiles); + await _sendLink(); } if (actionResult.action == ButtonAction.second) { await routeToPage( @@ -803,7 +802,7 @@ class _FileSelectionActionsWidgetState } } - Future _copyLink() async { + Future _sendLink() async { if (_cachedCollectionForSharedLink != null) { final String collectionKey = Base58Encode( CollectionsService.instance @@ -811,19 +810,19 @@ class _FileSelectionActionsWidgetState ); final String url = "${_cachedCollectionForSharedLink!.publicURLs?.first?.url}#$collectionKey"; - await shareImageAndUrl(generatedPathNotifier.value!, url); + await shareImageAndUrl(placeholderPath!, url); await Clipboard.setData(ClipboardData(text: url)); showShortToast(context, S.of(context).linkCopiedToClipboard); - if (generatedPathNotifier.value != null) { - final file = File(generatedPathNotifier.value!); + if (placeholderPath != null) { + final file = File(placeholderPath!); try { - if (await file.exists()) { - await file.delete(); + if (file.existsSync()) { + file.deleteSync(); } } catch (e) { - debugPrint("Failed to delete the file: $e"); + _logger.warning("Failed to delete the file: $e"); } finally { - generatedPathNotifier.value = null; + placeholderPath = null; } } } From ebf83b7bba5573b716dc869fd8f4dae2e4299f55 Mon Sep 17 00:00:00 2001 From: Aman Raj Singh Mourya Date: Mon, 3 Jun 2024 12:15:43 +0530 Subject: [PATCH 06/22] [mob][photos] merge placeholder_for_link2 --- mobile/lib/ui/sharing/show_images_prevew.dart | 539 +++++++++++------- mobile/lib/utils/share_util.dart | 2 +- 2 files changed, 327 insertions(+), 214 deletions(-) diff --git a/mobile/lib/ui/sharing/show_images_prevew.dart b/mobile/lib/ui/sharing/show_images_prevew.dart index b95700bd9e..fc68f66843 100644 --- a/mobile/lib/ui/sharing/show_images_prevew.dart +++ b/mobile/lib/ui/sharing/show_images_prevew.dart @@ -1,7 +1,9 @@ +import 'dart:math' as math; import "dart:ui"; import "package:figma_squircle/figma_squircle.dart"; import "package:flutter/material.dart"; +import "package:photos/core/constants.dart"; import "package:photos/models/file/file.dart"; import "package:photos/ui/viewer/file/thumbnail_widget.dart"; @@ -22,181 +24,276 @@ class LinkPlaceholder extends StatelessWidget { ); if (length == 1) { - placeholderWidget = AspectRatio( - aspectRatio: 1, - child: _BackDrop( - backDropImage: files[0], - children: [ - Padding( - padding: const EdgeInsets.all(18.0), - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20.0), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.5), - spreadRadius: 1, - blurRadius: 1, - offset: const Offset(1, 1), - ), - BoxShadow( - color: Colors.black.withOpacity(0.5), - spreadRadius: 1, - blurRadius: 1, - offset: const Offset(-1, -1), - ), - ], + placeholderWidget = _BackDrop( + backDropImage: files[0], + children: [ + LayoutBuilder( + builder: (context, constraints) { + final imageHeight = constraints.maxHeight * 0.9; + return Center( + child: _CustomImage( + width: imageHeight, + height: imageHeight, + file: files[0], + zIndex: 0, ), - child: ClipSmoothRect( - radius: SmoothBorderRadius( - cornerRadius: 15, - cornerSmoothing: 1, - ), - child: ThumbnailWidget( - files[0], - shouldShowArchiveStatus: false, - shouldShowSyncStatus: false, - ), - ), - ), - ), - ], - ), + ); + }, + ), + ], ); } else if (length == 2) { - placeholderWidget = AspectRatio( - aspectRatio: 1, - child: _BackDrop( - backDropImage: files[0], - children: [ - Positioned( - right: 20, - bottom: 50, - child: _CustomImage( - height: 190, - width: 190, - collages: files[1], - zIndex: 0.2, - ), - ), - Positioned( - top: 50, - left: 20, - child: _CustomImage( - height: 190, - width: 190, - collages: files[0], - zIndex: -0.2, - ), - ), - ], - ), - ); - } else if (length == 3) { - placeholderWidget = AspectRatio( - aspectRatio: 1, - child: _BackDrop( - backDropImage: files[0], - children: [ - Positioned( - top: 55, - left: 10, - child: _CustomImage( - height: 160, - width: 160, - collages: files[1], - zIndex: -0.3, - ), - ), - Positioned( - right: 10, - bottom: 50, - child: _CustomImage( - height: 160, - width: 160, - collages: files[2], - zIndex: 0.3, - ), - ), - Positioned( - top: 100, - left: 100, - child: _CustomImage( - height: 175, - width: 175, - collages: files[0], - zIndex: 0.0, - ), - ), - ], - ), - ); - } else if (length > 3) { - placeholderWidget = Padding( - padding: const EdgeInsets.all(8.0), - child: AspectRatio( - aspectRatio: 1, - child: _BackDrop( - backDropImage: files[0], - children: [ - Positioned( - top: 20, - left: 20, - child: _CustomImage( - height: 160, - width: 160, - collages: files[1], - zIndex: 0, - ), - ), - Positioned( - bottom: 15, - left: 40, - child: _CustomImage( - height: 160, - width: 160, - collages: files[2], - zIndex: 0, - ), - ), - Positioned( - top: 75, - right: 30, - child: _CustomImage( - height: 175, - width: 175, - collages: files[0], - zIndex: 0.0, - ), - ), - Positioned( - bottom: 30, - right: 40, - child: ClipSmoothRect( - radius: SmoothBorderRadius( - cornerRadius: 7.5, - cornerSmoothing: 1, - ), - child: Container( - color: Colors.white, - height: 50, - width: 50, - child: Center( - child: Text( - "+" "$length", - style: const TextStyle( - fontWeight: FontWeight.w600, - fontSize: 24, - color: Colors.black, - ), - ), + placeholderWidget = _BackDrop( + backDropImage: files[0], + children: [ + LayoutBuilder( + builder: ((context, constraints) { + final imageHeight = constraints.maxHeight * 0.52; + return Stack( + children: [ + Positioned( + top: 145, + left: 180, + child: _CustomImage( + height: imageHeight, + width: imageHeight, + file: files[1], + zIndex: 10 * math.pi / 180, ), ), - ), - ), - ], + Positioned( + top: 45, + left: 3.2, + child: _CustomImage( + height: imageHeight, + width: imageHeight, + file: files[0], + zIndex: -(10 * math.pi / 180), + imageShadow: const [ + BoxShadow( + offset: Offset(0, 0), + blurRadius: 0.84, + color: Color.fromRGBO(0, 0, 0, 0.11), + ), + BoxShadow( + offset: Offset(0.84, 0.84), + blurRadius: 1.68, + color: Color.fromRGBO(0, 0, 0, 0.09), + ), + BoxShadow( + offset: Offset(2.53, 2.53), + blurRadius: 2.53, + color: Color.fromRGBO(0, 0, 0, 0.05), + ), + BoxShadow( + offset: Offset(5.05, 4.21), + blurRadius: 2.53, + color: Color.fromRGBO(0, 0, 0, 0.02), + ), + BoxShadow( + offset: Offset(7.58, 6.74), + blurRadius: 2.53, + color: Color.fromRGBO(0, 0, 0, 0.0), + ), + ], + ), + ), + ], + ); + }), ), - ), + ], + ); + } else if (length == 3) { + placeholderWidget = _BackDrop( + backDropImage: files[0], + children: [ + LayoutBuilder( + builder: (context, constraint) { + final imageHeightSmall = constraint.maxHeight * 0.43; + final imageHeightLarge = constraint.maxHeight * 0.50; + return Stack( + children: [ + Positioned( + top: 55, + child: _CustomImage( + height: imageHeightSmall, + width: imageHeightSmall, + file: files[1], + zIndex: -(20 * math.pi / 180), + ), + ), + Positioned( + bottom: 50, + right: -10, + child: _CustomImage( + height: imageHeightSmall, + width: imageHeightSmall, + file: files[2], + zIndex: 20 * math.pi / 180, + ), + ), + Center( + child: _CustomImage( + height: imageHeightLarge, + width: imageHeightLarge, + file: files[0], + zIndex: 0.0, + imageShadow: const [ + BoxShadow( + offset: Offset(0, 1.02), + blurRadius: 2.04, + color: Color.fromRGBO(0, 0, 0, 0.23), + ), + BoxShadow( + offset: Offset(0, 3.06), + blurRadius: 3.06, + color: Color.fromRGBO(0, 0, 0, 0.2), + ), + BoxShadow( + offset: Offset(0, 6.12), + blurRadius: 4.08, + color: Color.fromRGBO(0, 0, 0, 0.12), + ), + BoxShadow( + offset: Offset(0, 11.22), + blurRadius: 5.1, + color: Color.fromRGBO(0, 0, 0, 0.04), + ), + BoxShadow( + offset: Offset(0, 18.36), + blurRadius: 5.1, + color: Color.fromRGBO(0, 0, 0, 0.0), + ), + ], + ), + ), + ], + ); + }, + ), + ], + ); + } else if (length > 3) { + placeholderWidget = _BackDrop( + backDropImage: files[0], + children: [ + LayoutBuilder( + builder: (context, constraint) { + final imageHeightSmall = constraint.maxHeight * 0.43; + final imageHeightLarge = constraint.maxHeight * 0.50; + final boxHeight = constraint.maxHeight * 0.15; + return Stack( + children: [ + Positioned( + top: 30, + left: 25, + child: _CustomImage( + height: imageHeightSmall, + width: imageHeightSmall, + file: files[1], + zIndex: 0.0, + ), + ), + Positioned( + top: 202, + left: 50, + child: _CustomImage( + height: imageHeightSmall, + width: imageHeightSmall, + file: files[2], + zIndex: 0.0, + ), + ), + Positioned( + top: 75, + right: 25, + child: _CustomImage( + height: imageHeightLarge, + width: imageHeightLarge, + file: files[0], + zIndex: 0.0, + imageShadow: const [ + BoxShadow( + offset: Offset(0, 1.02), + blurRadius: 2.04, + color: Color.fromRGBO(0, 0, 0, 0.23), + ), + BoxShadow( + offset: Offset(0, 3.06), + blurRadius: 3.06, + color: Color.fromRGBO(0, 0, 0, 0.2), + ), + BoxShadow( + offset: Offset(0, 6.12), + blurRadius: 4.08, + color: Color.fromRGBO(0, 0, 0, 0.12), + ), + BoxShadow( + offset: Offset(0, 11.22), + blurRadius: 5.1, + color: Color.fromRGBO(0, 0, 0, 0.04), + ), + BoxShadow( + offset: Offset(0, 18.36), + blurRadius: 5.1, + color: Color.fromRGBO(0, 0, 0, 0.0), + ), + ], + ), + ), + Positioned( + top: 290, + left: 270, + child: Stack( + children: [ + Center( + child: Container( + height: boxHeight + 3, + width: boxHeight + 3, + decoration: ShapeDecoration( + color: const Color.fromRGBO(129, 129, 129, 0.1), + shape: SmoothRectangleBorder( + borderRadius: SmoothBorderRadius( + cornerRadius: 15.0, + cornerSmoothing: 1.0, + ), + ), + ), + ), + ), + Center( + child: ClipSmoothRect( + radius: SmoothBorderRadius( + cornerRadius: 12, + cornerSmoothing: 1.0, + ), + child: Container( + height: boxHeight, + width: boxHeight, + color: const Color.fromRGBO(255, 255, 255, 1), + child: Center( + child: Text( + "+" "${length - 3}", + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 24, + color: Color.fromRGBO(0, 0, 0, 1), + fontFamily: 'Inter', + ), + ), + ), + ), + ), + ), + ], + ), + ), + ], + ); + }, + ), + ], ); } @@ -206,7 +303,6 @@ class LinkPlaceholder extends StatelessWidget { class _BackDrop extends StatelessWidget { const _BackDrop({ - super.key, required this.backDropImage, required this.children, }); @@ -216,21 +312,25 @@ class _BackDrop extends StatelessWidget { @override Widget build(BuildContext context) { - return Stack( - children: [ - ThumbnailWidget( - backDropImage, - shouldShowArchiveStatus: false, - shouldShowSyncStatus: false, - ), - BackdropFilter( - filter: ImageFilter.blur(sigmaX: 12, sigmaY: 12), - child: Container( - color: Colors.transparent, + return AspectRatio( + aspectRatio: 1, + child: Stack( + children: [ + ThumbnailWidget( + backDropImage, + shouldShowArchiveStatus: false, + shouldShowSyncStatus: false, + thumbnailSize: thumbnailLargeSize, ), - ), - ...children, - ], + BackdropFilter( + filter: ImageFilter.blur(sigmaX: 12, sigmaY: 12), + child: Container( + color: Colors.transparent, + ), + ), + ...children, + ], + ), ); } } @@ -239,12 +339,12 @@ class _CustomImage extends StatelessWidget { const _CustomImage({ required this.width, required this.height, - super.key, - required this.collages, + required this.file, required this.zIndex, + this.imageShadow, }); - - final EnteFile collages; + final List? imageShadow; + final EnteFile file; final double zIndex; final double height; final double width; @@ -255,35 +355,48 @@ class _CustomImage extends StatelessWidget { transform: Matrix4.rotationZ(zIndex), height: height, width: width, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20.0), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.5), - spreadRadius: 1, - blurRadius: 1, - offset: const Offset(1, 1), + child: Stack( + children: [ + Center( + child: Container( + height: height, + width: width, + decoration: ShapeDecoration( + color: const Color.fromRGBO(129, 129, 129, 0.1), + shadows: imageShadow, + shape: SmoothRectangleBorder( + borderRadius: SmoothBorderRadius( + cornerRadius: 21.0, + cornerSmoothing: 1.0, + ), + ), + ), + ), ), - BoxShadow( - color: Colors.black.withOpacity(0.5), - spreadRadius: 1, - blurRadius: 1, - offset: const Offset(-1, -1), + Center( + child: SizedBox( + height: height - 5, + width: width - 5, + child: ClipSmoothRect( + radius: SmoothBorderRadius( + cornerRadius: 16.0, + cornerSmoothing: 1, + ), + clipBehavior: Clip.antiAliasWithSaveLayer, + child: Container( + decoration: BoxDecoration(boxShadow: imageShadow), + child: ThumbnailWidget( + file, + shouldShowArchiveStatus: false, + shouldShowSyncStatus: false, + thumbnailSize: thumbnailLargeSize, + ), + ), + ), + ), ), ], ), - child: ClipSmoothRect( - radius: SmoothBorderRadius( - cornerRadius: 20.0, - cornerSmoothing: 1, - ), - clipBehavior: Clip.antiAliasWithSaveLayer, - child: ThumbnailWidget( - collages, - shouldShowArchiveStatus: false, - shouldShowSyncStatus: false, - ), - ), ); } } diff --git a/mobile/lib/utils/share_util.dart b/mobile/lib/utils/share_util.dart index aeb1e6bdab..57e2a68fa5 100644 --- a/mobile/lib/utils/share_util.dart +++ b/mobile/lib/utils/share_util.dart @@ -223,5 +223,5 @@ Future shareImageAndUrl( String imagePath, String url, ) async { - await Share.shareFiles([imagePath], text: url); + await Share.shareXFiles([XFile(imagePath)], text: url); } From 39d50d24f0f9dbcbcb1d433d96e7552a0e919fc6 Mon Sep 17 00:00:00 2001 From: Aman Raj Singh Mourya Date: Mon, 3 Jun 2024 13:15:09 +0530 Subject: [PATCH 07/22] [mob][photos] send link button changed --- .../selection_action_button_widget.dart | 48 ++++++++- .../file_selection_actions_widget.dart | 97 ++++++++++--------- 2 files changed, 92 insertions(+), 53 deletions(-) diff --git a/mobile/lib/ui/components/bottom_action_bar/selection_action_button_widget.dart b/mobile/lib/ui/components/bottom_action_bar/selection_action_button_widget.dart index 5ca6a25dcc..662eb3d936 100644 --- a/mobile/lib/ui/components/bottom_action_bar/selection_action_button_widget.dart +++ b/mobile/lib/ui/components/bottom_action_bar/selection_action_button_widget.dart @@ -1,3 +1,5 @@ +import 'dart:math' as math; + import "package:flutter/material.dart"; import "package:photos/theme/ente_theme.dart"; @@ -89,11 +91,47 @@ class __BodyState extends State<_Body> { mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ - Icon( - widget.icon, - size: 24, - color: getEnteColorScheme(context).textMuted, - ), + if (widget.icon == Icons.navigation_rounded) + Transform.rotate( + angle: math.pi / 2, + child: Icon( + widget.icon, + size: 24, + color: getEnteColorScheme(context).primary300, + shadows: const [ + BoxShadow( + color: Color.fromARGB(30, 0, 179, 60), + offset: Offset(0, 2.51), + blurRadius: 5.02, + spreadRadius: 0, + ), + BoxShadow( + color: Color.fromARGB(61, 0, 179, 60), + offset: Offset(0, 1.25), + blurRadius: 3.76, + spreadRadius: 0, + ), + BoxShadow( + color: Color.fromARGB(61, 0, 179, 60), + offset: Offset(0, 0.63), + blurRadius: 1.88, + spreadRadius: 0, + ), + BoxShadow( + color: Color.fromARGB(61, 255, 255, 255), + offset: Offset(0.63, 0.63), + blurRadius: 1.25, + spreadRadius: 0, + ), + ], + ), + ) + else + Icon( + widget.icon, + size: 24, + color: getEnteColorScheme(context).textMuted, + ), const SizedBox(height: 4), Text( widget.labelText, diff --git a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart index ac9cdfc38b..112d0dc50a 100644 --- a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart +++ b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart @@ -34,7 +34,7 @@ import 'package:photos/ui/components/action_sheet_widget.dart'; import "package:photos/ui/components/bottom_action_bar/selection_action_button_widget.dart"; import 'package:photos/ui/components/buttons/button_widget.dart'; import 'package:photos/ui/components/models/button_type.dart'; -import 'package:photos/ui/sharing/manage_links_widget.dart'; +// import 'package:photos/ui/sharing/manage_links_widget.dart'; import "package:photos/ui/sharing/show_images_prevew.dart"; import "package:photos/ui/tools/collage/collage_creator_page.dart"; import "package:photos/ui/viewer/location/update_location_data_widget.dart"; @@ -168,7 +168,7 @@ class _FileSelectionActionsWidgetState } else { items.add( SelectionActionButton( - icon: Icons.link_outlined, + icon: Icons.navigation_rounded, labelText: S.of(context).shareLink, onTap: anyUploadedFiles ? _onCreateLinkTapped : null, shouldShow: ownedFilesCount > 0, @@ -655,52 +655,53 @@ class _FileSelectionActionsWidgetState .createSharedCollectionLink(context, split.ownedByCurrentUser); final List ownedSelectedFiles = split.ownedByCurrentUser; - - final actionResult = await showActionSheet( - context: context, - buttons: [ - ButtonWidget( - labelText: S.of(context).shareLink, - buttonType: ButtonType.neutral, - buttonSize: ButtonSize.large, - shouldStickToDarkTheme: true, - buttonAction: ButtonAction.first, - isInAlert: true, - ), - ButtonWidget( - labelText: S.of(context).manageLink, - buttonType: ButtonType.secondary, - buttonSize: ButtonSize.large, - buttonAction: ButtonAction.second, - shouldStickToDarkTheme: true, - isInAlert: true, - ), - ButtonWidget( - labelText: S.of(context).done, - buttonType: ButtonType.secondary, - buttonSize: ButtonSize.large, - buttonAction: ButtonAction.third, - shouldStickToDarkTheme: true, - isInAlert: true, - ), - ], - title: S.of(context).publicLinkCreated, - body: S.of(context).youCanManageYourLinksInTheShareTab, - actionSheetType: ActionSheetType.defaultActionSheet, - ); - if (actionResult?.action != null) { - if (actionResult!.action == ButtonAction.first) { - placeholderPath = - await _selectedFilesPlaceholderPath(ownedSelectedFiles); - await _sendLink(); - } - if (actionResult.action == ButtonAction.second) { - await routeToPage( - context, - ManageSharedLinkWidget(collection: _cachedCollectionForSharedLink), - ); - } - } + placeholderPath = await _selectedFilesPlaceholderPath(ownedSelectedFiles); + await _sendLink(); + // final actionResult = await showActionSheet( + // context: context, + // buttons: [ + // ButtonWidget( + // labelText: S.of(context).shareLink, + // buttonType: ButtonType.neutral, + // buttonSize: ButtonSize.large, + // shouldStickToDarkTheme: true, + // buttonAction: ButtonAction.first, + // isInAlert: true, + // ), + // ButtonWidget( + // labelText: S.of(context).manageLink, + // buttonType: ButtonType.secondary, + // buttonSize: ButtonSize.large, + // buttonAction: ButtonAction.second, + // shouldStickToDarkTheme: true, + // isInAlert: true, + // ), + // ButtonWidget( + // labelText: S.of(context).done, + // buttonType: ButtonType.secondary, + // buttonSize: ButtonSize.large, + // buttonAction: ButtonAction.third, + // shouldStickToDarkTheme: true, + // isInAlert: true, + // ), + // ], + // title: S.of(context).publicLinkCreated, + // body: S.of(context).youCanManageYourLinksInTheShareTab, + // actionSheetType: ActionSheetType.defaultActionSheet, + // ); + // if (actionResult?.action != null) { + // if (actionResult!.action == ButtonAction.first) { + // placeholderPath = + // await _selectedFilesPlaceholderPath(ownedSelectedFiles); + // await _sendLink(); + // } + // if (actionResult.action == ButtonAction.second) { + // await routeToPage( + // context, + // ManageSharedLinkWidget(collection: _cachedCollectionForSharedLink), + // ); + // } + // } widget.selectedFiles.clearAll(); if (mounted) { setState(() => {}); From 0d99d3e037f976f1680df1e9f1403dd91065d49c Mon Sep 17 00:00:00 2001 From: Aman Raj Singh Mourya Date: Mon, 3 Jun 2024 13:20:05 +0530 Subject: [PATCH 08/22] [mob][photos] removed commented code --- .../file_selection_actions_widget.dart | 45 ------------------- 1 file changed, 45 deletions(-) diff --git a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart index 112d0dc50a..24eeb04647 100644 --- a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart +++ b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart @@ -657,51 +657,6 @@ class _FileSelectionActionsWidgetState final List ownedSelectedFiles = split.ownedByCurrentUser; placeholderPath = await _selectedFilesPlaceholderPath(ownedSelectedFiles); await _sendLink(); - // final actionResult = await showActionSheet( - // context: context, - // buttons: [ - // ButtonWidget( - // labelText: S.of(context).shareLink, - // buttonType: ButtonType.neutral, - // buttonSize: ButtonSize.large, - // shouldStickToDarkTheme: true, - // buttonAction: ButtonAction.first, - // isInAlert: true, - // ), - // ButtonWidget( - // labelText: S.of(context).manageLink, - // buttonType: ButtonType.secondary, - // buttonSize: ButtonSize.large, - // buttonAction: ButtonAction.second, - // shouldStickToDarkTheme: true, - // isInAlert: true, - // ), - // ButtonWidget( - // labelText: S.of(context).done, - // buttonType: ButtonType.secondary, - // buttonSize: ButtonSize.large, - // buttonAction: ButtonAction.third, - // shouldStickToDarkTheme: true, - // isInAlert: true, - // ), - // ], - // title: S.of(context).publicLinkCreated, - // body: S.of(context).youCanManageYourLinksInTheShareTab, - // actionSheetType: ActionSheetType.defaultActionSheet, - // ); - // if (actionResult?.action != null) { - // if (actionResult!.action == ButtonAction.first) { - // placeholderPath = - // await _selectedFilesPlaceholderPath(ownedSelectedFiles); - // await _sendLink(); - // } - // if (actionResult.action == ButtonAction.second) { - // await routeToPage( - // context, - // ManageSharedLinkWidget(collection: _cachedCollectionForSharedLink), - // ); - // } - // } widget.selectedFiles.clearAll(); if (mounted) { setState(() => {}); From 7ee9d8efddb0442f8775330c60e93bd9dbc3930c Mon Sep 17 00:00:00 2001 From: ashilkn Date: Mon, 3 Jun 2024 15:41:57 +0530 Subject: [PATCH 09/22] [mob][photos] Upgrade dependency to work with flutter 3.22.x --- mobile/pubspec.lock | 6 +++--- mobile/pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mobile/pubspec.lock b/mobile/pubspec.lock index 5c62cc6db2..edad689d58 100644 --- a/mobile/pubspec.lock +++ b/mobile/pubspec.lock @@ -1875,10 +1875,10 @@ packages: dependency: "direct main" description: name: screenshot - sha256: d448f43130f49bc7eead1b267b3ea0291cb2450f037bb0a0ecce7aa4c65e2aee + sha256: "63817697a7835e6ce82add4228e15d233b74d42975c143ad8cfe07009fab866b" url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "3.0.0" scrollable_positioned_list: dependency: "direct main" description: @@ -2607,4 +2607,4 @@ packages: version: "3.1.2" sdks: dart: ">=3.3.0 <4.0.0" - flutter: ">=3.20.0-1.2.pre" + flutter: ">=3.22.0" diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index 2c7ce64894..c5a1471771 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -141,7 +141,7 @@ dependencies: provider: ^6.0.0 quiver: ^3.0.1 receive_sharing_intent: ^1.7.0 - screenshot: ^2.4.0 + screenshot: ^3.0.0 scrollable_positioned_list: ^0.3.5 sentry: ^7.9.0 sentry_flutter: ^7.9.0 From 8367e4d4e108d0d5c634113ef69fa0be727986cf Mon Sep 17 00:00:00 2001 From: ashilkn Date: Mon, 3 Jun 2024 16:22:22 +0530 Subject: [PATCH 10/22] [mob][photos] Fix UI of element depicting extra photos in placeholder shared with link --- mobile/lib/ui/sharing/show_images_prevew.dart | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/mobile/lib/ui/sharing/show_images_prevew.dart b/mobile/lib/ui/sharing/show_images_prevew.dart index fc68f66843..1f1574c7df 100644 --- a/mobile/lib/ui/sharing/show_images_prevew.dart +++ b/mobile/lib/ui/sharing/show_images_prevew.dart @@ -5,6 +5,7 @@ import "package:figma_squircle/figma_squircle.dart"; import "package:flutter/material.dart"; import "package:photos/core/constants.dart"; import "package:photos/models/file/file.dart"; +import "package:photos/theme/ente_theme.dart"; import "package:photos/ui/viewer/file/thumbnail_widget.dart"; class LinkPlaceholder extends StatelessWidget { @@ -246,16 +247,17 @@ class LinkPlaceholder extends StatelessWidget { top: 290, left: 270, child: Stack( + alignment: Alignment.center, children: [ Center( child: Container( - height: boxHeight + 3, - width: boxHeight + 3, + height: boxHeight + 1, + width: boxHeight + 1, decoration: ShapeDecoration( color: const Color.fromRGBO(129, 129, 129, 0.1), shape: SmoothRectangleBorder( borderRadius: SmoothBorderRadius( - cornerRadius: 15.0, + cornerRadius: 12.5, cornerSmoothing: 1.0, ), ), @@ -272,14 +274,12 @@ class LinkPlaceholder extends StatelessWidget { height: boxHeight, width: boxHeight, color: const Color.fromRGBO(255, 255, 255, 1), + padding: const EdgeInsets.all(4), child: Center( - child: Text( - "+" "${length - 3}", - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 24, - color: Color.fromRGBO(0, 0, 0, 1), - fontFamily: 'Inter', + child: FittedBox( + child: Text( + "+" "${length - 3}", + style: getEnteTextTheme(context).h3Bold, ), ), ), From f7e24287bae559db5145d7c4c2032b5f250019b1 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Mon, 3 Jun 2024 16:30:50 +0530 Subject: [PATCH 11/22] [mob][photos] Tweak stroke of elements in placeholder to match figma design --- mobile/lib/ui/sharing/show_images_prevew.dart | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mobile/lib/ui/sharing/show_images_prevew.dart b/mobile/lib/ui/sharing/show_images_prevew.dart index 1f1574c7df..f6d6093d34 100644 --- a/mobile/lib/ui/sharing/show_images_prevew.dart +++ b/mobile/lib/ui/sharing/show_images_prevew.dart @@ -247,7 +247,6 @@ class LinkPlaceholder extends StatelessWidget { top: 290, left: 270, child: Stack( - alignment: Alignment.center, children: [ Center( child: Container( @@ -375,11 +374,11 @@ class _CustomImage extends StatelessWidget { ), Center( child: SizedBox( - height: height - 5, - width: width - 5, + height: height - 2, + width: width - 2, child: ClipSmoothRect( radius: SmoothBorderRadius( - cornerRadius: 16.0, + cornerRadius: 20.0, cornerSmoothing: 1, ), clipBehavior: Clip.antiAliasWithSaveLayer, From 7204d3471f5dc755e8fb8692d8acbc35a968ac54 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Mon, 3 Jun 2024 16:36:22 +0530 Subject: [PATCH 12/22] [mob][photos] Do not show fav icon on placeholder elements --- mobile/lib/ui/sharing/show_images_prevew.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mobile/lib/ui/sharing/show_images_prevew.dart b/mobile/lib/ui/sharing/show_images_prevew.dart index f6d6093d34..eb04e49a6c 100644 --- a/mobile/lib/ui/sharing/show_images_prevew.dart +++ b/mobile/lib/ui/sharing/show_images_prevew.dart @@ -317,8 +317,8 @@ class _BackDrop extends StatelessWidget { children: [ ThumbnailWidget( backDropImage, - shouldShowArchiveStatus: false, shouldShowSyncStatus: false, + shouldShowFavoriteIcon: false, thumbnailSize: thumbnailLargeSize, ), BackdropFilter( @@ -386,8 +386,8 @@ class _CustomImage extends StatelessWidget { decoration: BoxDecoration(boxShadow: imageShadow), child: ThumbnailWidget( file, - shouldShowArchiveStatus: false, shouldShowSyncStatus: false, + shouldShowFavoriteIcon: false, thumbnailSize: thumbnailLargeSize, ), ), From 5367e90ecf79fa56037f65228db4ba8c7977956c Mon Sep 17 00:00:00 2001 From: ashilkn Date: Mon, 3 Jun 2024 17:49:37 +0530 Subject: [PATCH 13/22] [mob][photos] Stop showing redundant toast --- .../lib/ui/viewer/actions/file_selection_actions_widget.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart index 24eeb04647..afc7711350 100644 --- a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart +++ b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart @@ -766,9 +766,8 @@ class _FileSelectionActionsWidgetState ); final String url = "${_cachedCollectionForSharedLink!.publicURLs?.first?.url}#$collectionKey"; + unawaited(Clipboard.setData(ClipboardData(text: url))); await shareImageAndUrl(placeholderPath!, url); - await Clipboard.setData(ClipboardData(text: url)); - showShortToast(context, S.of(context).linkCopiedToClipboard); if (placeholderPath != null) { final file = File(placeholderPath!); try { From ee602e63d2f33c36774e18eaaafd865c7568aed8 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Mon, 3 Jun 2024 17:58:45 +0530 Subject: [PATCH 14/22] [mob][photos] Show loading dialog after clicking on send link till the native share sheet comes up --- .../ui/actions/collection/collection_sharing_actions.dart | 8 -------- .../ui/viewer/actions/file_selection_actions_widget.dart | 7 +++++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/mobile/lib/ui/actions/collection/collection_sharing_actions.dart b/mobile/lib/ui/actions/collection/collection_sharing_actions.dart index 3328722dbe..c4f23df419 100644 --- a/mobile/lib/ui/actions/collection/collection_sharing_actions.dart +++ b/mobile/lib/ui/actions/collection/collection_sharing_actions.dart @@ -110,12 +110,6 @@ class CollectionActions { BuildContext context, List files, ) async { - final dialog = createProgressDialog( - context, - S.of(context).creatingLink, - isDismissible: true, - ); - await dialog.show(); try { // create album with emptyName, use collectionCreationTime on UI to // show name @@ -143,10 +137,8 @@ class CollectionActions { await collectionsService.addOrCopyToCollection(collection.id, files); logger.finest("creating public link for the newly created album"); await CollectionsService.instance.createShareUrl(collection); - await dialog.hide(); return collection; } catch (e, s) { - await dialog.hide(); await showGenericErrorDialog(context: context, error: e); logger.severe("Failing to create link for selected files", e, s); } diff --git a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart index afc7711350..e4510b0918 100644 --- a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart +++ b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart @@ -651,11 +651,18 @@ class _FileSelectionActionsWidgetState ); return; } + final dialog = createProgressDialog( + context, + S.of(context).creatingLink, + isDismissible: true, + ); + await dialog.show(); _cachedCollectionForSharedLink ??= await collectionActions .createSharedCollectionLink(context, split.ownedByCurrentUser); final List ownedSelectedFiles = split.ownedByCurrentUser; placeholderPath = await _selectedFilesPlaceholderPath(ownedSelectedFiles); + await dialog.hide(); await _sendLink(); widget.selectedFiles.clearAll(); if (mounted) { From 482239ce8d1e9b0eb9e170509e1870fea525c583 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Mon, 3 Jun 2024 18:04:58 +0530 Subject: [PATCH 15/22] [mob][photos] Change names and copy --- .../viewer/actions/file_selection_actions_widget.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart index e4510b0918..ed50b9b674 100644 --- a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart +++ b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart @@ -169,8 +169,8 @@ class _FileSelectionActionsWidgetState items.add( SelectionActionButton( icon: Icons.navigation_rounded, - labelText: S.of(context).shareLink, - onTap: anyUploadedFiles ? _onCreateLinkTapped : null, + labelText: S.of(context).sendLink, + onTap: anyUploadedFiles ? _onSendLinkTapped : null, shouldShow: ownedFilesCount > 0, ), ); @@ -623,7 +623,7 @@ class _FileSelectionActionsWidgetState return path; } - Future _selectedFilesPlaceholderPath( + Future _createPlaceholder( List ownedSelectedFiles, ) async { final Widget imageWidget = LinkPlaceholder( @@ -643,7 +643,7 @@ class _FileSelectionActionsWidgetState return onCreatedPlaceholderPath; } - Future _onCreateLinkTapped() async { + Future _onSendLinkTapped() async { if (split.ownedByCurrentUser.isEmpty) { showShortToast( context, @@ -661,7 +661,7 @@ class _FileSelectionActionsWidgetState .createSharedCollectionLink(context, split.ownedByCurrentUser); final List ownedSelectedFiles = split.ownedByCurrentUser; - placeholderPath = await _selectedFilesPlaceholderPath(ownedSelectedFiles); + placeholderPath = await _createPlaceholder(ownedSelectedFiles); await dialog.hide(); await _sendLink(); widget.selectedFiles.clearAll(); From 8b44165b775edaeadd21046cc1de4c6c01520b66 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Mon, 3 Jun 2024 18:35:58 +0530 Subject: [PATCH 16/22] [mob][photos] Fix shadows in send link icon --- .../selection_action_button_widget.dart | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/mobile/lib/ui/components/bottom_action_bar/selection_action_button_widget.dart b/mobile/lib/ui/components/bottom_action_bar/selection_action_button_widget.dart index 662eb3d936..12a744848e 100644 --- a/mobile/lib/ui/components/bottom_action_bar/selection_action_button_widget.dart +++ b/mobile/lib/ui/components/bottom_action_bar/selection_action_button_widget.dart @@ -100,29 +100,23 @@ class __BodyState extends State<_Body> { color: getEnteColorScheme(context).primary300, shadows: const [ BoxShadow( - color: Color.fromARGB(30, 0, 179, 60), + color: Color.fromARGB(12, 0, 179, 60), offset: Offset(0, 2.51), blurRadius: 5.02, spreadRadius: 0, ), BoxShadow( - color: Color.fromARGB(61, 0, 179, 60), + color: Color.fromARGB(24, 0, 179, 60), offset: Offset(0, 1.25), blurRadius: 3.76, spreadRadius: 0, ), BoxShadow( - color: Color.fromARGB(61, 0, 179, 60), + color: Color.fromARGB(24, 0, 179, 60), offset: Offset(0, 0.63), blurRadius: 1.88, spreadRadius: 0, ), - BoxShadow( - color: Color.fromARGB(61, 255, 255, 255), - offset: Offset(0.63, 0.63), - blurRadius: 1.25, - spreadRadius: 0, - ), ], ), ) From 3d0a810f262aeff72e0cb0d8ebba4f92ae361b4f Mon Sep 17 00:00:00 2001 From: ashilkn Date: Tue, 4 Jun 2024 12:11:04 +0530 Subject: [PATCH 17/22] [mob][photos] Upgrade share_plus --- mobile/lib/utils/share_util.dart | 36 +++++++++++++++----------------- mobile/pubspec.lock | 8 +++---- mobile/pubspec.yaml | 2 +- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/mobile/lib/utils/share_util.dart b/mobile/lib/utils/share_util.dart index 57e2a68fa5..91dc292fad 100644 --- a/mobile/lib/utils/share_util.dart +++ b/mobile/lib/utils/share_util.dart @@ -18,19 +18,8 @@ import 'package:share_plus/share_plus.dart'; import "package:uuid/uuid.dart"; final _logger = Logger("ShareUtil"); -// Set of possible image extensions -final _imageExtension = {"jpg", "jpeg", "png", "heic", "heif", "webp", ".gif"}; -final _videoExtension = { - "mp4", - "mov", - "avi", - "mkv", - "webm", - "wmv", - "flv", - "3gp", -}; -// share is used to share media/files from ente to other apps + +/// share is used to share media/files from ente to other apps Future share( BuildContext context, List files, { @@ -62,9 +51,13 @@ Future share( final paths = await Future.wait(pathFutures); await dialog.hide(); paths.removeWhere((element) => element == null); - final List nonNullPaths = paths.map((element) => element!).toList(); - return Share.shareFiles( - nonNullPaths, + final xFiles = []; + for (String? path in paths) { + if (path == null) continue; + xFiles.add(XFile(path)); + } + await Share.shareXFiles( + xFiles, // required for ipad https://github.com/flutter/flutter/issues/47220#issuecomment-608453383 sharePositionOrigin: shareButtonRect(context, shareButtonKey), ); @@ -99,8 +92,10 @@ Rect shareButtonRect(BuildContext context, GlobalKey? shareButtonKey) { ); } -Future shareText(String text) async { - return Share.share(text); +Future shareText(String text) async { + return Share.shareUri( + Uri.parse(text), + ); } Future> convertIncomingSharedMediaToFile( @@ -223,5 +218,8 @@ Future shareImageAndUrl( String imagePath, String url, ) async { - await Share.shareXFiles([XFile(imagePath)], text: url); + await Share.shareXFiles( + [XFile(imagePath)], + text: url, + ); } diff --git a/mobile/pubspec.lock b/mobile/pubspec.lock index edad689d58..e2408583c4 100644 --- a/mobile/pubspec.lock +++ b/mobile/pubspec.lock @@ -1907,18 +1907,18 @@ packages: dependency: "direct main" description: name: share_plus - sha256: "3ef39599b00059db0990ca2e30fca0a29d8b37aae924d60063f8e0184cf20900" + sha256: ef3489a969683c4f3d0239010cc8b7a2a46543a8d139e111c06c558875083544 url: "https://pub.dev" source: hosted - version: "7.2.2" + version: "9.0.0" share_plus_platform_interface: dependency: transitive description: name: share_plus_platform_interface - sha256: "251eb156a8b5fa9ce033747d73535bf53911071f8d3b6f4f0b578505ce0d4496" + sha256: "0f9e4418835d1b2c3ae78fdb918251959106cefdbc4dd43526e182f80e82f6d4" url: "https://pub.dev" source: hosted - version: "3.4.0" + version: "4.0.0" shared_preferences: dependency: "direct main" description: diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index c5a1471771..5dccd03b49 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -145,7 +145,7 @@ dependencies: scrollable_positioned_list: ^0.3.5 sentry: ^7.9.0 sentry_flutter: ^7.9.0 - share_plus: 7.2.2 + share_plus: ^9.0.0 shared_preferences: ^2.0.5 simple_cluster: ^0.3.0 sqflite: ^2.3.0 From 5723654ee0137ae8ccae1a1bb0a16ddf23d9e058 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Wed, 5 Jun 2024 11:19:10 +0530 Subject: [PATCH 18/22] [mob][photos] Fix send link not working on iPad --- .../lib/ui/viewer/actions/file_selection_actions_widget.dart | 5 ++++- mobile/lib/utils/share_util.dart | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart index ed50b9b674..d9555f8aad 100644 --- a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart +++ b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart @@ -84,6 +84,7 @@ class _FileSelectionActionsWidgetState // few files. This link is reset on any selection changed; Collection? _cachedCollectionForSharedLink; final GlobalKey shareButtonKey = GlobalKey(); + final GlobalKey sendLinkButtonKey = GlobalKey(); @override void initState() { @@ -172,6 +173,7 @@ class _FileSelectionActionsWidgetState labelText: S.of(context).sendLink, onTap: anyUploadedFiles ? _onSendLinkTapped : null, shouldShow: ownedFilesCount > 0, + key: sendLinkButtonKey, ), ); } @@ -414,6 +416,7 @@ class _FileSelectionActionsWidgetState SelectionActionButton( labelText: S.of(context).share, icon: Icons.adaptive.share_outlined, + key: shareButtonKey, onTap: () => shareSelected( context, shareButtonKey, @@ -774,7 +777,7 @@ class _FileSelectionActionsWidgetState final String url = "${_cachedCollectionForSharedLink!.publicURLs?.first?.url}#$collectionKey"; unawaited(Clipboard.setData(ClipboardData(text: url))); - await shareImageAndUrl(placeholderPath!, url); + await shareImageAndUrl(placeholderPath!, url, context, sendLinkButtonKey); if (placeholderPath != null) { final file = File(placeholderPath!); try { diff --git a/mobile/lib/utils/share_util.dart b/mobile/lib/utils/share_util.dart index 91dc292fad..1012747799 100644 --- a/mobile/lib/utils/share_util.dart +++ b/mobile/lib/utils/share_util.dart @@ -217,9 +217,12 @@ void shareSelected( Future shareImageAndUrl( String imagePath, String url, + BuildContext context, + GlobalKey key, ) async { await Share.shareXFiles( [XFile(imagePath)], text: url, + sharePositionOrigin: shareButtonRect(context, key), ); } From 79838bd49d55aed355e223f28ba3ade048b40fda Mon Sep 17 00:00:00 2001 From: ashilkn Date: Wed, 5 Jun 2024 11:46:51 +0530 Subject: [PATCH 19/22] [mob][photos] fix shareText not working (regression) --- mobile/lib/utils/share_util.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mobile/lib/utils/share_util.dart b/mobile/lib/utils/share_util.dart index 1012747799..ec15ee8146 100644 --- a/mobile/lib/utils/share_util.dart +++ b/mobile/lib/utils/share_util.dart @@ -93,9 +93,7 @@ Rect shareButtonRect(BuildContext context, GlobalKey? shareButtonKey) { } Future shareText(String text) async { - return Share.shareUri( - Uri.parse(text), - ); + return Share.share(text); } Future> convertIncomingSharedMediaToFile( From 419a4a78cf66f5596d6fd4e45b5921b19d6461e3 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Wed, 5 Jun 2024 12:54:53 +0530 Subject: [PATCH 20/22] [mob][photos] Fix share outside of ente not working at multiple places on iPad For the ios share sheet to be shown properly on iPad, the position of the button that triggered it needs to be known, which requires BuildContext and GlobalKey of the button, which is difficult to pass from some parts of code. So to make it work, we pass a default point on the screen so that the share sheet at least shows up --- .../file_selection_actions_widget.dart | 7 ++- mobile/lib/utils/share_util.dart | 47 +++++++++++++++---- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart index d9555f8aad..d162ec9ba4 100644 --- a/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart +++ b/mobile/lib/ui/viewer/actions/file_selection_actions_widget.dart @@ -777,7 +777,12 @@ class _FileSelectionActionsWidgetState final String url = "${_cachedCollectionForSharedLink!.publicURLs?.first?.url}#$collectionKey"; unawaited(Clipboard.setData(ClipboardData(text: url))); - await shareImageAndUrl(placeholderPath!, url, context, sendLinkButtonKey); + await shareImageAndUrl( + placeholderPath!, + url, + context: context, + key: sendLinkButtonKey, + ); if (placeholderPath != null) { final file = File(placeholderPath!); try { diff --git a/mobile/lib/utils/share_util.dart b/mobile/lib/utils/share_util.dart index ec15ee8146..b55730439a 100644 --- a/mobile/lib/utils/share_util.dart +++ b/mobile/lib/utils/share_util.dart @@ -72,8 +72,10 @@ Future share( } } +/// Returns the rect of button if context and key are not null +/// If key is null, returned rect will be at the center of the screen Rect shareButtonRect(BuildContext context, GlobalKey? shareButtonKey) { - Size size = MediaQuery.of(context).size; + Size size = MediaQuery.sizeOf(context); final RenderObject? renderObject = shareButtonKey?.currentContext?.findRenderObject(); RenderBox? renderBox; @@ -92,8 +94,21 @@ Rect shareButtonRect(BuildContext context, GlobalKey? shareButtonKey) { ); } -Future shareText(String text) async { - return Share.share(text); +Future shareText( + String text, { + BuildContext? context, + GlobalKey? key, +}) async { + try { + final sharePosOrigin = _sharePosOrigin(context, key); + return Share.share( + text, + sharePositionOrigin: sharePosOrigin, + ); + } catch (e, s) { + _logger.severe("failed to share text", e, s); + return ShareResult.unavailable; + } } Future> convertIncomingSharedMediaToFile( @@ -214,13 +229,29 @@ void shareSelected( Future shareImageAndUrl( String imagePath, - String url, - BuildContext context, - GlobalKey key, -) async { + String url, { + BuildContext? context, + GlobalKey? key, +}) async { + final sharePosOrigin = _sharePosOrigin(context, key); + await Share.shareXFiles( [XFile(imagePath)], text: url, - sharePositionOrigin: shareButtonRect(context, key), + sharePositionOrigin: sharePosOrigin, ); } + +/// required for ipad https://github.com/flutter/flutter/issues/47220#issuecomment-608453383 +/// This returns the position of the share button if context and key are not null +/// and if not, it returns a default position so that the share sheet on iPad has +/// some position to show up. +Rect _sharePosOrigin(BuildContext? context, GlobalKey? key) { + late final Rect rect; + if (context != null) { + rect = shareButtonRect(context, key); + } else { + rect = const Offset(20.0, 20.0) & const Size(10, 10); + } + return rect; +} From 9fef6ae6626c7ba023cd30d06495128957f3248f Mon Sep 17 00:00:00 2001 From: ashilkn Date: Wed, 5 Jun 2024 15:05:52 +0530 Subject: [PATCH 21/22] [mob][photos] Redesign QuickLinkAlbumItem --- .../ui/tabs/shared/quick_link_album_item.dart | 179 ++++++++++-------- .../lib/ui/tabs/shared_collections_tab.dart | 15 +- 2 files changed, 115 insertions(+), 79 deletions(-) diff --git a/mobile/lib/ui/tabs/shared/quick_link_album_item.dart b/mobile/lib/ui/tabs/shared/quick_link_album_item.dart index 70ed4d3dc7..9debde5e84 100644 --- a/mobile/lib/ui/tabs/shared/quick_link_album_item.dart +++ b/mobile/lib/ui/tabs/shared/quick_link_album_item.dart @@ -4,9 +4,9 @@ import 'package:photos/models/collection/collection.dart'; import 'package:photos/models/collection/collection_items.dart'; import 'package:photos/models/file/file.dart'; import "package:photos/services/collections_service.dart"; -import "package:photos/theme/colors.dart"; import "package:photos/theme/ente_theme.dart"; import "package:photos/ui/common/loading_widget.dart"; +import "package:photos/ui/components/buttons/icon_button_widget.dart"; import "package:photos/ui/viewer/file/no_thumbnail_widget.dart"; import "package:photos/ui/viewer/file/thumbnail_widget.dart"; import "package:photos/ui/viewer/gallery/collection_page.dart"; @@ -20,96 +20,123 @@ class QuickLinkAlbumItem extends StatelessWidget { @override Widget build(BuildContext context) { + final colorScheme = getEnteColorScheme(context); + final textTheme = getEnteTextTheme(context); return GestureDetector( behavior: HitTestBehavior.opaque, child: Container( - margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), + decoration: BoxDecoration( + border: Border.all(color: colorScheme.strokeFainter), + borderRadius: const BorderRadius.all( + Radius.circular(2), + ), + ), child: Row( - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(1), - child: SizedBox( - height: 60, - width: 60, - child: FutureBuilder( - future: CollectionsService.instance.getCover(c), - builder: (context, snapshot) { - if (snapshot.hasData) { - final String heroTag = heroTagPrefix + snapshot.data!.tag; - return Hero( - tag: heroTag, - child: ThumbnailWidget( - snapshot.data!, - key: ValueKey(heroTag), - ), - ); - } else { - return const NoThumbnailWidget(); - } - }, - ), - ), - ), - const Padding(padding: EdgeInsets.all(8)), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + flex: 6, + child: Row( children: [ - Text( - c.displayName, - style: getEnteTextTheme(context).body, - ), - Padding( - padding: const EdgeInsets.fromLTRB(0, 4, 0, 0), - child: FutureBuilder( - future: CollectionsService.instance.getFileCount(c), + SizedBox( + width: 60, + height: 60, + child: FutureBuilder( + future: CollectionsService.instance.getCover(c), builder: (context, snapshot) { - if (!snapshot.hasError) { - // final String textCount = NumberFormat().format(snapshot.data); - return Row( - children: [ - (!snapshot.hasData) - ? const Padding( - padding: EdgeInsets.symmetric( - horizontal: 16.0, - ), - child: EnteLoadingWidget(size: 10), - ) - : Padding( - padding: - const EdgeInsets.only(right: 8.0), - child: Text( - S.of(context).itemCount(snapshot.data!), - style: getEnteTextTheme(context) - .smallMuted, - ), - ), - const SizedBox(width: 6), - c.hasLink - ? (c.publicURLs!.first!.isExpired - ? const Icon( - Icons.link_outlined, - color: warning500, - ) - : Icon( - Icons.link_outlined, - color: getEnteColorScheme(context) - .strokeMuted, - )) - : const SizedBox.shrink(), - ], + if (snapshot.hasData) { + final String heroTag = + heroTagPrefix + snapshot.data!.tag; + return Hero( + tag: heroTag, + child: ClipRRect( + borderRadius: const BorderRadius.horizontal( + left: Radius.circular(2), + ), + child: ThumbnailWidget( + snapshot.data!, + key: ValueKey(heroTag), + ), + ), ); - } else if (snapshot.hasError) { - return Text(S.of(context).somethingWentWrong); } else { - return const EnteLoadingWidget(size: 10); + return const NoThumbnailWidget(); } }, ), ), + const SizedBox(width: 12), + Flexible( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + c.displayName, + overflow: TextOverflow.ellipsis, + ), + const SizedBox( + height: 2, + ), + FutureBuilder( + future: CollectionsService.instance.getFileCount(c), + builder: (context, snapshot) { + if (!snapshot.hasError) { + if (!snapshot.hasData) { + return Row( + children: [ + EnteLoadingWidget( + size: 10, + color: colorScheme.strokeMuted, + ), + ], + ); + } + final noOfMemories = snapshot.data; + + return Row( + children: [ + Text( + noOfMemories.toString() + " \u2022 ", + style: textTheme.smallMuted, + ), + c.hasLink + ? (c.publicURLs!.first!.isExpired + ? Icon( + Icons.link_outlined, + color: colorScheme.warning500, + size: 22, + ) + : Icon( + Icons.link_outlined, + color: colorScheme.strokeMuted, + size: 22, + )) + : const SizedBox.shrink(), + ], + ); + } else if (snapshot.hasError) { + return Text(S.of(context).somethingWentWrong); + } else { + return const EnteLoadingWidget(size: 10); + } + }, + ), + ], + ), + ), + ), ], ), ), + const Flexible( + flex: 1, + child: IconButtonWidget( + icon: Icons.chevron_right_outlined, + iconButtonType: IconButtonType.secondary, + ), + ), ], ), ), diff --git a/mobile/lib/ui/tabs/shared_collections_tab.dart b/mobile/lib/ui/tabs/shared_collections_tab.dart index 450d3062ca..161f0908cd 100644 --- a/mobile/lib/ui/tabs/shared_collections_tab.dart +++ b/mobile/lib/ui/tabs/shared_collections_tab.dart @@ -218,22 +218,31 @@ class _SharedCollectionsTabState extends State ), hasQuickLinks ? Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), + padding: const EdgeInsets.symmetric( + vertical: 8.0, + ), child: Column( children: [ SectionOptions( SectionTitle(title: S.of(context).quickLinks), ), const SizedBox(height: 2), - ListView.builder( + ListView.separated( shrinkWrap: true, - padding: const EdgeInsets.only(bottom: 12), + padding: const EdgeInsets.only( + bottom: 12, + left: 12, + right: 12, + ), physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) { return QuickLinkAlbumItem( c: collections.quickLinks[index], ); }, + separatorBuilder: (context, index) { + return const SizedBox(height: 8); + }, itemCount: collections.quickLinks.length, ), ], From 0e028fa9d18dd58f80b6d3a90747aae2ccf80aa6 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Wed, 5 Jun 2024 16:36:22 +0530 Subject: [PATCH 22/22] [photos][mob] Imporve UI/UX of quick link by only showing max 6 in shared tab + expand all in a different screen --- .../ui/components/title_bar_title_widget.dart | 7 +- .../ui/tabs/shared/all_quick_links_page.dart | 69 +++++++++++++++++++ .../lib/ui/tabs/shared_collections_tab.dart | 44 +++++++++--- 3 files changed, 110 insertions(+), 10 deletions(-) create mode 100644 mobile/lib/ui/tabs/shared/all_quick_links_page.dart diff --git a/mobile/lib/ui/components/title_bar_title_widget.dart b/mobile/lib/ui/components/title_bar_title_widget.dart index a685ea0456..e838849ef3 100644 --- a/mobile/lib/ui/components/title_bar_title_widget.dart +++ b/mobile/lib/ui/components/title_bar_title_widget.dart @@ -6,11 +6,13 @@ class TitleBarTitleWidget extends StatelessWidget { final bool isTitleH2; final IconData? icon; final VoidCallback? onTap; + final String? heroTag; const TitleBarTitleWidget({ this.title, this.isTitleH2 = false, this.icon, this.onTap, + this.heroTag, super.key, }); @@ -51,7 +53,10 @@ class TitleBarTitleWidget extends StatelessWidget { maxLines: 1, ); } - return GestureDetector(onTap: onTap, child: widget); + return GestureDetector( + onTap: onTap, + child: heroTag != null ? Hero(tag: heroTag!, child: widget) : widget, + ); } return const SizedBox.shrink(); diff --git a/mobile/lib/ui/tabs/shared/all_quick_links_page.dart b/mobile/lib/ui/tabs/shared/all_quick_links_page.dart new file mode 100644 index 0000000000..3a42ad0b61 --- /dev/null +++ b/mobile/lib/ui/tabs/shared/all_quick_links_page.dart @@ -0,0 +1,69 @@ +import "package:flutter/material.dart"; +import "package:photos/generated/l10n.dart"; +import "package:photos/models/collection/collection.dart"; +import "package:photos/ui/components/title_bar_title_widget.dart"; +import "package:photos/ui/tabs/shared/quick_link_album_item.dart"; + +class AllQuickLinksPage extends StatelessWidget { + final List quickLinks; + final String titleHeroTag; + const AllQuickLinksPage({ + required this.quickLinks, + required this.titleHeroTag, + super.key, + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + toolbarHeight: 48, + leadingWidth: 48, + leading: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: const Icon( + Icons.arrow_back_outlined, + ), + ), + ), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TitleBarTitleWidget( + title: S.of(context).quickLinks, + heroTag: titleHeroTag, + ), + Text(quickLinks.length.toString()), + ], + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 20, + horizontal: 16, + ), + child: ListView.separated( + itemBuilder: (context, index) { + return QuickLinkAlbumItem(c: quickLinks[index]); + }, + separatorBuilder: (context, index) { + return const SizedBox(height: 10); + }, + itemCount: quickLinks.length, + physics: const BouncingScrollPhysics(), + ), + ), + ), + ], + ), + ); + } +} diff --git a/mobile/lib/ui/tabs/shared_collections_tab.dart b/mobile/lib/ui/tabs/shared_collections_tab.dart index 161f0908cd..a0d78192ac 100644 --- a/mobile/lib/ui/tabs/shared_collections_tab.dart +++ b/mobile/lib/ui/tabs/shared_collections_tab.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import "dart:math"; import 'package:flutter/material.dart'; import 'package:logging/logging.dart'; @@ -17,6 +18,7 @@ import "package:photos/ui/components/buttons/icon_button_widget.dart"; import "package:photos/ui/components/divider_widget.dart"; import "package:photos/ui/components/models/button_type.dart"; import 'package:photos/ui/tabs/section_title.dart'; +import "package:photos/ui/tabs/shared/all_quick_links_page.dart"; import "package:photos/ui/tabs/shared/empty_state.dart"; import "package:photos/ui/tabs/shared/quick_link_album_item.dart"; import "package:photos/utils/debouncer.dart"; @@ -97,7 +99,9 @@ class _SharedCollectionsTabState extends State Widget _getSharedCollectionsGallery(SharedCollections collections) { const maxThumbnailWidth = 160.0; - final bool hasQuickLinks = collections.quickLinks.isNotEmpty; + const maxQuickLinks = 6; + final numberOfQuickLinks = collections.quickLinks.length; + const quickLinkTitleHeroTag = "quick_link_title"; final SectionTitle sharedWithYou = SectionTitle(title: S.of(context).sharedWithYou); final SectionTitle sharedByYou = @@ -216,7 +220,7 @@ class _SharedCollectionsTabState extends State ], ), ), - hasQuickLinks + numberOfQuickLinks > 0 ? Padding( padding: const EdgeInsets.symmetric( vertical: 8.0, @@ -224,7 +228,29 @@ class _SharedCollectionsTabState extends State child: Column( children: [ SectionOptions( - SectionTitle(title: S.of(context).quickLinks), + Hero( + tag: quickLinkTitleHeroTag, + child: SectionTitle( + title: S.of(context).quickLinks, + ), + ), + trailingWidget: numberOfQuickLinks > maxQuickLinks + ? IconButtonWidget( + icon: Icons.chevron_right, + iconButtonType: IconButtonType.secondary, + onTap: () { + unawaited( + routeToPage( + context, + AllQuickLinksPage( + titleHeroTag: quickLinkTitleHeroTag, + quickLinks: collections.quickLinks, + ), + ), + ); + }, + ) + : null, ), const SizedBox(height: 2), ListView.separated( @@ -241,9 +267,9 @@ class _SharedCollectionsTabState extends State ); }, separatorBuilder: (context, index) { - return const SizedBox(height: 8); + return const SizedBox(height: 4); }, - itemCount: collections.quickLinks.length, + itemCount: min(numberOfQuickLinks, maxQuickLinks), ), ], ), @@ -257,10 +283,10 @@ class _SharedCollectionsTabState extends State Padding( padding: const EdgeInsets.fromLTRB(24, 0, 24, 12), child: ButtonWidget( - buttonType: - !hasQuickLinks && collections.outgoing.isEmpty - ? ButtonType.trailingIconSecondary - : ButtonType.trailingIconPrimary, + buttonType: numberOfQuickLinks == 0 && + collections.outgoing.isEmpty + ? ButtonType.trailingIconSecondary + : ButtonType.trailingIconPrimary, labelText: S.of(context).inviteYourFriendsToEnte, icon: Icons.ios_share_outlined, onTap: () async {