diff --git a/mobile/lib/ui/settings/storage_error_widget.dart b/mobile/lib/ui/settings/storage_error_widget.dart deleted file mode 100644 index 8ccf6de0f5..0000000000 --- a/mobile/lib/ui/settings/storage_error_widget.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:flutter/material.dart'; -import "package:photos/generated/l10n.dart"; -import 'package:photos/theme/colors.dart'; -import 'package:photos/theme/ente_theme.dart'; - -class StorageErrorWidget extends StatelessWidget { - const StorageErrorWidget({super.key}); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Icon( - Icons.error_outline_outlined, - color: strokeBaseDark, - ), - const SizedBox(height: 8), - Text( - S.of(context).yourStorageDetailsCouldNotBeFetched, - style: getEnteTextTheme(context).small.copyWith( - color: textMutedDark, - ), - ), - ], - ), - ); - } -} diff --git a/mobile/lib/ui/viewer/file_details/objects_item_widget.dart b/mobile/lib/ui/viewer/file_details/objects_item_widget.dart deleted file mode 100644 index c02576c116..0000000000 --- a/mobile/lib/ui/viewer/file_details/objects_item_widget.dart +++ /dev/null @@ -1,66 +0,0 @@ -import "package:flutter/foundation.dart"; -import "package:flutter/material.dart"; -import "package:logging/logging.dart"; -import "package:photos/generated/l10n.dart"; -import 'package:photos/models/file/file.dart'; -import "package:photos/ui/components/buttons/chip_button_widget.dart"; -import "package:photos/ui/components/info_item_widget.dart"; - -class ObjectsItemWidget extends StatelessWidget { - final EnteFile file; - const ObjectsItemWidget(this.file, {super.key}); - - @override - Widget build(BuildContext context) { - return InfoItemWidget( - key: const ValueKey("Objects"), - leadingIcon: Icons.image_search_outlined, - subtitleSection: _objectTags(context, file), - hasChipButtons: true, - ); - } - - Future> _objectTags( - BuildContext context, - EnteFile file, - ) async { - try { - final chipButtons = []; - var objectTags = {}; - - // final thumbnail = await getThumbnail(file); - // if (thumbnail != null) { - // objectTags = await ObjectDetectionService.instance.predict(thumbnail); - // } - if (objectTags.isEmpty) { - return [ - ChipButtonWidget( - S.of(context).noResults, - noChips: true, - ), - ]; - } - // sort by values - objectTags = Map.fromEntries( - objectTags.entries.toList() - ..sort((e1, e2) => e2.value.compareTo(e1.value)), - ); - - for (MapEntry entry in objectTags.entries) { - chipButtons.add( - ChipButtonWidget( - entry.key + - (kDebugMode - ? "-" + (entry.value * 100).round().toString() - : ""), - ), - ); - } - - return chipButtons; - } catch (e, s) { - Logger("ObjctsItemWidget").info(e, s); - return []; - } - } -} diff --git a/mobile/lib/ui/viewer/people/new_person_item_widget.dart b/mobile/lib/ui/viewer/people/new_person_item_widget.dart deleted file mode 100644 index 88fa0fa3de..0000000000 --- a/mobile/lib/ui/viewer/people/new_person_item_widget.dart +++ /dev/null @@ -1,74 +0,0 @@ -import 'package:dotted_border/dotted_border.dart'; -import 'package:flutter/material.dart'; -import "package:photos/generated/l10n.dart"; -import 'package:photos/theme/ente_theme.dart'; - -///https://www.figma.com/file/SYtMyLBs5SAOkTbfMMzhqt/ente-Visual-Design?node-id=10854%3A57947&t=H5AvR79OYDnB9ekw-4 -class NewPersonItemWidget extends StatelessWidget { - const NewPersonItemWidget({ - super.key, - }); - - @override - Widget build(BuildContext context) { - final textTheme = getEnteTextTheme(context); - final colorScheme = getEnteColorScheme(context); - const sideOfThumbnail = 60.0; - return LayoutBuilder( - builder: (context, constraints) { - return Stack( - alignment: Alignment.center, - children: [ - Row( - children: [ - ClipRRect( - borderRadius: const BorderRadius.horizontal( - left: Radius.circular(4), - ), - child: SizedBox( - height: sideOfThumbnail, - width: sideOfThumbnail, - child: Icon( - Icons.add_outlined, - color: colorScheme.strokeMuted, - ), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 12), - child: Text( - S.of(context).addNewPerson, - style: - textTheme.body.copyWith(color: colorScheme.textMuted), - ), - ), - ], - ), - IgnorePointer( - child: DottedBorder( - dashPattern: const [4], - color: colorScheme.strokeFainter, - strokeWidth: 1, - padding: const EdgeInsets.all(0), - borderType: BorderType.RRect, - radius: const Radius.circular(4), - child: SizedBox( - //Have to decrease the height and width by 1 pt as the stroke - //dotted border gives is of strokeAlign.center, so 0.5 inside and - // outside. Here for the row, stroke should be inside so we - //decrease the size of this sizedBox by 1 (so it shrinks 0.5 from - //every side) so that the strokeAlign.center of this sizedBox - //looks like a strokeAlign.inside in the row. - height: sideOfThumbnail - 1, - //This width will work for this only if the row widget takes up the - //full size it's parent (stack). - width: constraints.maxWidth - 1, - ), - ), - ), - ], - ); - }, - ); - } -} diff --git a/mobile/lib/utils/face/face_util.dart b/mobile/lib/utils/face/face_util.dart deleted file mode 100644 index cb5b186b04..0000000000 --- a/mobile/lib/utils/face/face_util.dart +++ /dev/null @@ -1,175 +0,0 @@ -import "dart:math"; -import "dart:typed_data"; - -import "package:computer/computer.dart"; -import "package:flutter_image_compress/flutter_image_compress.dart"; -import "package:image/image.dart" as img; -import "package:logging/logging.dart"; -import "package:photos/models/ml/face/box.dart"; - -/// Bounding box of a face. -/// -/// [xMin] and [yMin] are the coordinates of the top left corner of the box, and -/// [width] and [height] are the width and height of the box. -/// -/// One unit is equal to one pixel in the original image. -class FaceBoxImage { - final int xMin; - final int yMin; - final int width; - final int height; - - FaceBoxImage({ - required this.xMin, - required this.yMin, - required this.width, - required this.height, - }); -} - -final _logger = Logger("FaceUtil"); -final _computer = Computer.shared(); -const _faceImageBufferFactor = 0.2; - -///Convert img.Image to ui.Image and use RawImage to display. -Future> generateImgFaceThumbnails( - String imagePath, - List faceBoxes, -) async { - final faceThumbnails = []; - - final image = await decodeToImgImage(imagePath); - - for (FaceBox faceBox in faceBoxes) { - final croppedImage = cropFaceBoxFromImage(image, faceBox); - faceThumbnails.add(croppedImage); - } - - return faceThumbnails; -} - -Future> generateJpgFaceThumbnails( - String imagePath, - List faceBoxes, -) async { - final image = await decodeToImgImage(imagePath); - final croppedImages = []; - for (FaceBox faceBox in faceBoxes) { - final croppedImage = cropFaceBoxFromImage(image, faceBox); - croppedImages.add(croppedImage); - } - - return await _computer - .compute(_encodeImagesToJpg, param: {"images": croppedImages}); -} - -Future decodeToImgImage(String imagePath) async { - img.Image? image = - await _computer.compute(_decodeImageFile, param: {"filePath": imagePath}); - - if (image == null) { - _logger.info( - "Failed to decode image. Compressing to jpg and decoding", - ); - final compressedJPGImage = - await FlutterImageCompress.compressWithFile(imagePath); - image = await _computer.compute( - _decodeJpg, - param: {"image": compressedJPGImage}, - ); - - if (image == null) { - throw Exception("Failed to decode image"); - } else { - return image; - } - } else { - return image; - } -} - -/// Returns an Image from 'package:image/image.dart' -img.Image cropFaceBoxFromImage(img.Image image, FaceBox faceBox) { - final squareFaceBox = _getSquareFaceBoxImage(image, faceBox); - final squareFaceBoxWithBuffer = - _addBufferAroundFaceBox(squareFaceBox, _faceImageBufferFactor); - return img.copyCrop( - image, - x: squareFaceBoxWithBuffer.xMin, - y: squareFaceBoxWithBuffer.yMin, - width: squareFaceBoxWithBuffer.width, - height: squareFaceBoxWithBuffer.height, - antialias: false, - ); -} - -/// Returns a square face box image from the original image with -/// side length equal to the maximum of the width and height of the face box in -/// the OG image. -FaceBoxImage _getSquareFaceBoxImage(img.Image image, FaceBox faceBox) { - final width = (image.width * faceBox.width).round(); - final height = (image.height * faceBox.height).round(); - final side = max(width, height); - final xImage = (image.width * faceBox.x).round(); - final yImage = (image.height * faceBox.y).round(); - - if (height >= width) { - final xImageAdj = (xImage - (height - width) / 2).round(); - return FaceBoxImage( - xMin: xImageAdj, - yMin: yImage, - width: side, - height: side, - ); - } else { - final yImageAdj = (yImage - (width - height) / 2).round(); - return FaceBoxImage( - xMin: xImage, - yMin: yImageAdj, - width: side, - height: side, - ); - } -} - -///To add some buffer around the face box so that the face isn't cropped -///too close to the face. -FaceBoxImage _addBufferAroundFaceBox( - FaceBoxImage faceBoxImage, - double bufferFactor, -) { - final heightBuffer = faceBoxImage.height * bufferFactor; - final widthBuffer = faceBoxImage.width * bufferFactor; - final xMinWithBuffer = faceBoxImage.xMin - widthBuffer; - final yMinWithBuffer = faceBoxImage.yMin - heightBuffer; - final widthWithBuffer = faceBoxImage.width + 2 * widthBuffer; - final heightWithBuffer = faceBoxImage.height + 2 * heightBuffer; - //Do not add buffer if the top left edge of the image is out of bounds - //after adding the buffer. - if (xMinWithBuffer < 0 || yMinWithBuffer < 0) { - return faceBoxImage; - } - //Another similar case that can be handled is when the bottom right edge - //of the image is out of bounds after adding the buffer. But the - //the visual difference is not as significant as when the top left edge - //is out of bounds, so we are not handling that case. - return FaceBoxImage( - xMin: xMinWithBuffer.round(), - yMin: yMinWithBuffer.round(), - width: widthWithBuffer.round(), - height: heightWithBuffer.round(), - ); -} - -List _encodeImagesToJpg(Map args) { - final images = args["images"] as List; - return images.map((img.Image image) => img.encodeJpg(image)).toList(); -} - -Future _decodeImageFile(Map args) async { - return await img.decodeImageFile(args["filePath"]); -} - -img.Image? _decodeJpg(Map args) { - return img.decodeJpg(args["image"])!; -} diff --git a/mobile/lib/utils/multipart_upload_util.dart b/mobile/lib/utils/multipart_upload_util.dart deleted file mode 100644 index 6b9ccafb97..0000000000 --- a/mobile/lib/utils/multipart_upload_util.dart +++ /dev/null @@ -1,157 +0,0 @@ -// ignore_for_file: implementation_imports - -import "dart:io"; - -import "package:dio/dio.dart"; -import "package:logging/logging.dart"; -import "package:photos/core/constants.dart"; -import "package:photos/core/network/network.dart"; -import 'package:photos/module/upload/model/xml.dart'; -import "package:photos/service_locator.dart"; - -final _enteDio = NetworkClient.instance.enteDio; -final _dio = NetworkClient.instance.getDio(); - -class PartETag extends XmlParsableObject { - final int partNumber; - final String eTag; - - PartETag(this.partNumber, this.eTag); - - @override - String get elementName => "Part"; - - @override - Map toMap() { - return { - "PartNumber": partNumber, - "ETag": eTag, - }; - } -} - -class MultipartUploadURLs { - final String objectKey; - final List partsURLs; - final String completeURL; - - MultipartUploadURLs({ - required this.objectKey, - required this.partsURLs, - required this.completeURL, - }); - - factory MultipartUploadURLs.fromMap(Map map) { - return MultipartUploadURLs( - objectKey: map["urls"]["objectKey"], - partsURLs: (map["urls"]["partURLs"] as List).cast(), - completeURL: map["urls"]["completeURL"], - ); - } -} - -Future calculatePartCount(int fileSize) async { - final partCount = (fileSize / multipartPartSize).ceil(); - return partCount; -} - -Future getMultipartUploadURLs(int count) async { - try { - assert( - flagService.internalUser, - "Multipart upload should not be enabled for external users.", - ); - final response = await _enteDio.get( - "/files/multipart-upload-urls", - queryParameters: { - "count": count, - }, - ); - - return MultipartUploadURLs.fromMap(response.data); - } on Exception catch (e) { - Logger("MultipartUploadURL").severe(e); - rethrow; - } -} - -Future putMultipartFile( - MultipartUploadURLs urls, - File encryptedFile, -) async { - // upload individual parts and get their etags - final etags = await uploadParts(urls.partsURLs, encryptedFile); - - // complete the multipart upload - await completeMultipartUpload(etags, urls.completeURL); - - return urls.objectKey; -} - -Future> uploadParts( - List partsURLs, - File encryptedFile, -) async { - final partsLength = partsURLs.length; - final etags = {}; - - for (int i = 0; i < partsLength; i++) { - final partURL = partsURLs[i]; - final isLastPart = i == partsLength - 1; - final fileSize = isLastPart - ? encryptedFile.lengthSync() % multipartPartSize - : multipartPartSize; - - final response = await _dio.put( - partURL, - data: encryptedFile.openRead( - i * multipartPartSize, - isLastPart ? null : multipartPartSize, - ), - options: Options( - headers: { - Headers.contentLengthHeader: fileSize, - }, - ), - ); - - final eTag = response.headers.value("etag"); - - if (eTag?.isEmpty ?? true) { - throw Exception('ETAG_MISSING'); - } - - etags[i] = eTag!; - } - - return etags; -} - -Future completeMultipartUpload( - Map partEtags, - String completeURL, -) async { - final body = convertJs2Xml({ - 'CompleteMultipartUpload': partEtags.entries - .map( - (e) => PartETag( - e.key + 1, - e.value, - ), - ) - .toList(), - }).replaceAll('"', '').replaceAll('"', ''); - - try { - await _dio.post( - completeURL, - data: body, - options: Options( - contentType: "text/xml", - ), - ); - } catch (e) { - Logger("MultipartUpload").severe(e); - rethrow; - } -}