From 552003600aa9184dcf70c038549b348a643e20a7 Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Fri, 18 Jul 2025 13:47:58 +0530 Subject: [PATCH 01/28] Add pro_image_editor package --- mobile/apps/photos/pubspec.lock | 90 ++++++++++++++++++++++----------- mobile/apps/photos/pubspec.yaml | 1 + 2 files changed, 62 insertions(+), 29 deletions(-) diff --git a/mobile/apps/photos/pubspec.lock b/mobile/apps/photos/pubspec.lock index 58284d5f09..5aab6b5201 100644 --- a/mobile/apps/photos/pubspec.lock +++ b/mobile/apps/photos/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 + sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab" url: "https://pub.dev" source: hosted - version: "72.0.0" + version: "76.0.0" _flutterfire_internals: dependency: transitive description: @@ -21,7 +21,7 @@ packages: dependency: transitive description: dart source: sdk - version: "0.3.2" + version: "0.3.3" adaptive_theme: dependency: "direct main" description: @@ -34,10 +34,10 @@ packages: dependency: transitive description: name: analyzer - sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 + sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" url: "https://pub.dev" source: hosted - version: "6.7.0" + version: "6.11.0" android_intent_plus: dependency: "direct main" description: @@ -317,10 +317,10 @@ packages: dependency: "direct main" description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" computer: dependency: "direct main" description: @@ -514,6 +514,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.17" + emoji_picker_flutter: + dependency: transitive + description: + name: emoji_picker_flutter + sha256: "08567e6f914d36c32091a96cf2f51d2558c47aa2bd47a590dc4f50e42e0965f6" + url: "https://pub.dev" + source: hosted + version: "3.1.0" encrypt: dependency: "direct main" description: @@ -1416,18 +1424,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "10.0.7" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.8" leak_tracker_testing: dependency: transitive description: @@ -1536,10 +1544,10 @@ packages: dependency: transitive description: name: macros - sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" + sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656" url: "https://pub.dev" source: hosted - version: "0.1.2-main.4" + version: "0.1.3-main.0" maps_launcher: dependency: "direct main" description: @@ -2064,6 +2072,14 @@ packages: url: "https://github.com/eddyuan/privacy_screen.git" source: git version: "0.0.6" + pro_image_editor: + dependency: "direct main" + description: + name: pro_image_editor + sha256: "1df9d15d514d958c740fc6aeacc41cc94b77cdcd8d72dac13c8f3a781c5680da" + url: "https://pub.dev" + source: hosted + version: "7.2.0" process: dependency: transitive description: @@ -2309,7 +2325,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_gen: dependency: transitive description: @@ -2434,10 +2450,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.0" step_progress_indicator: dependency: "direct main" description: @@ -2466,10 +2482,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" styled_text: dependency: "direct main" description: @@ -2530,26 +2546,26 @@ packages: dependency: "direct dev" description: name: test - sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e" + sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f" url: "https://pub.dev" source: hosted - version: "1.25.7" + version: "1.25.8" test_api: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.3" test_core: dependency: transitive description: name: test_core - sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696" + sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d" url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.6.5" thermal: dependency: "direct main" description: @@ -2742,6 +2758,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + vibration: + dependency: transitive + description: + name: vibration + sha256: "3b08a0579c2f9c18d5d78cb5c74f1005f731e02eeca6d72561a2e8059bf98ec3" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + vibration_platform_interface: + dependency: transitive + description: + name: vibration_platform_interface + sha256: "6ffeee63547562a6fef53c05a41d4fdcae2c0595b83ef59a4813b0612cd2bc36" + url: "https://pub.dev" + source: hosted + version: "0.0.3" video_editor: dependency: "direct main" description: @@ -2813,10 +2845,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b url: "https://pub.dev" source: hosted - version: "14.2.5" + version: "14.3.0" volume_controller: dependency: transitive description: @@ -2877,10 +2909,10 @@ packages: dependency: transitive description: name: webdriver - sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" + sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.4" webkit_inspection_protocol: dependency: transitive description: @@ -2979,4 +3011,4 @@ packages: version: "3.1.3" sdks: dart: ">=3.5.0 <4.0.0" - flutter: ">=3.24.0" + flutter: ">=3.27.0" diff --git a/mobile/apps/photos/pubspec.yaml b/mobile/apps/photos/pubspec.yaml index 19bf6b4b0c..41c26fe860 100644 --- a/mobile/apps/photos/pubspec.yaml +++ b/mobile/apps/photos/pubspec.yaml @@ -173,6 +173,7 @@ dependencies: git: url: https://github.com/eddyuan/privacy_screen.git ref: 855418e + pro_image_editor: ^7.2.0 receive_sharing_intent: # pub.dev is behind git: url: https://github.com/KasemJaffer/receive_sharing_intent.git From 9386e3796c8e65662e6cc6a4096398342fbfd174 Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Wed, 23 Jul 2025 23:42:45 +0530 Subject: [PATCH 02/28] Add svg assets of image editor --- .../assets/image-editor/image-editor-brightness.svg | 6 ++++++ .../photos/assets/image-editor/image-editor-contrast.svg | 3 +++ .../assets/image-editor/image-editor-crop-original.svg | 5 +++++ .../assets/image-editor/image-editor-crop-rotate.svg | 4 ++++ .../apps/photos/assets/image-editor/image-editor-crop.svg | 6 ++++++ .../photos/assets/image-editor/image-editor-exposure.svg | 3 +++ .../apps/photos/assets/image-editor/image-editor-fade.svg | 3 +++ .../photos/assets/image-editor/image-editor-filter.svg | 3 +++ .../apps/photos/assets/image-editor/image-editor-flip.svg | 4 ++++ .../apps/photos/assets/image-editor/image-editor-hue.svg | 8 ++++++++ .../photos/assets/image-editor/image-editor-luminance.svg | 3 +++ .../photos/assets/image-editor/image-editor-paint.svg | 3 +++ .../apps/photos/assets/image-editor/image-editor-redo.svg | 3 +++ .../assets/image-editor/image-editor-saturation.svg | 4 ++++ .../photos/assets/image-editor/image-editor-sharpness.svg | 3 +++ .../photos/assets/image-editor/image-editor-sticker.svg | 3 +++ .../assets/image-editor/image-editor-temperature.svg | 3 +++ .../image-editor/image-editor-text-align-center.svg | 7 +++++++ .../assets/image-editor/image-editor-text-align-left.svg | 5 +++++ .../assets/image-editor/image-editor-text-align-right.svg | 5 +++++ .../assets/image-editor/image-editor-text-background.svg | 3 +++ .../assets/image-editor/image-editor-text-color.svg | 5 +++++ .../photos/assets/image-editor/image-editor-text-font.svg | 4 ++++ .../apps/photos/assets/image-editor/image-editor-text.svg | 4 ++++ .../apps/photos/assets/image-editor/image-editor-tune.svg | 7 +++++++ .../apps/photos/assets/image-editor/image-editor-undo.svg | 4 ++++ 26 files changed, 111 insertions(+) create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-brightness.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-contrast.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-crop-original.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-crop-rotate.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-crop.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-exposure.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-fade.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-filter.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-flip.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-hue.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-luminance.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-paint.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-redo.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-saturation.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-sharpness.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-sticker.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-temperature.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-text-align-center.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-text-align-left.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-text-align-right.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-text-background.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-text-color.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-text-font.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-text.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-tune.svg create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-undo.svg diff --git a/mobile/apps/photos/assets/image-editor/image-editor-brightness.svg b/mobile/apps/photos/assets/image-editor/image-editor-brightness.svg new file mode 100644 index 0000000000..a468e3b80f --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-brightness.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-contrast.svg b/mobile/apps/photos/assets/image-editor/image-editor-contrast.svg new file mode 100644 index 0000000000..22e2dcaf3f --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-contrast.svg @@ -0,0 +1,3 @@ + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-crop-original.svg b/mobile/apps/photos/assets/image-editor/image-editor-crop-original.svg new file mode 100644 index 0000000000..e2cf9c3492 --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-crop-original.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-crop-rotate.svg b/mobile/apps/photos/assets/image-editor/image-editor-crop-rotate.svg new file mode 100644 index 0000000000..c7f604b8b3 --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-crop-rotate.svg @@ -0,0 +1,4 @@ + + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-crop.svg b/mobile/apps/photos/assets/image-editor/image-editor-crop.svg new file mode 100644 index 0000000000..ccd9d13ccd --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-crop.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-exposure.svg b/mobile/apps/photos/assets/image-editor/image-editor-exposure.svg new file mode 100644 index 0000000000..2d4c5c3f4e --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-exposure.svg @@ -0,0 +1,3 @@ + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-fade.svg b/mobile/apps/photos/assets/image-editor/image-editor-fade.svg new file mode 100644 index 0000000000..9aafd259cf --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-fade.svg @@ -0,0 +1,3 @@ + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-filter.svg b/mobile/apps/photos/assets/image-editor/image-editor-filter.svg new file mode 100644 index 0000000000..639e801937 --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-filter.svg @@ -0,0 +1,3 @@ + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-flip.svg b/mobile/apps/photos/assets/image-editor/image-editor-flip.svg new file mode 100644 index 0000000000..ba76ac2697 --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-flip.svg @@ -0,0 +1,4 @@ + + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-hue.svg b/mobile/apps/photos/assets/image-editor/image-editor-hue.svg new file mode 100644 index 0000000000..96b3df92f3 --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-hue.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-luminance.svg b/mobile/apps/photos/assets/image-editor/image-editor-luminance.svg new file mode 100644 index 0000000000..02ffd024bd --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-luminance.svg @@ -0,0 +1,3 @@ + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-paint.svg b/mobile/apps/photos/assets/image-editor/image-editor-paint.svg new file mode 100644 index 0000000000..1c914cd569 --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-paint.svg @@ -0,0 +1,3 @@ + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-redo.svg b/mobile/apps/photos/assets/image-editor/image-editor-redo.svg new file mode 100644 index 0000000000..8d82ac9ecf --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-redo.svg @@ -0,0 +1,3 @@ + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-saturation.svg b/mobile/apps/photos/assets/image-editor/image-editor-saturation.svg new file mode 100644 index 0000000000..9820828c78 --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-saturation.svg @@ -0,0 +1,4 @@ + + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-sharpness.svg b/mobile/apps/photos/assets/image-editor/image-editor-sharpness.svg new file mode 100644 index 0000000000..976aeec184 --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-sharpness.svg @@ -0,0 +1,3 @@ + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-sticker.svg b/mobile/apps/photos/assets/image-editor/image-editor-sticker.svg new file mode 100644 index 0000000000..cd4cd7e01e --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-sticker.svg @@ -0,0 +1,3 @@ + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-temperature.svg b/mobile/apps/photos/assets/image-editor/image-editor-temperature.svg new file mode 100644 index 0000000000..2616b4a463 --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-temperature.svg @@ -0,0 +1,3 @@ + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-text-align-center.svg b/mobile/apps/photos/assets/image-editor/image-editor-text-align-center.svg new file mode 100644 index 0000000000..755e31b8d0 --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-text-align-center.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-text-align-left.svg b/mobile/apps/photos/assets/image-editor/image-editor-text-align-left.svg new file mode 100644 index 0000000000..931fe8d5cd --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-text-align-left.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-text-align-right.svg b/mobile/apps/photos/assets/image-editor/image-editor-text-align-right.svg new file mode 100644 index 0000000000..5a03574c99 --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-text-align-right.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-text-background.svg b/mobile/apps/photos/assets/image-editor/image-editor-text-background.svg new file mode 100644 index 0000000000..6e9ae615dd --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-text-background.svg @@ -0,0 +1,3 @@ + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-text-color.svg b/mobile/apps/photos/assets/image-editor/image-editor-text-color.svg new file mode 100644 index 0000000000..9f176ab63c --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-text-color.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-text-font.svg b/mobile/apps/photos/assets/image-editor/image-editor-text-font.svg new file mode 100644 index 0000000000..2c248aab4f --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-text-font.svg @@ -0,0 +1,4 @@ + + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-text.svg b/mobile/apps/photos/assets/image-editor/image-editor-text.svg new file mode 100644 index 0000000000..f2b7eb9ff8 --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-text.svg @@ -0,0 +1,4 @@ + + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-tune.svg b/mobile/apps/photos/assets/image-editor/image-editor-tune.svg new file mode 100644 index 0000000000..9de251f75e --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-tune.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/mobile/apps/photos/assets/image-editor/image-editor-undo.svg b/mobile/apps/photos/assets/image-editor/image-editor-undo.svg new file mode 100644 index 0000000000..cb6e99a24d --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-undo.svg @@ -0,0 +1,4 @@ + + + + From 3d952a2ecc9b8dddae3d2b16ad0b613564f4d442 Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Wed, 23 Jul 2025 23:42:58 +0530 Subject: [PATCH 03/28] Add new color for image editor --- mobile/apps/photos/lib/ente_theme_data.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mobile/apps/photos/lib/ente_theme_data.dart b/mobile/apps/photos/lib/ente_theme_data.dart index c7ed51640b..6434e3ffe1 100644 --- a/mobile/apps/photos/lib/ente_theme_data.dart +++ b/mobile/apps/photos/lib/ente_theme_data.dart @@ -233,6 +233,8 @@ extension CustomColorScheme on ColorScheme { ? const Color(0xFF424242) : const Color(0xFFFFFFFF); + Color get imageEditorPrimaryColor => const Color.fromRGBO(8, 194, 37, 1); + Color get defaultBackgroundColor => brightness == Brightness.light ? backgroundBaseLight : backgroundBaseDark; From 4dd7305c46f609e3f68090801ca146cf71371e56 Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Wed, 23 Jul 2025 23:44:36 +0530 Subject: [PATCH 04/28] New app bar for editor --- .../image_editor/image_editor_app_bar.dart | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_app_bar.dart diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_app_bar.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_app_bar.dart new file mode 100644 index 0000000000..96eeb220a9 --- /dev/null +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_app_bar.dart @@ -0,0 +1,99 @@ +import 'package:flutter/material.dart'; +import "package:flutter_svg/svg.dart"; +import "package:photos/ente_theme_data.dart"; +import "package:photos/theme/ente_theme.dart"; +import "package:pro_image_editor/models/editor_configs/pro_image_editor_configs.dart"; + +class ImageEditorAppBar extends StatelessWidget implements PreferredSizeWidget { + const ImageEditorAppBar({ + super.key, + required this.configs, + this.undo, + this.redo, + required this.done, + required this.close, + this.enableUndo = false, + this.enableRedo = false, + this.isMainEditor = false, + }); + + final ProImageEditorConfigs configs; + final Function()? undo; + final Function()? redo; + final Function() done; + final Function() close; + final bool enableUndo; + final bool enableRedo; + final bool isMainEditor; + + @override + Size get preferredSize => const Size.fromHeight(kToolbarHeight); + + @override + Widget build(BuildContext context) { + final colorScheme = getEnteColorScheme(context); + return AppBar( + elevation: 0, + automaticallyImplyLeading: false, + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + TextButton( + onPressed: () { + enableUndo ? close() : Navigator.of(context).pop(); + }, + child: Text( + 'Cancel', + style: getEnteTextTheme(context).body, + ), + ), + if (undo != null && redo != null) + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + IconButton( + tooltip: 'Undo', + onPressed: () { + undo != null ? undo!() : null; + }, + icon: SvgPicture.asset( + "assets/image-editor/image-editor-undo.svg", + colorFilter: ColorFilter.mode( + enableUndo ? colorScheme.textBase : colorScheme.textMuted, + BlendMode.srcIn, + ), + ), + ), + const SizedBox(width: 16), + IconButton( + tooltip: 'Redo', + onPressed: () { + redo != null ? redo!() : null; + }, + icon: SvgPicture.asset( + 'assets/image-editor/image-editor-redo.svg', + colorFilter: ColorFilter.mode( + enableRedo ? colorScheme.textBase : colorScheme.textMuted, + BlendMode.srcIn, + ), + ), + ), + ], + ), + TextButton( + onPressed: () { + done(); + }, + child: Text( + isMainEditor ? 'Save Copy' : 'Done', + style: getEnteTextTheme(context).body.copyWith( + color: + Theme.of(context).colorScheme.imageEditorPrimaryColor, + ), + ), + ), + ], + ), + ); + } +} From 774292bdea819e0433daba8a0cb897225eb1b332 Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Wed, 23 Jul 2025 23:45:35 +0530 Subject: [PATCH 05/28] Custom widget for editor & constants --- .../image_editor/circular_icon_button.dart | 76 ++++++++ .../image_editor_color_picker.dart | 163 ++++++++++++++++++ .../image_editor/image_editor_constants.dart | 8 + 3 files changed, 247 insertions(+) create mode 100644 mobile/apps/photos/lib/ui/tools/editor/image_editor/circular_icon_button.dart create mode 100644 mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_color_picker.dart create mode 100644 mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_constants.dart diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/circular_icon_button.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/circular_icon_button.dart new file mode 100644 index 0000000000..7a025fe81f --- /dev/null +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/circular_icon_button.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart'; +import "package:flutter_svg/svg.dart"; +import "package:photos/ente_theme_data.dart"; +import "package:photos/theme/ente_theme.dart"; + +class CircularIconButton extends StatelessWidget { + final String label; + final VoidCallback onTap; + final String? svgPath; + final double size; + final bool isSelected; + + const CircularIconButton({ + super.key, + required this.label, + required this.onTap, + this.svgPath, + this.size = 60, + this.isSelected = false, + }); + + @override + Widget build(BuildContext context) { + final textTheme = getEnteTextTheme(context); + final colorScheme = getEnteColorScheme(context); + return SizedBox( + width: 90, + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + onTap: onTap, + child: Container( + height: size, + width: size, + decoration: BoxDecoration( + color: isSelected + ? Theme.of(context) + .colorScheme + .imageEditorPrimaryColor + .withOpacity(0.24) + : colorScheme.backgroundElevated2, + shape: BoxShape.circle, + border: Border.all( + color: isSelected + ? Theme.of(context).colorScheme.imageEditorPrimaryColor + : colorScheme.backgroundElevated2, + width: 2, + ), + ), + child: svgPath != null + ? SvgPicture.asset( + svgPath!, + width: 12, + height: 12, + fit: BoxFit.scaleDown, + colorFilter: ColorFilter.mode( + colorScheme.tabIcon, + BlendMode.srcIn, + ), + ) + : const SizedBox(), + ), + ), + const SizedBox(height: 6), + Text( + label, + style: textTheme.small, + textAlign: TextAlign.center, + ), + ], + ), + ); + } +} diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_color_picker.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_color_picker.dart new file mode 100644 index 0000000000..b87175d757 --- /dev/null +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_color_picker.dart @@ -0,0 +1,163 @@ +import "package:flutter/material.dart"; +import "package:photos/theme/ente_theme.dart"; + +class ImageEditorColorPicker extends StatefulWidget { + final double value; + final ValueChanged onChanged; + + const ImageEditorColorPicker({ + super.key, + required this.value, + required this.onChanged, + }); + + @override + ColorSliderState createState() => ColorSliderState(); +} + +class ColorSliderState extends State { + Color get _selectedColor { + final hue = widget.value * 360; + return HSVColor.fromAHSV(1.0, hue, 1.0, 1.0).toColor(); + } + + @override + Widget build(BuildContext context) { + final colorScheme = getEnteColorScheme(context); + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: SizedBox( + height: 40, + child: Stack( + alignment: Alignment.center, + children: [ + Container( + height: 36, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(25), + gradient: const LinearGradient( + colors: [ + Color(0xFFFF0000), + Color(0xFFFF8000), + Color(0xFFFFFF00), + Color(0xFF80FF00), + Color(0xFF00FF00), + Color(0xFF00FF80), + Color(0xFF00FFFF), + Color(0xFF0080FF), + Color(0xFF0000FF), + Color(0xFF8000FF), + Color(0xFFFF00FF), + Color(0xFFFF0080), + Color(0xFFFF0000), + ], + begin: Alignment.centerLeft, + end: Alignment.centerRight, + ), + border: Border.all( + color: colorScheme.backgroundElevated2, + width: 6, + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: SliderTheme( + data: SliderTheme.of(context).copyWith( + trackHeight: 36, + thumbShape: _CustomThumbShape(_selectedColor), + activeTrackColor: Colors.transparent, + inactiveTrackColor: Colors.transparent, + overlayShape: const RoundSliderOverlayShape(overlayRadius: 0), + trackShape: const _TransparentTrackShape(), + ), + child: Slider( + value: widget.value, + onChanged: widget.onChanged, + min: 0.0, + max: 1.0, + ), + ), + ), + ], + ), + ), + ); + } +} + +class _CustomThumbShape extends SliderComponentShape { + final Color color; + + const _CustomThumbShape(this.color); + + @override + Size getPreferredSize(bool isEnabled, bool isDiscrete) { + return const Size(28, 28); + } + + @override + void paint( + PaintingContext context, + Offset center, { + required Animation activationAnimation, + required Animation enableAnimation, + required bool isDiscrete, + required TextPainter labelPainter, + required RenderBox parentBox, + required SliderThemeData sliderTheme, + required TextDirection textDirection, + required double value, + required double textScaleFactor, + required Size sizeWithOverflow, + }) { + final Canvas canvas = context.canvas; + + final Paint thumbPaint = Paint() + ..color = color + ..style = PaintingStyle.fill; + + canvas.drawCircle(center, 11, thumbPaint); + + final Paint borderPaint = Paint() + ..color = Colors.white + ..style = PaintingStyle.stroke + ..strokeWidth = 3; + + canvas.drawCircle(center, 13, borderPaint); + } +} + +class _TransparentTrackShape extends SliderTrackShape { + const _TransparentTrackShape(); + + @override + Rect getPreferredRect({ + required RenderBox parentBox, + Offset offset = Offset.zero, + required SliderThemeData sliderTheme, + bool isEnabled = false, + bool isDiscrete = false, + }) { + final double trackHeight = sliderTheme.trackHeight!; + final double trackLeft = offset.dx; + final double trackTop = + offset.dy + (parentBox.size.height - trackHeight) / 2; + final double trackWidth = parentBox.size.width; + return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight); + } + + @override + void paint( + PaintingContext context, + Offset offset, { + required RenderBox parentBox, + required SliderThemeData sliderTheme, + required Animation enableAnimation, + required TextDirection textDirection, + required Offset thumbCenter, + Offset? secondaryOffset, + bool isDiscrete = false, + bool isEnabled = false, + }) {} +} diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_constants.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_constants.dart new file mode 100644 index 0000000000..c798b278b4 --- /dev/null +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_constants.dart @@ -0,0 +1,8 @@ +/// The duration used for fade-in animations. +const fadeInDuration = Duration(milliseconds: 220); + +/// The stagger delay between multiple fade-in animations +const fadeInDelay = Duration(milliseconds: 25); + +/// The height of the sub-bar. +const editorBottomBarHeight = 180.0; From 7a6fb1ba31ac9537dc5c0244373448d09ed59a67 Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Wed, 23 Jul 2025 23:47:03 +0530 Subject: [PATCH 06/28] Implemented new image editor --- .../image_editor_configs_mixin.dart | 20 + .../image_editor_crop_rotate.dart | 225 ++++++ .../image_editor/image_editor_filter_bar.dart | 101 +++ .../image_editor_main_bottom_bar.dart | 143 ++++ .../image_editor/image_editor_page_new.dart | 513 ++++++++++++++ .../image_editor/image_editor_paint_bar.dart | 88 +++ .../image_editor/image_editor_text_bar.dart | 366 ++++++++++ .../image_editor/image_editor_tune_bar.dart | 649 ++++++++++++++++++ 8 files changed, 2105 insertions(+) create mode 100644 mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_configs_mixin.dart create mode 100644 mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_crop_rotate.dart create mode 100644 mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_filter_bar.dart create mode 100644 mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_main_bottom_bar.dart create mode 100644 mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart create mode 100644 mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_paint_bar.dart create mode 100644 mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_text_bar.dart create mode 100644 mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_tune_bar.dart diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_configs_mixin.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_configs_mixin.dart new file mode 100644 index 0000000000..dd0a5c9c42 --- /dev/null +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_configs_mixin.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import "package:pro_image_editor/mixins/converted_configs.dart"; +import "package:pro_image_editor/models/editor_callbacks/pro_image_editor_callbacks.dart"; +import "package:pro_image_editor/models/editor_configs/pro_image_editor_configs.dart"; + +/// A mixin providing access to simple editor configurations. +mixin SimpleConfigsAccess on StatefulWidget { + ProImageEditorConfigs get configs; + ProImageEditorCallbacks get callbacks; +} + +mixin SimpleConfigsAccessState + on State, ImageEditorConvertedConfigs { + SimpleConfigsAccess get _widget => (widget as SimpleConfigsAccess); + + @override + ProImageEditorConfigs get configs => _widget.configs; + + ProImageEditorCallbacks get callbacks => _widget.callbacks; +} diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_crop_rotate.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_crop_rotate.dart new file mode 100644 index 0000000000..e7e5c97c66 --- /dev/null +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_crop_rotate.dart @@ -0,0 +1,225 @@ +import 'package:flutter/material.dart'; +import "package:flutter_svg/svg.dart"; +import "package:photos/theme/ente_theme.dart"; +import "package:photos/ui/tools/editor/image_editor/circular_icon_button.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_configs_mixin.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_constants.dart"; +import "package:pro_image_editor/mixins/converted_configs.dart"; +import "package:pro_image_editor/models/editor_callbacks/pro_image_editor_callbacks.dart"; +import "package:pro_image_editor/models/editor_configs/pro_image_editor_configs.dart"; +import "package:pro_image_editor/modules/crop_rotate_editor/crop_rotate_editor.dart"; +import "package:pro_image_editor/widgets/animated/fade_in_up.dart"; + +enum CropAspectRatioType { + original( + label: "Original", + ratio: null, + svg: "assets/image-editor/image-editor-crop-original.svg", + ), + free( + label: "Free", + ratio: null, + svg: "assets/video-editor/video-crop-free-action.svg", + ), + square( + label: "1:1", + ratio: 1.0, + svg: "assets/video-editor/video-crop-ratio_1_1-action.svg", + ), + widescreen( + label: "16:9", + ratio: 16.0 / 9.0, + svg: "assets/video-editor/video-crop-ratio_16_9-action.svg", + ), + portrait( + label: "9:16", + ratio: 9.0 / 16.0, + svg: "assets/video-editor/video-crop-ratio_9_16-action.svg", + ), + photo( + label: "4:3", + ratio: 4.0 / 3.0, + svg: "assets/video-editor/video-crop-ratio_4_3-action.svg", + ), + photo_3_4( + label: "3:4", + ratio: 3.0 / 4.0, + svg: "assets/video-editor/video-crop-ratio_3_4-action.svg", + ); + + const CropAspectRatioType({ + required this.label, + required this.ratio, + required this.svg, + }); + + final String label; + final String svg; + final double? ratio; +} + +class ImageEditorCropRotateBar extends StatefulWidget with SimpleConfigsAccess { + const ImageEditorCropRotateBar({ + super.key, + required this.configs, + required this.callbacks, + required this.editor, + }); + final CropRotateEditorState editor; + + @override + final ProImageEditorConfigs configs; + + @override + final ProImageEditorCallbacks callbacks; + + @override + State createState() => + _ImageEditorCropRotateBarState(); +} + +class _ImageEditorCropRotateBarState extends State + with ImageEditorConvertedConfigs, SimpleConfigsAccessState { + CropAspectRatioType selectedAspectRatio = CropAspectRatioType.original; + + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (context, constraints) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + _buildFunctions(constraints), + ], + ); + }, + ); + } + + Widget _buildFunctions(BoxConstraints constraints) { + return BottomAppBar( + color: getEnteColorScheme(context).backgroundBase, + height: editorBottomBarHeight, + child: Align( + alignment: Alignment.bottomCenter, + child: FadeInUp( + duration: fadeInDuration, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + CircularIconButton( + svgPath: "assets/image-editor/image-editor-crop-rotate.svg", + label: "Rotate", + onTap: () { + widget.editor.rotate(); + }, + ), + const SizedBox(width: 12), + CircularIconButton( + svgPath: "assets/image-editor/image-editor-flip.svg", + label: "Flip", + onTap: () { + widget.editor.flip(); + }, + ), + ], + ), + const SizedBox(height: 20), + SizedBox( + height: 48, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: CropAspectRatioType.values.length, + itemBuilder: (context, index) { + final aspectRatio = CropAspectRatioType.values[index]; + final isSelected = selectedAspectRatio == aspectRatio; + return Padding( + padding: const EdgeInsets.only(right: 12.0), + child: CropAspectChip( + label: aspectRatio.label, + svg: aspectRatio.svg, + isSelected: isSelected, + onTap: () { + setState(() { + selectedAspectRatio = aspectRatio; + }); + widget.editor + .updateAspectRatio(aspectRatio.ratio ?? -1); + }, + ), + ); + }, + ), + ), + ], + ), + ), + ), + ); + } +} + +class CropAspectChip extends StatelessWidget { + final String? label; + final IconData? icon; + final String? svg; + final bool isSelected; + final VoidCallback? onTap; + + const CropAspectChip({ + super.key, + this.label, + this.icon, + this.svg, + required this.isSelected, + this.onTap, + }); + + @override + Widget build(BuildContext context) { + final colorScheme = getEnteColorScheme(context); + return GestureDetector( + onTap: onTap, + child: Container( + decoration: BoxDecoration( + color: isSelected + ? colorScheme.fillBasePressed + : colorScheme.backgroundElevated2, + borderRadius: BorderRadius.circular(25), + ), + padding: const EdgeInsets.symmetric( + horizontal: 14, + vertical: 10, + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (svg != null) ...[ + SvgPicture.asset( + svg!, + height: 40, + colorFilter: ColorFilter.mode( + isSelected ? colorScheme.backdropBase : colorScheme.tabIcon, + BlendMode.srcIn, + ), + ), + ], + const SizedBox(width: 4), + if (label != null) + Text( + label!, + style: TextStyle( + color: isSelected + ? colorScheme.backdropBase + : colorScheme.tabIcon, + ), + ), + ], + ), + ), + ); + } +} diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_filter_bar.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_filter_bar.dart new file mode 100644 index 0000000000..1fc6927c6e --- /dev/null +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_filter_bar.dart @@ -0,0 +1,101 @@ +import 'package:figma_squircle/figma_squircle.dart'; +import 'package:flutter/material.dart'; +import "package:photos/ente_theme_data.dart"; +import "package:photos/theme/ente_theme.dart"; +import 'package:pro_image_editor/pro_image_editor.dart'; + +class ImageEditorFilterBar extends StatefulWidget { + const ImageEditorFilterBar({ + required this.filterModel, + required this.isSelected, + required this.onSelectFilter, + required this.editorImage, + this.filterKey, + super.key, + }); + + final FilterModel filterModel; + final bool isSelected; + final VoidCallback onSelectFilter; + final Widget editorImage; + final Key? filterKey; + + @override + State createState() => _ImageEditorFilterBarState(); +} + +class _ImageEditorFilterBarState extends State { + @override + Widget build(BuildContext context) { + return buildFilteredOptions( + widget.editorImage, + widget.isSelected, + widget.filterModel.name, + widget.onSelectFilter, + widget.filterKey ?? ValueKey(widget.filterModel.name), + ); + } + + Widget buildFilteredOptions( + Widget editorImage, + bool isSelected, + String filterName, + VoidCallback onSelectFilter, + Key filterKey, + ) { + return GestureDetector( + onTap: () => onSelectFilter(), + child: SizedBox( + height: 90, + width: 80, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Container( + height: 60, + width: 60, + decoration: ShapeDecoration( + shape: SmoothRectangleBorder( + borderRadius: SmoothBorderRadius( + cornerRadius: 12, + cornerSmoothing: 0.6, + ), + side: BorderSide( + color: isSelected + ? Theme.of(context).colorScheme.imageEditorPrimaryColor + : Colors.transparent, + width: 1.5, + ), + ), + ), + child: Padding( + padding: isSelected ? const EdgeInsets.all(2) : EdgeInsets.zero, + child: ClipSmoothRect( + radius: SmoothBorderRadius( + cornerRadius: 9.69, + cornerSmoothing: 0.4, + ), + child: SizedBox( + height: isSelected ? 56 : 60, + width: isSelected ? 56 : 60, + child: editorImage, + ), + ), + ), + ), + const SizedBox(height: 8), + Text( + filterName, + style: isSelected + ? getEnteTextTheme(context).smallBold + : getEnteTextTheme(context).smallMuted, + textAlign: TextAlign.center, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ), + ); + } +} diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_main_bottom_bar.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_main_bottom_bar.dart new file mode 100644 index 0000000000..1d5a9ff789 --- /dev/null +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_main_bottom_bar.dart @@ -0,0 +1,143 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import "package:photos/ui/tools/editor/image_editor/circular_icon_button.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_configs_mixin.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_constants.dart"; +import "package:pro_image_editor/mixins/converted_configs.dart"; +import 'package:pro_image_editor/pro_image_editor.dart'; + +class ImageEditorMainBottomBar extends StatefulWidget with SimpleConfigsAccess { + const ImageEditorMainBottomBar({ + super.key, + required this.configs, + required this.callbacks, + required this.editor, + }); + + final ProImageEditorState editor; + + @override + final ProImageEditorConfigs configs; + @override + final ProImageEditorCallbacks callbacks; + + @override + State createState() => + ImageEditorMainBottomBarState(); +} + +class ImageEditorMainBottomBarState extends State + with ImageEditorConvertedConfigs, SimpleConfigsAccessState { + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (context, constraints) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + _buildFunctions(constraints), + ], + ); + }, + ); + } + + Widget _buildFunctions(BoxConstraints constraints) { + return BottomAppBar( + height: editorBottomBarHeight, + padding: EdgeInsets.zero, + clipBehavior: Clip.none, + child: AnimatedSwitcher( + layoutBuilder: (currentChild, previousChildren) => Stack( + clipBehavior: Clip.none, + alignment: Alignment.bottomCenter, + children: [ + ...previousChildren, + if (currentChild != null) currentChild, + ], + ), + duration: const Duration(milliseconds: 400), + reverseDuration: const Duration(milliseconds: 0), + transitionBuilder: (child, animation) { + return FadeTransition( + opacity: animation, + child: SizeTransition( + sizeFactor: animation, + axis: Axis.vertical, + axisAlignment: -1, + child: child, + ), + ); + }, + switchInCurve: Curves.ease, + child: widget.editor.isSubEditorOpen && + !widget.editor.isSubEditorClosing + ? const SizedBox.shrink() + : Align( + alignment: Alignment.center, + child: SingleChildScrollView( + clipBehavior: Clip.none, + scrollDirection: Axis.horizontal, + child: ConstrainedBox( + constraints: BoxConstraints( + minWidth: min(constraints.maxWidth, 600), + maxWidth: 600, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + CircularIconButton( + svgPath: "assets/image-editor/image-editor-crop.svg", + label: "Crop", + onTap: () { + widget.editor.openCropRotateEditor(); + }, + ), + CircularIconButton( + svgPath: + "assets/image-editor/image-editor-filter.svg", + label: "Filter", + onTap: () { + widget.editor.openFilterEditor(); + }, + ), + CircularIconButton( + svgPath: "assets/image-editor/image-editor-text.svg", + label: "Text", + onTap: () { + widget.editor.openTextEditor(); + }, + ), + CircularIconButton( + svgPath: "assets/image-editor/image-editor-tune.svg", + label: "Adjust", + onTap: () { + widget.editor.openTuneEditor(); + }, + ), + CircularIconButton( + svgPath: "assets/image-editor/image-editor-paint.svg", + label: "Draw", + onTap: () { + widget.editor.openPaintEditor(); + }, + ), + CircularIconButton( + svgPath: + "assets/image-editor/image-editor-sticker.svg", + label: "Sticker", + onTap: () { + widget.editor.openEmojiEditor(); + }, + ), + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart new file mode 100644 index 0000000000..da15c97924 --- /dev/null +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart @@ -0,0 +1,513 @@ +import "dart:async"; +import "dart:io"; +import "dart:math"; +import "dart:typed_data"; +import 'dart:ui' as ui show Image; + +import 'package:flutter/material.dart'; +import "package:flutter_image_compress/flutter_image_compress.dart"; +import "package:google_fonts/google_fonts.dart"; +import "package:logging/logging.dart"; +import 'package:path/path.dart' as path; +import "package:photo_manager/photo_manager.dart"; +import "package:photos/core/event_bus.dart"; +import "package:photos/db/files_db.dart"; +import "package:photos/ente_theme_data.dart"; +import "package:photos/events/local_photos_updated_event.dart"; +import "package:photos/generated/l10n.dart"; +import 'package:photos/models/file/file.dart' as ente; +import "package:photos/models/location/location.dart"; +import "package:photos/services/sync/sync_service.dart"; +import "package:photos/theme/ente_theme.dart"; +import "package:photos/ui/components/action_sheet_widget.dart"; +import "package:photos/ui/components/buttons/button_widget.dart"; +import "package:photos/ui/components/models/button_type.dart"; +import "package:photos/ui/notification/toast.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_app_bar.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_constants.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_crop_rotate.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_filter_bar.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_main_bottom_bar.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_paint_bar.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_text_bar.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_tune_bar.dart"; +import "package:photos/ui/viewer/file/detail_page.dart"; +import "package:photos/utils/dialog_util.dart"; +import "package:photos/utils/navigation_util.dart"; +import "package:pro_image_editor/models/editor_configs/utils/editor_safe_area.dart"; +import 'package:pro_image_editor/pro_image_editor.dart'; + +class NewImageEditor extends StatefulWidget { + final ente.EnteFile originalFile; + final File file; + final DetailPageConfiguration detailPageConfig; + + const NewImageEditor({ + super.key, + required this.file, + required this.originalFile, + required this.detailPageConfig, + }); + + @override + State createState() => _NewImageEditorState(); +} + +class _NewImageEditorState extends State { + final _mainEditorBarKey = GlobalKey(); + final editorKey = GlobalKey(); + final _logger = Logger("ImageEditor"); + + Future saveImage(Uint8List? bytes) async { + if (bytes == null) return; + + final dialog = createProgressDialog(context, S.of(context).saving); + await dialog.show(); + + debugPrint("Image saved with size: ${bytes.length} bytes"); + final DateTime start = DateTime.now(); + + final ui.Image decodedResult = await decodeImageFromList(bytes); + final result = await FlutterImageCompress.compressWithList( + bytes, + minWidth: decodedResult.width, + minHeight: decodedResult.height, + ); + _logger.info('Size after compression = ${result.length}'); + final Duration diff = DateTime.now().difference(start); + _logger.info('image_editor time : $diff'); + + try { + final fileName = + path.basenameWithoutExtension(widget.originalFile.title!) + + "_edited_" + + DateTime.now().microsecondsSinceEpoch.toString() + + ".JPEG"; + //Disabling notifications for assets changing to insert the file into + //files db before triggering a sync. + await PhotoManager.stopChangeNotify(); + final AssetEntity newAsset = + await (PhotoManager.editor.saveImage(result, filename: fileName)); + final newFile = await ente.EnteFile.fromAsset( + widget.originalFile.deviceFolder ?? '', + newAsset, + ); + + newFile.creationTime = widget.originalFile.creationTime; + newFile.collectionID = widget.originalFile.collectionID; + newFile.location = widget.originalFile.location; + if (!newFile.hasLocation && widget.originalFile.localID != null) { + final assetEntity = await widget.originalFile.getAsset; + if (assetEntity != null) { + final latLong = await assetEntity.latlngAsync(); + newFile.location = Location( + latitude: latLong.latitude, + longitude: latLong.longitude, + ); + } + } + newFile.generatedID = await FilesDB.instance.insertAndGetId(newFile); + Bus.instance.fire(LocalPhotosUpdatedEvent([newFile], source: "editSave")); + unawaited(SyncService.instance.sync()); + showShortToast(context, S.of(context).editsSaved); + _logger.info("Original file " + widget.originalFile.toString()); + _logger.info("Saved edits to file " + newFile.toString()); + final files = widget.detailPageConfig.files; + + // the index could be -1 if the files fetched doesn't contain the newly + // edited files + int selectionIndex = + files.indexWhere((file) => file.generatedID == newFile.generatedID); + if (selectionIndex == -1) { + files.add(newFile); + selectionIndex = files.length - 1; + } + await dialog.hide(); + replacePage( + context, + DetailPage( + widget.detailPageConfig.copyWith( + files: files, + selectedIndex: min(selectionIndex, files.length - 1), + ), + ), + ); + } catch (e, s) { + await dialog.hide(); + showToast(context, S.of(context).oopsCouldNotSaveEdits); + _logger.severe(e, s); + } finally { + await PhotoManager.startChangeNotify(); + } + } + + Future _showExitConfirmationDialog(BuildContext context) async { + final actionResult = await showActionSheet( + context: context, + buttons: [ + ButtonWidget( + labelText: S.of(context).yesDiscardChanges, + buttonType: ButtonType.critical, + buttonSize: ButtonSize.large, + shouldStickToDarkTheme: true, + buttonAction: ButtonAction.first, + isInAlert: true, + ), + ButtonWidget( + labelText: S.of(context).no, + buttonType: ButtonType.secondary, + buttonSize: ButtonSize.large, + buttonAction: ButtonAction.second, + shouldStickToDarkTheme: true, + isInAlert: true, + ), + ], + body: S.of(context).doYouWantToDiscardTheEditsYouHaveMade, + actionSheetType: ActionSheetType.defaultActionSheet, + ); + if (actionResult?.action != null && + actionResult!.action == ButtonAction.first) { + replacePage(context, DetailPage(widget.detailPageConfig)); + } + } + + @override + Widget build(BuildContext context) { + final isLightMode = Theme.of(context).brightness == Brightness.light; + final colorScheme = getEnteColorScheme(context); + final textTheme = getEnteTextTheme(context); + return Scaffold( + backgroundColor: colorScheme.backgroundBase, + body: ProImageEditor.file( + key: editorKey, + widget.file, + callbacks: ProImageEditorCallbacks( + mainEditorCallbacks: MainEditorCallbacks( + onStartCloseSubEditor: (value) { + _mainEditorBarKey.currentState?.setState(() {}); + }, + ), + ), + configs: ProImageEditorConfigs( + layerInteraction: const LayerInteractionConfigs( + hideToolbarOnInteraction: false, + ), + theme: ThemeData( + scaffoldBackgroundColor: colorScheme.backgroundBase, + appBarTheme: AppBarTheme( + titleTextStyle: textTheme.body, + backgroundColor: colorScheme.backgroundBase, + ), + bottomAppBarTheme: BottomAppBarTheme( + color: colorScheme.backgroundBase, + ), + brightness: isLightMode ? Brightness.light : Brightness.dark, + ), + mainEditor: MainEditorConfigs( + style: MainEditorStyle( + appBarBackground: colorScheme.backgroundBase, + background: colorScheme.backgroundBase, + bottomBarBackground: colorScheme.backgroundBase, + ), + widgets: MainEditorWidgets( + removeLayerArea: (removeAreaKey, editor, rebuildStream) { + return Align( + alignment: Alignment.bottomCenter, + child: StreamBuilder( + stream: rebuildStream, + builder: (_, __) { + final isHovered = + editor.layerInteractionManager.hoverRemoveBtn; + + return AnimatedContainer( + key: removeAreaKey, + duration: const Duration(milliseconds: 150), + height: 56, + width: 56, + margin: const EdgeInsets.only(bottom: 24), + decoration: BoxDecoration( + color: isHovered + ? const Color.fromARGB(255, 255, 197, 197) + : const Color.fromARGB(255, 255, 255, 255), + shape: BoxShape.circle, + ), + padding: const EdgeInsets.all(12), + child: const Center( + child: Icon( + Icons.delete_forever_outlined, + size: 28, + color: Color(0xFFF44336), + ), + ), + ); + }, + ), + ); + }, + appBar: (editor, rebuildStream) { + return ReactiveCustomAppbar( + builder: (context) { + return ImageEditorAppBar( + enableRedo: editor.canRedo, + enableUndo: editor.canUndo, + key: const Key('image_editor_app_bar'), + redo: () => editor.redoAction(), + undo: () => editor.undoAction(), + configs: editor.configs, + done: () async { + final Uint8List bytes = + await editorKey.currentState!.captureEditorImage(); + await saveImage(bytes); + }, + close: () { + _showExitConfirmationDialog(context); + }, + isMainEditor: true, + ); + }, + stream: rebuildStream, + ); + }, + bottomBar: (editor, rebuildStream, key) => ReactiveCustomWidget( + key: key, + builder: (context) { + return ImageEditorMainBottomBar( + key: _mainEditorBarKey, + editor: editor, + configs: editor.configs, + callbacks: editor.callbacks, + ); + }, + stream: rebuildStream, + ), + ), + ), + paintEditor: PaintEditorConfigs( + style: PaintEditorStyle( + background: colorScheme.backgroundBase, + initialStrokeWidth: 5, + ), + widgets: PaintEditorWidgets( + appBar: (editor, rebuildStream) { + return ReactiveCustomAppbar( + builder: (context) { + return ImageEditorAppBar( + enableRedo: editor.canRedo, + enableUndo: editor.canUndo, + key: const Key('image_editor_app_bar'), + redo: () => editor.redoAction(), + undo: () => editor.undoAction(), + configs: editor.configs, + done: () => editor.done(), + close: () => editor.close(), + ); + }, + stream: rebuildStream, + ); + }, + colorPicker: + (paintEditor, rebuildStream, currentColor, setColor) => null, + bottomBar: (editorState, rebuildStream) { + return ReactiveCustomWidget( + builder: (context) { + return ImageEditorPaintBar( + configs: editorState.configs, + callbacks: editorState.callbacks, + editor: editorState, + i18nColor: 'Color', + ); + }, + stream: rebuildStream, + ); + }, + ), + ), + textEditor: TextEditorConfigs( + canToggleTextAlign: true, + customTextStyles: [ + GoogleFonts.inter(), + GoogleFonts.giveYouGlory(), + GoogleFonts.dmSerifText(), + GoogleFonts.comicNeue(), + ], + safeArea: const EditorSafeArea( + bottom: false, + top: false, + ), + style: const TextEditorStyle( + background: Colors.transparent, + textFieldMargin: EdgeInsets.only(top: kToolbarHeight), + ), + widgets: TextEditorWidgets( + appBar: (textEditor, rebuildStream) => null, + colorPicker: + (textEditor, rebuildStream, currentColor, setColor) => null, + bottomBar: (editorState, rebuildStream) { + return ReactiveCustomWidget( + builder: (context) { + return ImageEditorTextBar( + configs: editorState.configs, + callbacks: editorState.callbacks, + editor: editorState, + ); + }, + stream: rebuildStream, + ); + }, + ), + ), + cropRotateEditor: CropRotateEditorConfigs( + safeArea: const EditorSafeArea( + bottom: false, + top: false, + ), + style: CropRotateEditorStyle( + background: colorScheme.backgroundBase, + cropCornerColor: + Theme.of(context).colorScheme.imageEditorPrimaryColor, + ), + widgets: CropRotateEditorWidgets( + appBar: (editor, rebuildStream) { + return ReactiveCustomAppbar( + builder: (context) { + return ImageEditorAppBar( + key: const Key('image_editor_app_bar'), + configs: editor.configs, + done: () => editor.done(), + close: () => editor.close(), + enableRedo: editor.canRedo, + enableUndo: editor.canUndo, + redo: () => editor.redoAction(), + undo: () => editor.undoAction(), + ); + }, + stream: rebuildStream, + ); + }, + bottomBar: (cropRotateEditor, rebuildStream) => + ReactiveCustomWidget( + stream: rebuildStream, + builder: (_) => ImageEditorCropRotateBar( + configs: cropRotateEditor.configs, + callbacks: cropRotateEditor.callbacks, + editor: cropRotateEditor, + ), + ), + ), + ), + filterEditor: FilterEditorConfigs( + fadeInUpDuration: fadeInDuration, + fadeInUpStaggerDelayDuration: fadeInDelay, + safeArea: const EditorSafeArea(top: false), + style: FilterEditorStyle( + filterListSpacing: 7, + background: colorScheme.backgroundBase, + ), + widgets: FilterEditorWidgets( + slider: ( + editorState, + rebuildStream, + value, + onChanged, + onChangeEnd, + ) => + ReactiveCustomWidget( + builder: (context) { + return const SizedBox.shrink(); + }, + stream: rebuildStream, + ), + filterButton: ( + filter, + isSelected, + scaleFactor, + onSelectFilter, + editorImage, + filterKey, + ) { + return ImageEditorFilterBar( + filterModel: filter, + isSelected: isSelected, + onSelectFilter: onSelectFilter, + editorImage: editorImage, + filterKey: filterKey, + ); + }, + appBar: (editor, rebuildStream) { + return ReactiveCustomAppbar( + builder: (context) { + return ImageEditorAppBar( + key: const Key('image_editor_app_bar'), + configs: editor.configs, + done: () => editor.done(), + close: () => editor.close(), + ); + }, + stream: rebuildStream, + ); + }, + ), + ), + tuneEditor: TuneEditorConfigs( + safeArea: const EditorSafeArea(top: false), + style: TuneEditorStyle( + background: colorScheme.backgroundBase, + ), + widgets: TuneEditorWidgets( + appBar: (editor, rebuildStream) { + return ReactiveCustomAppbar( + builder: (context) { + return ImageEditorAppBar( + enableRedo: editor.canRedo, + enableUndo: editor.canUndo, + key: const Key('image_editor_app_bar'), + redo: () => editor.redo(), + undo: () => editor.undo(), + configs: editor.configs, + done: () => editor.done(), + close: () => editor.close(), + ); + }, + stream: rebuildStream, + ); + }, + bottomBar: (editorState, rebuildStream) { + return ReactiveCustomWidget( + builder: (context) { + return ImageEditorTuneBar( + configs: editorState.configs, + callbacks: editorState.callbacks, + editor: editorState, + ); + }, + stream: rebuildStream, + ); + }, + ), + ), + blurEditor: const BlurEditorConfigs( + enabled: false, + ), + emojiEditor: EmojiEditorConfigs( + icons: const EmojiEditorIcons(), + style: EmojiEditorStyle( + backgroundColor: colorScheme.backgroundBase, + emojiViewConfig: const EmojiViewConfig( + gridPadding: EdgeInsets.zero, + horizontalSpacing: 0, + verticalSpacing: 0, + recentsLimit: 40, + loadingIndicator: Center(child: CircularProgressIndicator()), + replaceEmojiOnLimitExceed: false, + ), + bottomActionBarConfig: const BottomActionBarConfig( + enabled: false, + ), + ), + ), + stickerEditor: const StickerEditorConfigs(enabled: false), + ), + ), + ); + } +} diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_paint_bar.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_paint_bar.dart new file mode 100644 index 0000000000..48f7b2a040 --- /dev/null +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_paint_bar.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; +import "package:photos/theme/ente_theme.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_color_picker.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_configs_mixin.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_constants.dart"; +import "package:pro_image_editor/mixins/converted_configs.dart"; +import "package:pro_image_editor/models/editor_callbacks/pro_image_editor_callbacks.dart"; +import "package:pro_image_editor/models/editor_configs/pro_image_editor_configs.dart"; +import "package:pro_image_editor/modules/paint_editor/paint_editor.dart"; +import "package:pro_image_editor/widgets/animated/fade_in_up.dart"; + +class ImageEditorPaintBar extends StatefulWidget with SimpleConfigsAccess { + const ImageEditorPaintBar({ + super.key, + required this.configs, + required this.callbacks, + required this.editor, + required this.i18nColor, + }); + + final PaintEditorState editor; + + @override + final ProImageEditorConfigs configs; + @override + final ProImageEditorCallbacks callbacks; + + final String i18nColor; + + @override + State createState() => _ImageEditorPaintBarState(); +} + +class _ImageEditorPaintBarState extends State + with ImageEditorConvertedConfigs, SimpleConfigsAccessState { + double colorSliderValue = 0.5; + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (context, constraints) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + _buildFunctions(constraints), + ], + ); + }, + ); + } + + Widget _buildFunctions(BoxConstraints constraints) { + return BottomAppBar( + height: editorBottomBarHeight, + padding: EdgeInsets.zero, + child: Align( + alignment: Alignment.center, + child: FadeInUp( + duration: fadeInDuration, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(left: 20.0), + child: Text( + "Brush Color", + style: getEnteTextTheme(context).body, + ), + ), + const SizedBox(height: 24), + ImageEditorColorPicker( + value: colorSliderValue, + onChanged: (value) { + setState(() { + colorSliderValue = value; + }); + final hue = value * 360; + final color = HSVColor.fromAHSV(1.0, hue, 1.0, 1.0).toColor(); + widget.editor.colorChanged(color); + }, + ), + ], + ), + ), + ), + ); + } +} diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_text_bar.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_text_bar.dart new file mode 100644 index 0000000000..db0d16a6e3 --- /dev/null +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_text_bar.dart @@ -0,0 +1,366 @@ +import 'package:flutter/material.dart'; +import "package:flutter_svg/svg.dart"; +import "package:photos/theme/ente_theme.dart"; +import "package:photos/ui/tools/editor/image_editor/circular_icon_button.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_color_picker.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_configs_mixin.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_constants.dart"; +import "package:pro_image_editor/mixins/converted_configs.dart"; +import 'package:pro_image_editor/pro_image_editor.dart'; + +class ImageEditorTextBar extends StatefulWidget with SimpleConfigsAccess { + const ImageEditorTextBar({ + super.key, + required this.configs, + required this.callbacks, + required this.editor, + }); + + final TextEditorState editor; + + @override + final ProImageEditorConfigs configs; + @override + final ProImageEditorCallbacks callbacks; + + @override + State createState() => _ImageEditorTextBarState(); +} + +class _ImageEditorTextBarState extends State + with ImageEditorConvertedConfigs, SimpleConfigsAccessState { + int selectedActionIndex = -1; + double colorSliderValue = 0.5; + + void _selectAction(int index) { + setState(() { + selectedActionIndex = selectedActionIndex == index ? -1 : index; + }); + } + + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (context, constraints) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + _buildFunctions(constraints), + ], + ); + }, + ); + } + + Widget _buildFunctions(BoxConstraints constraints) { + return BottomAppBar( + padding: EdgeInsets.zero, + height: editorBottomBarHeight, + child: FadeInUp( + duration: fadeInDuration, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _buildMainActionButtons(), + _buildHelperWidget(), + ], + ), + ), + ); + } + + Widget _buildMainActionButtons() { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + CircularIconButton( + svgPath: "assets/image-editor/image-editor-text-color.svg", + label: "Color", + isSelected: selectedActionIndex == 0, + onTap: () { + _selectAction(0); + }, + ), + CircularIconButton( + svgPath: "assets/image-editor/image-editor-text-font.svg", + label: "Font", + isSelected: selectedActionIndex == 1, + onTap: () { + _selectAction(1); + }, + ), + CircularIconButton( + svgPath: "assets/image-editor/image-editor-text-background.svg", + label: "Background", + isSelected: selectedActionIndex == 2, + onTap: () { + setState(() { + selectedActionIndex = 2; + }); + }, + ), + CircularIconButton( + svgPath: "assets/image-editor/image-editor-text-align-left.svg", + label: "Align", + isSelected: selectedActionIndex == 3, + onTap: () { + setState(() { + selectedActionIndex = 3; + }); + }, + ), + ], + ); + } + + Widget _buildHelperWidget() { + return AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + switchInCurve: Curves.easeInOut, + switchOutCurve: Curves.easeInOut, + child: switch (selectedActionIndex) { + 0 => ImageEditorColorPicker( + value: colorSliderValue, + onChanged: (value) { + setState(() { + colorSliderValue = value; + }); + final hue = value * 360; + final color = HSVColor.fromAHSV(1.0, hue, 1.0, 1.0).toColor(); + widget.editor.primaryColor = color; + }, + ), + 1 => _FontPickerWidget(editor: widget.editor), + 2 => _BackgroundPickerWidget(editor: widget.editor), + 3 => _AlignPickerWidget(editor: widget.editor), + _ => const SizedBox.shrink(), + }, + ); + } +} + +class _FontPickerWidget extends StatelessWidget { + final TextEditorState editor; + + const _FontPickerWidget({required this.editor}); + + @override + Widget build(BuildContext context) { + final colorScheme = getEnteColorScheme(context); + if (editor.textEditorConfigs.customTextStyles == null) { + return const SizedBox.shrink(); + } + + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: editor.textEditorConfigs.customTextStyles! + .asMap() + .entries + .map((entry) { + final item = entry.value; + final selected = editor.selectedTextStyle; + final bool isSelected = selected.hashCode == item.hashCode; + + return Padding( + padding: const EdgeInsets.only(right: 12), + child: GestureDetector( + onTap: () { + editor.setTextStyle(item); + }, + child: Container( + height: 40, + width: 48, + decoration: BoxDecoration( + color: isSelected + ? colorScheme.fillBasePressed + : colorScheme.backgroundElevated2, + borderRadius: BorderRadius.circular(25), + ), + child: Center( + child: Text( + 'Aa', + style: item.copyWith( + color: isSelected + ? colorScheme.backdropBase + : colorScheme.tabIcon, + ), + ), + ), + ), + ), + ); + }).toList(), + ); + } +} + +class _BackgroundPickerWidget extends StatelessWidget { + final TextEditorState editor; + + const _BackgroundPickerWidget({required this.editor}); + + @override + Widget build(BuildContext context) { + final colorScheme = getEnteColorScheme(context); + final isLightMode = Theme.of(context).brightness == Brightness.light; + final backgroundStyles = { + LayerBackgroundMode.background: { + 'text': 'Aa', + 'backgroundColor': isLightMode ? colorScheme.fillFaint : Colors.white, + 'border': null, + 'textColor': Colors.white, + 'innerBackgroundColor': Colors.black, + }, + LayerBackgroundMode.backgroundAndColor: { + 'text': 'Aa', + 'backgroundColor': isLightMode ? colorScheme.fillFaint : Colors.white, + 'border': null, + 'textColor': Colors.black, + 'innerBackgroundColor': Colors.transparent, + }, + LayerBackgroundMode.backgroundAndColorWithOpacity: { + 'text': 'Aa', + 'backgroundColor': isLightMode ? colorScheme.fillFaint : Colors.white, + 'border': null, + 'textColor': Colors.black, + 'innerBackgroundColor': Colors.black.withOpacity(0.11), + }, + LayerBackgroundMode.onlyColor: { + 'text': 'Aa', + 'backgroundColor': isLightMode ? colorScheme.fillFaint : Colors.black, + 'border': + isLightMode ? null : Border.all(color: Colors.white, width: 2), + 'textColor': Colors.black, + 'innerBackgroundColor': Colors.white, + }, + }; + + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: backgroundStyles.entries.map((entry) { + final mode = entry.key; + final style = entry.value; + final isSelected = editor.backgroundColorMode == mode; + + return Padding( + padding: const EdgeInsets.only(right: 12), + child: GestureDetector( + onTap: () { + editor.setState(() { + editor.backgroundColorMode = mode; + }); + }, + child: SizedBox( + height: 40, + width: 48, + child: Container( + decoration: BoxDecoration( + color: isSelected + ? style['backgroundColor'] as Color + : colorScheme.backgroundElevated2, + borderRadius: BorderRadius.circular(25), + border: isSelected ? style['border'] as Border? : null, + ), + child: Stack( + alignment: Alignment.center, + children: [ + Center( + child: Container( + height: 20, + width: 22, + decoration: ShapeDecoration( + color: isSelected + ? style['innerBackgroundColor'] as Color + : colorScheme.backgroundElevated2, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4), + ), + ), + ), + ), + Center( + child: Text( + style['text'] as String, + style: TextStyle( + color: isSelected + ? style['textColor'] as Color + : colorScheme.tabIcon, + ), + ), + ), + ], + ), + ), + ), + ), + ); + }).toList(), + ); + } +} + +class _AlignPickerWidget extends StatelessWidget { + final TextEditorState editor; + + const _AlignPickerWidget({required this.editor}); + + @override + Widget build(BuildContext context) { + final colorScheme = getEnteColorScheme(context); + final alignments = [ + (TextAlign.left, "assets/image-editor/image-editor-text-align-left.svg"), + ( + TextAlign.center, + "assets/image-editor/image-editor-text-align-center.svg" + ), + ( + TextAlign.right, + "assets/image-editor/image-editor-text-align-right.svg" + ), + ]; + + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: alignments.map((alignmentData) { + final (alignment, svgPath) = alignmentData; + final isSelected = editor.align == alignment; + + return Padding( + padding: const EdgeInsets.only(right: 12.0), + child: GestureDetector( + onTap: () { + editor.setState(() { + editor.align = alignment; + }); + }, + child: Container( + height: 40, + width: 48, + decoration: BoxDecoration( + color: isSelected + ? colorScheme.fillBasePressed + : colorScheme.backgroundElevated2, + borderRadius: BorderRadius.circular(25), + border: isSelected + ? Border.all(color: Colors.black, width: 2) + : null, + ), + child: Center( + child: SvgPicture.asset( + svgPath, + width: 22, + height: 22, + fit: BoxFit.scaleDown, + colorFilter: ColorFilter.mode( + isSelected ? colorScheme.backdropBase : colorScheme.tabIcon, + BlendMode.srcIn, + ), + ), + ), + ), + ), + ); + }).toList(), + ); + } +} diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_tune_bar.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_tune_bar.dart new file mode 100644 index 0000000000..1ebc163103 --- /dev/null +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_tune_bar.dart @@ -0,0 +1,649 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import "package:flutter_svg/svg.dart"; +import "package:photos/ente_theme_data.dart"; +import "package:photos/theme/ente_theme.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_configs_mixin.dart"; +import "package:photos/ui/tools/editor/image_editor/image_editor_constants.dart"; +import "package:pro_image_editor/mixins/converted_configs.dart"; +import "package:pro_image_editor/models/editor_callbacks/pro_image_editor_callbacks.dart"; +import "package:pro_image_editor/models/editor_configs/pro_image_editor_configs.dart"; +import "package:pro_image_editor/modules/tune_editor/tune_editor.dart"; +import "package:pro_image_editor/widgets/animated/fade_in_up.dart"; + +class ImageEditorTuneBar extends StatefulWidget with SimpleConfigsAccess { + const ImageEditorTuneBar({ + super.key, + required this.configs, + required this.callbacks, + required this.editor, + }); + + final TuneEditorState editor; + + @override + final ProImageEditorConfigs configs; + + @override + final ProImageEditorCallbacks callbacks; + + @override + State createState() => _ImageEditorTuneBarState(); +} + +class _ImageEditorTuneBarState extends State + with ImageEditorConvertedConfigs, SimpleConfigsAccessState { + TuneEditorState get tuneEditor => widget.editor; + + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (context, constraints) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + _buildFunctions(constraints), + ], + ); + }, + ); + } + + Widget _buildFunctions(BoxConstraints constraints) { + return SizedBox( + width: double.infinity, + height: editorBottomBarHeight, + child: FadeInUp( + duration: fadeInDuration, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + SizedBox( + height: 90, + child: SingleChildScrollView( + controller: tuneEditor.bottomBarScrollCtrl, + scrollDirection: Axis.horizontal, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: List.generate( + tuneEditor.tuneAdjustmentMatrix.length, (index) { + final item = tuneEditor.tuneAdjustmentList[index]; + return TuneItem( + icon: item.icon, + label: item.label, + isSelected: tuneEditor.selectedIndex == index, + value: tuneEditor.tuneAdjustmentMatrix[index].value, + max: item.max, + min: item.min, + onTap: () { + tuneEditor.setState(() { + tuneEditor.selectedIndex = index; + }); + }, + ); + }), + ), + ), + ), + RepaintBoundary( + child: StreamBuilder( + stream: tuneEditor.uiStream.stream, + builder: (context, snapshot) { + final activeOption = + tuneEditor.tuneAdjustmentList[tuneEditor.selectedIndex]; + final activeMatrix = + tuneEditor.tuneAdjustmentMatrix[tuneEditor.selectedIndex]; + + return _TuneAdjustWidget( + min: activeOption.min, + max: activeOption.max, + value: activeMatrix.value, + onChanged: tuneEditor.onChanged, + ); + }, + ), + ), + ], + ), + ), + ); + } +} + +class TuneItem extends StatelessWidget { + final IconData icon; + final String label; + final bool isSelected; + final double value; + final double min; + final double max; + final VoidCallback onTap; + + const TuneItem({ + super.key, + required this.icon, + required this.label, + required this.isSelected, + required this.value, + required this.min, + required this.max, + required this.onTap, + }); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onTap, + child: SizedBox( + width: 90, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + CircularProgressWithValue( + value: value, + min: min, + max: max, + size: 60, + icon: icon, + isSelected: isSelected, + progressColor: + Theme.of(context).colorScheme.imageEditorPrimaryColor, + svgPath: + "assets/image-editor/image-editor-${label.toLowerCase()}.svg", + ), + const SizedBox(height: 8), + Text( + label, + style: getEnteTextTheme(context).small, + textAlign: TextAlign.center, + ), + ], + ), + ), + ); + } +} + +class CircularProgressWithValue extends StatefulWidget { + final double value; + final double min; + final double max; + final IconData icon; + final bool isSelected; + final double size; + final Color progressColor; + final String? svgPath; + + const CircularProgressWithValue({ + super.key, + required this.value, + required this.min, + required this.max, + required this.icon, + required this.progressColor, + this.isSelected = false, + this.size = 60, + this.svgPath, + }); + + @override + State createState() => + _CircularProgressWithValueState(); +} + +class _CircularProgressWithValueState extends State + with SingleTickerProviderStateMixin { + late AnimationController _animationController; + late Animation _progressAnimation; + double _previousValue = 0.0; + + @override + void initState() { + super.initState(); + _animationController = AnimationController( + vsync: this, + duration: const Duration(milliseconds: 300), + animationBehavior: AnimationBehavior.preserve, + ); + + _progressAnimation = Tween( + begin: 0.0, + end: widget.value, + ).animate( + CurvedAnimation( + parent: _animationController, + curve: Curves.easeInOut, + ), + ); + + _animationController.forward(); + } + + @override + void didUpdateWidget(CircularProgressWithValue oldWidget) { + super.didUpdateWidget(oldWidget); + + if (oldWidget.value != widget.value) { + _previousValue = oldWidget.value; + _progressAnimation = Tween( + begin: _previousValue, + end: widget.value, + ).animate( + CurvedAnimation( + parent: _animationController, + curve: Curves.easeInOut, + ), + ); + _animationController.forward(from: 0.0); + } + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + + int _normalizeValueForDisplay(double value, double min, double max) { + if (min == -0.5 && max == 0.5) { + return (value * 200).round(); + } else if (min == 0 && max == 1) { + return (value * 100).round(); + } else if (min == -0.25 && max == 0.25) { + return (value * 400).round(); + } else { + return (value * 100).round(); + } + } + + double _normalizeValueForProgress(double value, double min, double max) { + if (min == -0.5 && max == 0.5) { + return (value.abs() / 0.5).clamp(0.0, 1.0); + } else if (min == 0 && max == 1) { + return (value / 1.0).clamp(0.0, 1.0); + } else if (min == -0.25 && max == 0.25) { + return (value.abs() / 0.25).clamp(0.0, 1.0); + } else { + return (value.abs() / 1.0).clamp(0.0, 1.0); + } + } + + bool _isClockwise(double value, double min, double max) { + if (min >= 0) { + return true; + } else { + return value >= 0; + } + } + + @override + Widget build(BuildContext context) { + final colorTheme = getEnteColorScheme(context); + final textTheme = getEnteTextTheme(context); + final displayValue = + _normalizeValueForDisplay(widget.value, widget.min, widget.max); + final displayText = displayValue.toString(); + final prefix = displayValue > 0 ? "+" : ""; + final progressColor = widget.progressColor; + + final showValue = displayValue != 0 || widget.isSelected; + + return SizedBox( + width: widget.size, + height: widget.size, + child: Stack( + alignment: Alignment.center, + children: [ + Container( + width: widget.size, + height: widget.size, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: showValue || widget.isSelected + ? progressColor.withOpacity(0.2) + : colorTheme.backgroundElevated2, + border: Border.all( + color: widget.isSelected + ? progressColor.withOpacity(0.4) + : colorTheme.backgroundElevated2, + width: 2, + ), + ), + ), + AnimatedBuilder( + animation: _progressAnimation, + builder: (context, child) { + final animatedValue = _progressAnimation.value; + final isClockwise = + _isClockwise(animatedValue, widget.min, widget.max); + final progressValue = _normalizeValueForProgress( + animatedValue, + widget.min, + widget.max, + ); + + return SizedBox( + width: widget.size, + height: widget.size, + child: CustomPaint( + painter: CircularProgressPainter( + progress: progressValue, + isClockwise: isClockwise, + color: progressColor, + ), + ), + ); + }, + ), + Align( + alignment: Alignment.center, + child: showValue + ? Text( + "$prefix$displayText", + style: textTheme.smallBold, + ) + : widget.svgPath != null + ? SvgPicture.asset( + widget.svgPath!, + width: 22, + height: 22, + fit: BoxFit.scaleDown, + colorFilter: ColorFilter.mode( + colorTheme.tabIcon, + BlendMode.srcIn, + ), + ) + : Icon( + widget.icon, + color: colorTheme.tabIcon, + size: 20, + ), + ), + ], + ), + ); + } +} + +class _TuneAdjustWidget extends StatelessWidget { + final double min; + final double max; + final double value; + final ValueChanged onChanged; + + const _TuneAdjustWidget({ + required this.min, + required this.max, + required this.value, + required this.onChanged, + }); + + @override + Widget build(BuildContext context) { + final colorScheme = getEnteColorScheme(context); + return SizedBox( + height: 40, + child: Stack( + alignment: Alignment.center, + children: [ + Positioned.fill( + child: Container( + margin: const EdgeInsets.symmetric(horizontal: 20), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(25), + color: colorScheme.backgroundElevated2, + ), + ), + ), + Container( + margin: const EdgeInsets.symmetric(horizontal: 20), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(25), + ), + child: SliderTheme( + data: SliderTheme.of(context).copyWith( + thumbShape: const _ColorPickerThumbShape(), + overlayShape: const RoundSliderOverlayShape(overlayRadius: 0), + activeTrackColor: + Theme.of(context).colorScheme.imageEditorPrimaryColor, + inactiveTrackColor: colorScheme.backgroundElevated2, + trackShape: const _CenterBasedTrackShape(), + trackHeight: 24, + ), + child: Slider( + value: value, + onChanged: onChanged, + min: min, + max: max, + ), + ), + ), + Container( + margin: const EdgeInsets.symmetric(horizontal: 38), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + width: 6, + height: 6, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: colorScheme.fillBase.withAlpha(30), + ), + ), + Container( + width: 6, + height: 6, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: colorScheme.fillBase.withAlpha(30), + ), + ), + Container( + width: 6, + height: 6, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: colorScheme.fillBase.withAlpha(30), + ), + ), + ], + ), + ), + ], + ), + ); + } +} + +class _ColorPickerThumbShape extends SliderComponentShape { + const _ColorPickerThumbShape(); + + @override + Size getPreferredSize(bool isEnabled, bool isDiscrete) { + return const Size(20, 20); + } + + @override + void paint( + PaintingContext context, + Offset center, { + required Animation activationAnimation, + required Animation enableAnimation, + required bool isDiscrete, + required TextPainter labelPainter, + required RenderBox parentBox, + required Size sizeWithOverflow, + required SliderThemeData sliderTheme, + required TextDirection textDirection, + required double textScaleFactor, + required double value, + }) { + final canvas = context.canvas; + + final trackRect = sliderTheme.trackShape!.getPreferredRect( + parentBox: parentBox, + offset: Offset.zero, + sliderTheme: sliderTheme, + isEnabled: true, + isDiscrete: isDiscrete, + ); + + final constrainedCenter = Offset( + center.dx.clamp(trackRect.left + 15, trackRect.right - 15), + center.dy, + ); + + final paint = Paint() + ..color = Colors.white + ..style = PaintingStyle.fill; + + canvas.drawCircle(constrainedCenter, 15, paint); + + final innerPaint = Paint() + ..color = const Color.fromRGBO(8, 194, 37, 1) + ..style = PaintingStyle.fill; + canvas.drawCircle(constrainedCenter, 12.5, innerPaint); + } +} + +class _CenterBasedTrackShape extends SliderTrackShape { + const _CenterBasedTrackShape(); + + static const double horizontalPadding = 6.0; + + @override + Rect getPreferredRect({ + required RenderBox parentBox, + Offset offset = Offset.zero, + required SliderThemeData sliderTheme, + bool isEnabled = false, + bool isDiscrete = false, + }) { + final double trackHeight = sliderTheme.trackHeight ?? 8; + final double trackLeft = offset.dx + horizontalPadding; + final double trackTop = + offset.dy + (parentBox.size.height - trackHeight) / 2; + final double trackWidth = parentBox.size.width - (horizontalPadding * 2); + return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight); + } + + @override + void paint( + PaintingContext context, + Offset offset, { + required RenderBox parentBox, + required SliderThemeData sliderTheme, + required Animation enableAnimation, + required TextDirection textDirection, + required Offset thumbCenter, + Offset? secondaryOffset, + bool isEnabled = false, + bool isDiscrete = false, + double? additionalActiveTrackHeight, + }) { + final Canvas canvas = context.canvas; + final Rect trackRect = getPreferredRect( + parentBox: parentBox, + offset: offset, + sliderTheme: sliderTheme, + isEnabled: isEnabled, + isDiscrete: isDiscrete, + ); + + final double centerX = trackRect.left + trackRect.width / 2; + + final double clampedThumbDx = thumbCenter.dx.clamp( + trackRect.left, + trackRect.right, + ); + + final Paint inactivePaint = Paint() + ..color = sliderTheme.inactiveTrackColor! + ..style = PaintingStyle.fill; + + final RRect inactiveRRect = RRect.fromRectAndRadius( + trackRect, + Radius.circular(trackRect.height / 2), + ); + + canvas.drawRRect(inactiveRRect, inactivePaint); + + if (clampedThumbDx != centerX) { + final Paint activePaint = Paint() + ..color = sliderTheme.activeTrackColor! + ..style = PaintingStyle.fill; + + final Rect activeRect = clampedThumbDx >= centerX + ? Rect.fromLTWH( + centerX, + trackRect.top, + clampedThumbDx - centerX, + trackRect.height, + ) + : Rect.fromLTWH( + clampedThumbDx, + trackRect.top, + centerX - clampedThumbDx, + trackRect.height, + ); + + final RRect activeRRect = RRect.fromRectAndRadius( + activeRect, + Radius.circular(trackRect.height / 2), + ); + + canvas.drawRRect(activeRRect, activePaint); + } + } +} + +class CircularProgressPainter extends CustomPainter { + final double progress; + final bool isClockwise; + final Color color; + + CircularProgressPainter({ + required this.progress, + required this.isClockwise, + required this.color, + }); + + @override + void paint(Canvas canvas, Size size) { + const strokeWidth = 2.5; + final center = Offset(size.width / 2, size.height / 2); + final radius = (size.width - strokeWidth) / 2; + + final backgroundPaint = Paint() + ..color = Colors.transparent + ..strokeWidth = strokeWidth + ..style = PaintingStyle.stroke; + + final foregroundPaint = Paint() + ..color = color + ..strokeWidth = strokeWidth + ..style = PaintingStyle.stroke + ..strokeCap = StrokeCap.round; + + canvas.drawCircle(center, radius, backgroundPaint); + + if (progress > 0) { + const startAngle = -pi / 2; + final sweepAngle = 2 * pi * progress * (isClockwise ? 1 : -1); + + canvas.drawArc( + Rect.fromCircle(center: center, radius: radius), + startAngle, + sweepAngle, + false, + foregroundPaint, + ); + } + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) => true; +} From cf75528f5e849861e209e1753d05b955d595334b Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Wed, 23 Jul 2025 23:47:49 +0530 Subject: [PATCH 07/28] Add new image editor functionality to detail page --- .../lib/ui/viewer/file/detail_page.dart | 65 ++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/mobile/apps/photos/lib/ui/viewer/file/detail_page.dart b/mobile/apps/photos/lib/ui/viewer/file/detail_page.dart index 2df8e6520b..5cb0d8fcbe 100644 --- a/mobile/apps/photos/lib/ui/viewer/file/detail_page.dart +++ b/mobile/apps/photos/lib/ui/viewer/file/detail_page.dart @@ -19,6 +19,7 @@ import "package:photos/services/local_authentication_service.dart"; import "package:photos/states/detail_page_state.dart"; import "package:photos/ui/common/fast_scroll_physics.dart"; import 'package:photos/ui/notification/toast.dart'; +import "package:photos/ui/tools/editor/image_editor/image_editor_page_new.dart"; import 'package:photos/ui/tools/editor/image_editor_page.dart'; import "package:photos/ui/tools/editor/video_editor_page.dart"; import "package:photos/ui/viewer/file/file_app_bar.dart"; @@ -175,7 +176,7 @@ class _DetailPageState extends State { builder: (BuildContext context, int selectedIndex, _) { return FileBottomBar( _files![selectedIndex], - _onEditFileRequested, + _onNewImageEditor, widget.config.mode == DetailPageMode.minimalistic && !isGuestView, onFileRemoved: _onFileRemoved, @@ -357,6 +358,68 @@ class _DetailPageState extends State { } } + Future _onNewImageEditor(EnteFile file) async { + if (file.uploadedFileID != null && + file.ownerID != Configuration.instance.getUserID()) { + _logger.severe( + "Attempt to edit unowned file", + UnauthorizedEditError(), + StackTrace.current, + ); + // ignore: unawaited_futures + showErrorDialog( + context, + S.of(context).sorry, + S.of(context).weDontSupportEditingPhotosAndAlbumsThatYouDont, + ); + return; + } + final dialog = createProgressDialog(context, S.of(context).pleaseWait); + await dialog.show(); + + try { + final ioFile = await getFile(file); + if (ioFile == null) { + showShortToast(context, S.of(context).failedToFetchOriginalForEdit); + await dialog.hide(); + return; + } + if (file.fileType == FileType.video) { + await dialog.hide(); + replacePage( + context, + VideoEditorPage( + file: file, + ioFile: ioFile, + detailPageConfig: widget.config.copyWith( + files: _files, + selectedIndex: _selectedIndexNotifier.value, + ), + ), + ); + return; + } + final imageProvider = + ExtendedFileImageProvider(ioFile, cacheRawData: true); + await precacheImage(imageProvider, context); + await dialog.hide(); + replacePage( + context, + NewImageEditor( + originalFile: file, + file: ioFile, + detailPageConfig: widget.config.copyWith( + files: _files, + selectedIndex: _selectedIndexNotifier.value, + ), + ), + ); + } catch (e) { + await dialog.hide(); + _logger.warning("Failed to initiate edit", e); + } + } + Future _onEditFileRequested(EnteFile file) async { if (file.uploadedFileID != null && file.ownerID != Configuration.instance.getUserID()) { From b8bb3d573031a6dfe152958b201094e77b0ebbb6 Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Wed, 23 Jul 2025 23:48:07 +0530 Subject: [PATCH 08/28] Add google_fonts dependency and include image-editor assets --- mobile/apps/photos/pubspec.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mobile/apps/photos/pubspec.yaml b/mobile/apps/photos/pubspec.yaml index 41c26fe860..59fc710426 100644 --- a/mobile/apps/photos/pubspec.yaml +++ b/mobile/apps/photos/pubspec.yaml @@ -109,6 +109,7 @@ dependencies: fluttertoast: ^8.0.6 fraction: ^5.0.2 freezed_annotation: ^2.4.1 + google_fonts: ^6.2.1 home_widget: ^0.7.0+1 html_unescape: ^2.0.0 http: ^1.1.0 @@ -343,6 +344,7 @@ flutter: assets: - assets/ - assets/video-editor/ + - assets/image-editor/ - assets/icons/ - assets/launcher_icon/ fonts: From 0289a5535e025a256933d5aea1f6e364ee28ddfe Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Thu, 24 Jul 2025 14:20:41 +0530 Subject: [PATCH 09/28] Fix pubspec.lock file --- mobile/apps/photos/pubspec.lock | 74 ++++++++++++++++----------------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/mobile/apps/photos/pubspec.lock b/mobile/apps/photos/pubspec.lock index bb1b26279a..a4417cd068 100644 --- a/mobile/apps/photos/pubspec.lock +++ b/mobile/apps/photos/pubspec.lock @@ -6,11 +6,9 @@ packages: description: name: _fe_analyzer_shared sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab" - sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab" url: "https://pub.dev" source: hosted version: "76.0.0" - version: "76.0.0" _flutterfire_internals: dependency: transitive description: @@ -24,7 +22,6 @@ packages: description: dart source: sdk version: "0.3.3" - version: "0.3.3" adaptive_theme: dependency: "direct main" description: @@ -38,11 +35,9 @@ packages: description: name: analyzer sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" - sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" url: "https://pub.dev" source: hosted version: "6.11.0" - version: "6.11.0" android_intent_plus: dependency: "direct main" description: @@ -135,10 +130,10 @@ packages: dependency: "direct main" description: name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.11.0" battery_info: dependency: "direct main" description: @@ -160,10 +155,10 @@ packages: dependency: transitive description: name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" brotli: dependency: transitive description: @@ -273,10 +268,10 @@ packages: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.3.0" checked_yaml: dependency: transitive description: @@ -306,10 +301,10 @@ packages: dependency: transitive description: name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.1" code_builder: dependency: transitive description: @@ -632,10 +627,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.1" fast_base58: dependency: "direct main" description: @@ -681,10 +676,10 @@ packages: dependency: transitive description: name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" url: "https://pub.dev" source: hosted - version: "7.0.1" + version: "7.0.0" file_saver: dependency: "direct main" description: @@ -1180,6 +1175,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.3" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82 + url: "https://pub.dev" + source: hosted + version: "6.2.1" graphs: dependency: transitive description: @@ -1550,11 +1553,9 @@ packages: description: name: macros sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656" - sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656" url: "https://pub.dev" source: hosted version: "0.1.3-main.0" - version: "0.1.3-main.0" maps_launcher: dependency: "direct main" description: @@ -1567,10 +1568,10 @@ packages: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.17" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: @@ -1660,10 +1661,10 @@ packages: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.15.0" mgrs_dart: dependency: transitive description: @@ -1874,10 +1875,10 @@ packages: dependency: "direct main" description: name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.9.0" path_drawing: dependency: transitive description: @@ -2034,10 +2035,10 @@ packages: dependency: transitive description: name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" url: "https://pub.dev" source: hosted - version: "3.1.6" + version: "3.1.5" plugin_platform_interface: dependency: transitive description: @@ -2091,10 +2092,10 @@ packages: dependency: transitive description: name: process - sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" + sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" url: "https://pub.dev" source: hosted - version: "5.0.3" + version: "5.0.2" proj4dart: dependency: transitive description: @@ -2333,7 +2334,6 @@ packages: description: flutter source: sdk version: "0.0.0" - version: "0.0.0" source_gen: dependency: transitive description: @@ -2370,10 +2370,10 @@ packages: dependency: transitive description: name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.10.1" + version: "1.10.0" sprintf: dependency: transitive description: @@ -2474,10 +2474,10 @@ packages: dependency: transitive description: name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.2" stream_transform: dependency: transitive description: @@ -2546,10 +2546,10 @@ packages: dependency: transitive description: name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "1.2.1" test: dependency: "direct dev" description: @@ -2918,11 +2918,9 @@ packages: description: name: webdriver sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" - sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" url: "https://pub.dev" source: hosted version: "3.0.4" - version: "3.0.4" webkit_inspection_protocol: dependency: transitive description: From d466b77f0e7f3a3887271360074e22c1926aa816 Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Thu, 24 Jul 2025 15:59:34 +0530 Subject: [PATCH 10/28] Fix: show custom warning dialog --- .../image_editor/image_editor_page_new.dart | 631 +++++++++--------- 1 file changed, 324 insertions(+), 307 deletions(-) diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart index da15c97924..785e13687a 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart @@ -178,334 +178,351 @@ class _NewImageEditorState extends State { final textTheme = getEnteTextTheme(context); return Scaffold( backgroundColor: colorScheme.backgroundBase, - body: ProImageEditor.file( - key: editorKey, - widget.file, - callbacks: ProImageEditorCallbacks( - mainEditorCallbacks: MainEditorCallbacks( - onStartCloseSubEditor: (value) { - _mainEditorBarKey.currentState?.setState(() {}); + body: PopScope( + canPop: false, + onPopInvoked: (didPop) { + if (didPop) return; + editorKey.currentState?.disablePopScope = true; + _showExitConfirmationDialog(context); + }, + child: ProImageEditor.file( + key: editorKey, + widget.file, + callbacks: ProImageEditorCallbacks( + onCloseEditor: () { + editorKey.currentState?.disablePopScope = true; + _showExitConfirmationDialog(context); }, - ), - ), - configs: ProImageEditorConfigs( - layerInteraction: const LayerInteractionConfigs( - hideToolbarOnInteraction: false, - ), - theme: ThemeData( - scaffoldBackgroundColor: colorScheme.backgroundBase, - appBarTheme: AppBarTheme( - titleTextStyle: textTheme.body, - backgroundColor: colorScheme.backgroundBase, + mainEditorCallbacks: MainEditorCallbacks( + onStartCloseSubEditor: (value) { + _mainEditorBarKey.currentState?.setState(() {}); + }, + onPopInvoked: (didPop, result) { + editorKey.currentState?.disablePopScope = false; + }, ), - bottomAppBarTheme: BottomAppBarTheme( - color: colorScheme.backgroundBase, - ), - brightness: isLightMode ? Brightness.light : Brightness.dark, ), - mainEditor: MainEditorConfigs( - style: MainEditorStyle( - appBarBackground: colorScheme.backgroundBase, - background: colorScheme.backgroundBase, - bottomBarBackground: colorScheme.backgroundBase, + configs: ProImageEditorConfigs( + layerInteraction: const LayerInteractionConfigs( + hideToolbarOnInteraction: false, ), - widgets: MainEditorWidgets( - removeLayerArea: (removeAreaKey, editor, rebuildStream) { - return Align( - alignment: Alignment.bottomCenter, - child: StreamBuilder( - stream: rebuildStream, - builder: (_, __) { - final isHovered = - editor.layerInteractionManager.hoverRemoveBtn; + theme: ThemeData( + scaffoldBackgroundColor: colorScheme.backgroundBase, + appBarTheme: AppBarTheme( + titleTextStyle: textTheme.body, + backgroundColor: colorScheme.backgroundBase, + ), + bottomAppBarTheme: BottomAppBarTheme( + color: colorScheme.backgroundBase, + ), + brightness: isLightMode ? Brightness.light : Brightness.dark, + ), + mainEditor: MainEditorConfigs( + enableCloseButton: false, + style: MainEditorStyle( + appBarBackground: colorScheme.backgroundBase, + background: colorScheme.backgroundBase, + bottomBarBackground: colorScheme.backgroundBase, + ), + widgets: MainEditorWidgets( + removeLayerArea: (removeAreaKey, editor, rebuildStream) { + return Align( + alignment: Alignment.bottomCenter, + child: StreamBuilder( + stream: rebuildStream, + builder: (_, __) { + final isHovered = + editor.layerInteractionManager.hoverRemoveBtn; - return AnimatedContainer( - key: removeAreaKey, - duration: const Duration(milliseconds: 150), - height: 56, - width: 56, - margin: const EdgeInsets.only(bottom: 24), - decoration: BoxDecoration( - color: isHovered - ? const Color.fromARGB(255, 255, 197, 197) - : const Color.fromARGB(255, 255, 255, 255), - shape: BoxShape.circle, - ), - padding: const EdgeInsets.all(12), - child: const Center( - child: Icon( - Icons.delete_forever_outlined, - size: 28, - color: Color(0xFFF44336), + return AnimatedContainer( + key: removeAreaKey, + duration: const Duration(milliseconds: 150), + height: 56, + width: 56, + margin: const EdgeInsets.only(bottom: 24), + decoration: BoxDecoration( + color: isHovered + ? const Color.fromARGB(255, 255, 197, 197) + : const Color.fromARGB(255, 255, 255, 255), + shape: BoxShape.circle, ), - ), - ); - }, - ), - ); - }, - appBar: (editor, rebuildStream) { - return ReactiveCustomAppbar( - builder: (context) { - return ImageEditorAppBar( - enableRedo: editor.canRedo, - enableUndo: editor.canUndo, - key: const Key('image_editor_app_bar'), - redo: () => editor.redoAction(), - undo: () => editor.undoAction(), - configs: editor.configs, - done: () async { - final Uint8List bytes = - await editorKey.currentState!.captureEditorImage(); - await saveImage(bytes); + padding: const EdgeInsets.all(12), + child: const Center( + child: Icon( + Icons.delete_forever_outlined, + size: 28, + color: Color(0xFFF44336), + ), + ), + ); }, - close: () { - _showExitConfirmationDialog(context); - }, - isMainEditor: true, - ); - }, - stream: rebuildStream, - ); - }, - bottomBar: (editor, rebuildStream, key) => ReactiveCustomWidget( - key: key, - builder: (context) { - return ImageEditorMainBottomBar( - key: _mainEditorBarKey, - editor: editor, - configs: editor.configs, - callbacks: editor.callbacks, + ), ); }, - stream: rebuildStream, - ), - ), - ), - paintEditor: PaintEditorConfigs( - style: PaintEditorStyle( - background: colorScheme.backgroundBase, - initialStrokeWidth: 5, - ), - widgets: PaintEditorWidgets( - appBar: (editor, rebuildStream) { - return ReactiveCustomAppbar( + appBar: (editor, rebuildStream) { + return ReactiveCustomAppbar( + builder: (context) { + return ImageEditorAppBar( + enableRedo: editor.canRedo, + enableUndo: editor.canUndo, + key: const Key('image_editor_app_bar'), + redo: () => editor.redoAction(), + undo: () => editor.undoAction(), + configs: editor.configs, + done: () async { + final Uint8List bytes = await editorKey.currentState! + .captureEditorImage(); + await saveImage(bytes); + }, + close: () { + _showExitConfirmationDialog(context); + }, + isMainEditor: true, + ); + }, + stream: rebuildStream, + ); + }, + bottomBar: (editor, rebuildStream, key) => ReactiveCustomWidget( + key: key, builder: (context) { - return ImageEditorAppBar( - enableRedo: editor.canRedo, - enableUndo: editor.canUndo, - key: const Key('image_editor_app_bar'), - redo: () => editor.redoAction(), - undo: () => editor.undoAction(), + return ImageEditorMainBottomBar( + key: _mainEditorBarKey, + editor: editor, configs: editor.configs, - done: () => editor.done(), - close: () => editor.close(), + callbacks: editor.callbacks, ); }, stream: rebuildStream, - ); - }, - colorPicker: - (paintEditor, rebuildStream, currentColor, setColor) => null, - bottomBar: (editorState, rebuildStream) { - return ReactiveCustomWidget( - builder: (context) { - return ImageEditorPaintBar( - configs: editorState.configs, - callbacks: editorState.callbacks, - editor: editorState, - i18nColor: 'Color', - ); - }, - stream: rebuildStream, - ); - }, - ), - ), - textEditor: TextEditorConfigs( - canToggleTextAlign: true, - customTextStyles: [ - GoogleFonts.inter(), - GoogleFonts.giveYouGlory(), - GoogleFonts.dmSerifText(), - GoogleFonts.comicNeue(), - ], - safeArea: const EditorSafeArea( - bottom: false, - top: false, - ), - style: const TextEditorStyle( - background: Colors.transparent, - textFieldMargin: EdgeInsets.only(top: kToolbarHeight), - ), - widgets: TextEditorWidgets( - appBar: (textEditor, rebuildStream) => null, - colorPicker: - (textEditor, rebuildStream, currentColor, setColor) => null, - bottomBar: (editorState, rebuildStream) { - return ReactiveCustomWidget( - builder: (context) { - return ImageEditorTextBar( - configs: editorState.configs, - callbacks: editorState.callbacks, - editor: editorState, - ); - }, - stream: rebuildStream, - ); - }, - ), - ), - cropRotateEditor: CropRotateEditorConfigs( - safeArea: const EditorSafeArea( - bottom: false, - top: false, - ), - style: CropRotateEditorStyle( - background: colorScheme.backgroundBase, - cropCornerColor: - Theme.of(context).colorScheme.imageEditorPrimaryColor, - ), - widgets: CropRotateEditorWidgets( - appBar: (editor, rebuildStream) { - return ReactiveCustomAppbar( - builder: (context) { - return ImageEditorAppBar( - key: const Key('image_editor_app_bar'), - configs: editor.configs, - done: () => editor.done(), - close: () => editor.close(), - enableRedo: editor.canRedo, - enableUndo: editor.canUndo, - redo: () => editor.redoAction(), - undo: () => editor.undoAction(), - ); - }, - stream: rebuildStream, - ); - }, - bottomBar: (cropRotateEditor, rebuildStream) => - ReactiveCustomWidget( - stream: rebuildStream, - builder: (_) => ImageEditorCropRotateBar( - configs: cropRotateEditor.configs, - callbacks: cropRotateEditor.callbacks, - editor: cropRotateEditor, ), ), ), - ), - filterEditor: FilterEditorConfigs( - fadeInUpDuration: fadeInDuration, - fadeInUpStaggerDelayDuration: fadeInDelay, - safeArea: const EditorSafeArea(top: false), - style: FilterEditorStyle( - filterListSpacing: 7, - background: colorScheme.backgroundBase, - ), - widgets: FilterEditorWidgets( - slider: ( - editorState, - rebuildStream, - value, - onChanged, - onChangeEnd, - ) => - ReactiveCustomWidget( - builder: (context) { - return const SizedBox.shrink(); + paintEditor: PaintEditorConfigs( + style: PaintEditorStyle( + background: colorScheme.backgroundBase, + initialStrokeWidth: 5, + ), + widgets: PaintEditorWidgets( + appBar: (editor, rebuildStream) { + return ReactiveCustomAppbar( + builder: (context) { + return ImageEditorAppBar( + enableRedo: editor.canRedo, + enableUndo: editor.canUndo, + key: const Key('image_editor_app_bar'), + redo: () => editor.redoAction(), + undo: () => editor.undoAction(), + configs: editor.configs, + done: () => editor.done(), + close: () => editor.close(), + ); + }, + stream: rebuildStream, + ); + }, + colorPicker: + (paintEditor, rebuildStream, currentColor, setColor) => + null, + bottomBar: (editorState, rebuildStream) { + return ReactiveCustomWidget( + builder: (context) { + return ImageEditorPaintBar( + configs: editorState.configs, + callbacks: editorState.callbacks, + editor: editorState, + i18nColor: 'Color', + ); + }, + stream: rebuildStream, + ); }, - stream: rebuildStream, - ), - filterButton: ( - filter, - isSelected, - scaleFactor, - onSelectFilter, - editorImage, - filterKey, - ) { - return ImageEditorFilterBar( - filterModel: filter, - isSelected: isSelected, - onSelectFilter: onSelectFilter, - editorImage: editorImage, - filterKey: filterKey, - ); - }, - appBar: (editor, rebuildStream) { - return ReactiveCustomAppbar( - builder: (context) { - return ImageEditorAppBar( - key: const Key('image_editor_app_bar'), - configs: editor.configs, - done: () => editor.done(), - close: () => editor.close(), - ); - }, - stream: rebuildStream, - ); - }, - ), - ), - tuneEditor: TuneEditorConfigs( - safeArea: const EditorSafeArea(top: false), - style: TuneEditorStyle( - background: colorScheme.backgroundBase, - ), - widgets: TuneEditorWidgets( - appBar: (editor, rebuildStream) { - return ReactiveCustomAppbar( - builder: (context) { - return ImageEditorAppBar( - enableRedo: editor.canRedo, - enableUndo: editor.canUndo, - key: const Key('image_editor_app_bar'), - redo: () => editor.redo(), - undo: () => editor.undo(), - configs: editor.configs, - done: () => editor.done(), - close: () => editor.close(), - ); - }, - stream: rebuildStream, - ); - }, - bottomBar: (editorState, rebuildStream) { - return ReactiveCustomWidget( - builder: (context) { - return ImageEditorTuneBar( - configs: editorState.configs, - callbacks: editorState.callbacks, - editor: editorState, - ); - }, - stream: rebuildStream, - ); - }, - ), - ), - blurEditor: const BlurEditorConfigs( - enabled: false, - ), - emojiEditor: EmojiEditorConfigs( - icons: const EmojiEditorIcons(), - style: EmojiEditorStyle( - backgroundColor: colorScheme.backgroundBase, - emojiViewConfig: const EmojiViewConfig( - gridPadding: EdgeInsets.zero, - horizontalSpacing: 0, - verticalSpacing: 0, - recentsLimit: 40, - loadingIndicator: Center(child: CircularProgressIndicator()), - replaceEmojiOnLimitExceed: false, - ), - bottomActionBarConfig: const BottomActionBarConfig( - enabled: false, ), ), + textEditor: TextEditorConfigs( + canToggleTextAlign: true, + customTextStyles: [ + GoogleFonts.inter(), + GoogleFonts.giveYouGlory(), + GoogleFonts.dmSerifText(), + GoogleFonts.comicNeue(), + ], + safeArea: const EditorSafeArea( + bottom: false, + top: false, + ), + style: const TextEditorStyle( + background: Colors.transparent, + textFieldMargin: EdgeInsets.only(top: kToolbarHeight), + ), + widgets: TextEditorWidgets( + appBar: (textEditor, rebuildStream) => null, + colorPicker: + (textEditor, rebuildStream, currentColor, setColor) => null, + bottomBar: (editorState, rebuildStream) { + return ReactiveCustomWidget( + builder: (context) { + return ImageEditorTextBar( + configs: editorState.configs, + callbacks: editorState.callbacks, + editor: editorState, + ); + }, + stream: rebuildStream, + ); + }, + ), + ), + cropRotateEditor: CropRotateEditorConfigs( + safeArea: const EditorSafeArea( + bottom: false, + top: false, + ), + style: CropRotateEditorStyle( + background: colorScheme.backgroundBase, + cropCornerColor: + Theme.of(context).colorScheme.imageEditorPrimaryColor, + ), + widgets: CropRotateEditorWidgets( + appBar: (editor, rebuildStream) { + return ReactiveCustomAppbar( + builder: (context) { + return ImageEditorAppBar( + key: const Key('image_editor_app_bar'), + configs: editor.configs, + done: () => editor.done(), + close: () => editor.close(), + enableRedo: editor.canRedo, + enableUndo: editor.canUndo, + redo: () => editor.redoAction(), + undo: () => editor.undoAction(), + ); + }, + stream: rebuildStream, + ); + }, + bottomBar: (cropRotateEditor, rebuildStream) => + ReactiveCustomWidget( + stream: rebuildStream, + builder: (_) => ImageEditorCropRotateBar( + configs: cropRotateEditor.configs, + callbacks: cropRotateEditor.callbacks, + editor: cropRotateEditor, + ), + ), + ), + ), + filterEditor: FilterEditorConfigs( + fadeInUpDuration: fadeInDuration, + fadeInUpStaggerDelayDuration: fadeInDelay, + safeArea: const EditorSafeArea(top: false), + style: FilterEditorStyle( + filterListSpacing: 7, + background: colorScheme.backgroundBase, + ), + widgets: FilterEditorWidgets( + slider: ( + editorState, + rebuildStream, + value, + onChanged, + onChangeEnd, + ) => + ReactiveCustomWidget( + builder: (context) { + return const SizedBox.shrink(); + }, + stream: rebuildStream, + ), + filterButton: ( + filter, + isSelected, + scaleFactor, + onSelectFilter, + editorImage, + filterKey, + ) { + return ImageEditorFilterBar( + filterModel: filter, + isSelected: isSelected, + onSelectFilter: onSelectFilter, + editorImage: editorImage, + filterKey: filterKey, + ); + }, + appBar: (editor, rebuildStream) { + return ReactiveCustomAppbar( + builder: (context) { + return ImageEditorAppBar( + key: const Key('image_editor_app_bar'), + configs: editor.configs, + done: () => editor.done(), + close: () => editor.close(), + ); + }, + stream: rebuildStream, + ); + }, + ), + ), + tuneEditor: TuneEditorConfigs( + safeArea: const EditorSafeArea(top: false), + style: TuneEditorStyle( + background: colorScheme.backgroundBase, + ), + widgets: TuneEditorWidgets( + appBar: (editor, rebuildStream) { + return ReactiveCustomAppbar( + builder: (context) { + return ImageEditorAppBar( + enableRedo: editor.canRedo, + enableUndo: editor.canUndo, + key: const Key('image_editor_app_bar'), + redo: () => editor.redo(), + undo: () => editor.undo(), + configs: editor.configs, + done: () => editor.done(), + close: () => editor.close(), + ); + }, + stream: rebuildStream, + ); + }, + bottomBar: (editorState, rebuildStream) { + return ReactiveCustomWidget( + builder: (context) { + return ImageEditorTuneBar( + configs: editorState.configs, + callbacks: editorState.callbacks, + editor: editorState, + ); + }, + stream: rebuildStream, + ); + }, + ), + ), + blurEditor: const BlurEditorConfigs( + enabled: false, + ), + emojiEditor: EmojiEditorConfigs( + icons: const EmojiEditorIcons(), + style: EmojiEditorStyle( + backgroundColor: colorScheme.backgroundBase, + emojiViewConfig: const EmojiViewConfig( + gridPadding: EdgeInsets.zero, + horizontalSpacing: 0, + verticalSpacing: 0, + recentsLimit: 40, + loadingIndicator: Center(child: CircularProgressIndicator()), + replaceEmojiOnLimitExceed: false, + ), + bottomActionBarConfig: const BottomActionBarConfig( + enabled: false, + ), + ), + ), + stickerEditor: const StickerEditorConfigs(enabled: false), ), - stickerEditor: const StickerEditorConfigs(enabled: false), ), ), ); From e9da23aff986132e56c3407d8cef6382fc90b409 Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Thu, 24 Jul 2025 16:00:36 +0530 Subject: [PATCH 11/28] Refactor: remove unused safe area configurations from image editor --- .../editor/image_editor/image_editor_page_new.dart | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart index 785e13687a..7a5ea825eb 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart @@ -34,7 +34,6 @@ import "package:photos/ui/tools/editor/image_editor/image_editor_tune_bar.dart"; import "package:photos/ui/viewer/file/detail_page.dart"; import "package:photos/utils/dialog_util.dart"; import "package:photos/utils/navigation_util.dart"; -import "package:pro_image_editor/models/editor_configs/utils/editor_safe_area.dart"; import 'package:pro_image_editor/pro_image_editor.dart'; class NewImageEditor extends StatefulWidget { @@ -346,10 +345,6 @@ class _NewImageEditorState extends State { GoogleFonts.dmSerifText(), GoogleFonts.comicNeue(), ], - safeArea: const EditorSafeArea( - bottom: false, - top: false, - ), style: const TextEditorStyle( background: Colors.transparent, textFieldMargin: EdgeInsets.only(top: kToolbarHeight), @@ -373,10 +368,6 @@ class _NewImageEditorState extends State { ), ), cropRotateEditor: CropRotateEditorConfigs( - safeArea: const EditorSafeArea( - bottom: false, - top: false, - ), style: CropRotateEditorStyle( background: colorScheme.backgroundBase, cropCornerColor: @@ -414,7 +405,6 @@ class _NewImageEditorState extends State { filterEditor: FilterEditorConfigs( fadeInUpDuration: fadeInDuration, fadeInUpStaggerDelayDuration: fadeInDelay, - safeArea: const EditorSafeArea(top: false), style: FilterEditorStyle( filterListSpacing: 7, background: colorScheme.backgroundBase, @@ -465,7 +455,6 @@ class _NewImageEditorState extends State { ), ), tuneEditor: TuneEditorConfigs( - safeArea: const EditorSafeArea(top: false), style: TuneEditorStyle( background: colorScheme.backgroundBase, ), From b89a9a7307687d0ed542639dce6e25e9fba01dbc Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Thu, 24 Jul 2025 17:28:02 +0530 Subject: [PATCH 12/28] Fix options for background selections --- .../image_editor/image_editor_text_bar.dart | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_text_bar.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_text_bar.dart index db0d16a6e3..3115aa3933 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_text_bar.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_text_bar.dart @@ -206,32 +206,46 @@ class _BackgroundPickerWidget extends StatelessWidget { final backgroundStyles = { LayerBackgroundMode.background: { 'text': 'Aa', - 'backgroundColor': isLightMode ? colorScheme.fillFaint : Colors.white, + 'selectedBackgroundColor': + isLightMode ? colorScheme.fillFaint : Colors.white, + 'backgroundColor': colorScheme.backgroundElevated2, 'border': null, 'textColor': Colors.white, - 'innerBackgroundColor': Colors.black, + 'selectedInnerBackgroundColor': Colors.black, + 'innerBackgroundColor': Colors.transparent, }, LayerBackgroundMode.backgroundAndColor: { 'text': 'Aa', - 'backgroundColor': isLightMode ? colorScheme.fillFaint : Colors.white, + 'selectedBackgroundColor': + isLightMode ? colorScheme.fillFaint : Colors.white, + 'backgroundColor': colorScheme.backgroundElevated2, 'border': null, 'textColor': Colors.black, + 'selectedInnerBackgroundColor': Colors.transparent, 'innerBackgroundColor': Colors.transparent, }, LayerBackgroundMode.backgroundAndColorWithOpacity: { 'text': 'Aa', - 'backgroundColor': isLightMode ? colorScheme.fillFaint : Colors.white, + 'selectedBackgroundColor': + isLightMode ? colorScheme.fillFaint : Colors.white, + 'backgroundColor': colorScheme.backgroundElevated2, 'border': null, 'textColor': Colors.black, - 'innerBackgroundColor': Colors.black.withOpacity(0.11), + 'selectedInnerBackgroundColor': Colors.black.withOpacity(0.11), + 'innerBackgroundColor': isLightMode + ? Colors.black.withOpacity(0.11) + : Colors.white.withOpacity(0.11), }, LayerBackgroundMode.onlyColor: { 'text': 'Aa', - 'backgroundColor': isLightMode ? colorScheme.fillFaint : Colors.black, + 'selectedBackgroundColor': + isLightMode ? colorScheme.fillFaint : Colors.black, + 'backgroundColor': colorScheme.backgroundElevated2, 'border': isLightMode ? null : Border.all(color: Colors.white, width: 2), 'textColor': Colors.black, - 'innerBackgroundColor': Colors.white, + 'selectedInnerBackgroundColor': Colors.white, + 'innerBackgroundColor': Colors.white.withOpacity(0.6), }, }; @@ -256,8 +270,8 @@ class _BackgroundPickerWidget extends StatelessWidget { child: Container( decoration: BoxDecoration( color: isSelected - ? style['backgroundColor'] as Color - : colorScheme.backgroundElevated2, + ? style['selectedBackgroundColor'] as Color + : style['backgroundColor'] as Color, borderRadius: BorderRadius.circular(25), border: isSelected ? style['border'] as Border? : null, ), @@ -270,8 +284,8 @@ class _BackgroundPickerWidget extends StatelessWidget { width: 22, decoration: ShapeDecoration( color: isSelected - ? style['innerBackgroundColor'] as Color - : colorScheme.backgroundElevated2, + ? style['selectedInnerBackgroundColor'] as Color + : style['innerBackgroundColor'] as Color, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(4), ), From 21d59fa0a32216f2706b09aeba5376f07e35535d Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Thu, 24 Jul 2025 17:30:14 +0530 Subject: [PATCH 13/28] Fix: adjust padding and spacing in crop rotate bar UI --- .../image_editor_crop_rotate.dart | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_crop_rotate.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_crop_rotate.dart index e7e5c97c66..7d0b62f8e2 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_crop_rotate.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_crop_rotate.dart @@ -99,6 +99,7 @@ class _ImageEditorCropRotateBarState extends State Widget _buildFunctions(BoxConstraints constraints) { return BottomAppBar( color: getEnteColorScheme(context).backgroundBase, + padding: EdgeInsets.zero, height: editorBottomBarHeight, child: Align( alignment: Alignment.bottomCenter, @@ -111,15 +112,15 @@ class _ImageEditorCropRotateBarState extends State mainAxisAlignment: MainAxisAlignment.center, children: [ CircularIconButton( - svgPath: "assets/image-editor/image-editor-crop-rotate.svg", + svgPath: "assets/image-editor/image-editor-crop-rotate.svg", label: "Rotate", onTap: () { widget.editor.rotate(); }, ), - const SizedBox(width: 12), + const SizedBox(width: 6), CircularIconButton( - svgPath: "assets/image-editor/image-editor-flip.svg", + svgPath: "assets/image-editor/image-editor-flip.svg", label: "Flip", onTap: () { widget.editor.flip(); @@ -127,9 +128,8 @@ class _ImageEditorCropRotateBarState extends State ), ], ), - const SizedBox(height: 20), SizedBox( - height: 48, + height: 40, child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: CropAspectRatioType.values.length, @@ -190,17 +190,14 @@ class CropAspectChip extends StatelessWidget { : colorScheme.backgroundElevated2, borderRadius: BorderRadius.circular(25), ), - padding: const EdgeInsets.symmetric( - horizontal: 14, - vertical: 10, - ), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ if (svg != null) ...[ SvgPicture.asset( svg!, - height: 40, + height: 32, colorFilter: ColorFilter.mode( isSelected ? colorScheme.backdropBase : colorScheme.tabIcon, BlendMode.srcIn, @@ -217,6 +214,7 @@ class CropAspectChip extends StatelessWidget { : colorScheme.tabIcon, ), ), + const SizedBox(width: 4), ], ), ), From 7a35748e30a473d1ba3443d08b424c5fe8958511 Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Thu, 24 Jul 2025 17:33:27 +0530 Subject: [PATCH 14/28] Minor fix --- .../ui/tools/editor/image_editor/image_editor_app_bar.dart | 5 +++-- .../ui/tools/editor/image_editor/image_editor_page_new.dart | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_app_bar.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_app_bar.dart index 96eeb220a9..85f2ab2d65 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_app_bar.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_app_bar.dart @@ -87,8 +87,9 @@ class ImageEditorAppBar extends StatelessWidget implements PreferredSizeWidget { child: Text( isMainEditor ? 'Save Copy' : 'Done', style: getEnteTextTheme(context).body.copyWith( - color: - Theme.of(context).colorScheme.imageEditorPrimaryColor, + color: enableUndo + ? Theme.of(context).colorScheme.imageEditorPrimaryColor + : colorScheme.textMuted, ), ), ), diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart index 7a5ea825eb..13ff58e07a 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart @@ -338,6 +338,7 @@ class _NewImageEditorState extends State { ), ), textEditor: TextEditorConfigs( + canToggleBackgroundMode: true, canToggleTextAlign: true, customTextStyles: [ GoogleFonts.inter(), From aede55eb72fb78363618c568bbdb43238640f592 Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Fri, 25 Jul 2025 09:50:45 +0530 Subject: [PATCH 15/28] Fix: adjust spacing in the image editor app bar --- .../image_editor/image_editor_app_bar.dart | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_app_bar.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_app_bar.dart index 85f2ab2d65..03e84cf75d 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_app_bar.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_app_bar.dart @@ -64,7 +64,7 @@ class ImageEditorAppBar extends StatelessWidget implements PreferredSizeWidget { ), ), ), - const SizedBox(width: 16), + const SizedBox(width: 12), IconButton( tooltip: 'Redo', onPressed: () { @@ -80,17 +80,27 @@ class ImageEditorAppBar extends StatelessWidget implements PreferredSizeWidget { ), ], ), - TextButton( - onPressed: () { - done(); - }, - child: Text( - isMainEditor ? 'Save Copy' : 'Done', - style: getEnteTextTheme(context).body.copyWith( - color: enableUndo - ? Theme.of(context).colorScheme.imageEditorPrimaryColor - : colorScheme.textMuted, - ), + AnimatedSwitcher( + duration: const Duration(milliseconds: 250), + transitionBuilder: (child, animation) => + FadeTransition(opacity: animation, child: child), + child: TextButton( + key: ValueKey(isMainEditor ? 'save_copy' : 'done'), + onPressed: done, + child: Text( + isMainEditor ? 'Save Copy' : 'Done', + style: getEnteTextTheme(context).body.copyWith( + color: isMainEditor + ? (enableUndo + ? Theme.of(context) + .colorScheme + .imageEditorPrimaryColor + : colorScheme.textMuted) + : Theme.of(context) + .colorScheme + .imageEditorPrimaryColor, + ), + ), ), ), ], From ed7cc5f8c19a8b51c890b5a4f292d3381f6a2e4d Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Fri, 25 Jul 2025 09:51:08 +0530 Subject: [PATCH 16/28] Add SVG delete icon and update image editor UI to use it --- .../image-editor/image-editor-delete.svg | 6 +++ .../image_editor/image_editor_page_new.dart | 53 ++++++++++++++++--- 2 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 mobile/apps/photos/assets/image-editor/image-editor-delete.svg diff --git a/mobile/apps/photos/assets/image-editor/image-editor-delete.svg b/mobile/apps/photos/assets/image-editor/image-editor-delete.svg new file mode 100644 index 0000000000..392fc4cb52 --- /dev/null +++ b/mobile/apps/photos/assets/image-editor/image-editor-delete.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart index 13ff58e07a..771ac502a9 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart @@ -6,6 +6,7 @@ import 'dart:ui' as ui show Image; import 'package:flutter/material.dart'; import "package:flutter_image_compress/flutter_image_compress.dart"; +import "package:flutter_svg/svg.dart"; import "package:google_fonts/google_fonts.dart"; import "package:logging/logging.dart"; import 'package:path/path.dart' as path; @@ -202,6 +203,11 @@ class _NewImageEditorState extends State { ), ), configs: ProImageEditorConfigs( + imageGeneration: const ImageGenerationConfigs( + jpegQuality: 100, + generateInsideSeparateThread: true, + pngLevel: 0, + ), layerInteraction: const LayerInteractionConfigs( hideToolbarOnInteraction: false, ), @@ -241,16 +247,20 @@ class _NewImageEditorState extends State { margin: const EdgeInsets.only(bottom: 24), decoration: BoxDecoration( color: isHovered - ? const Color.fromARGB(255, 255, 197, 197) - : const Color.fromARGB(255, 255, 255, 255), + ? colorScheme.warning400.withOpacity(0.8) + : Colors.white, shape: BoxShape.circle, ), padding: const EdgeInsets.all(12), - child: const Center( - child: Icon( - Icons.delete_forever_outlined, - size: 28, - color: Color(0xFFF44336), + child: Center( + child: SvgPicture.asset( + "assets/image-editor/image-editor-delete.svg", + colorFilter: ColorFilter.mode( + isHovered + ? Colors.white + : colorScheme.warning400.withOpacity(0.8), + BlendMode.srcIn, + ), ), ), ); @@ -351,7 +361,34 @@ class _NewImageEditorState extends State { textFieldMargin: EdgeInsets.only(top: kToolbarHeight), ), widgets: TextEditorWidgets( - appBar: (textEditor, rebuildStream) => null, + appBar: (textEditor, rebuildStream) => ReactiveCustomAppbar( + builder: (context) { + return ImageEditorAppBar( + key: const Key('image_editor_app_bar'), + configs: textEditor.configs, + done: () => textEditor.done(), + close: () => textEditor.close(), + ); + }, + stream: rebuildStream, + ), + bodyItems: (editor, rebuildStream) { + return [ + ReactiveCustomWidget( + builder: (context) { + return Positioned.fill( + child: GestureDetector( + onTap: () {}, + child: Container( + color: Colors.transparent, + ), + ), + ); + }, + stream: rebuildStream, + ), + ]; + }, colorPicker: (textEditor, rebuildStream, currentColor, setColor) => null, bottomBar: (editorState, rebuildStream) { From dd0cfc4656606baee345da7d1d0211839defbd60 Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Tue, 29 Jul 2025 08:48:17 +0530 Subject: [PATCH 17/28] Fix: update padding in crop rotate bar and rename paint editor state --- .../image_editor_crop_rotate.dart | 5 +- .../image_editor_main_bottom_bar.dart | 2 +- .../image_editor/image_editor_page_new.dart | 492 +++++++++--------- .../image_editor/image_editor_paint_bar.dart | 2 +- 4 files changed, 255 insertions(+), 246 deletions(-) diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_crop_rotate.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_crop_rotate.dart index 7d0b62f8e2..a222ed92e4 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_crop_rotate.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_crop_rotate.dart @@ -137,7 +137,10 @@ class _ImageEditorCropRotateBarState extends State final aspectRatio = CropAspectRatioType.values[index]; final isSelected = selectedAspectRatio == aspectRatio; return Padding( - padding: const EdgeInsets.only(right: 12.0), + padding: const EdgeInsets.only( + left: 6.0, + right: 6.0, + ), child: CropAspectChip( label: aspectRatio.label, svg: aspectRatio.svg, diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_main_bottom_bar.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_main_bottom_bar.dart index 1d5a9ff789..de578abfec 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_main_bottom_bar.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_main_bottom_bar.dart @@ -121,7 +121,7 @@ class ImageEditorMainBottomBarState extends State svgPath: "assets/image-editor/image-editor-paint.svg", label: "Draw", onTap: () { - widget.editor.openPaintEditor(); + widget.editor.openPaintingEditor(); }, ), CircularIconButton( diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart index 771ac502a9..f72f9f386f 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart @@ -35,6 +35,7 @@ import "package:photos/ui/tools/editor/image_editor/image_editor_tune_bar.dart"; import "package:photos/ui/viewer/file/detail_page.dart"; import "package:photos/utils/dialog_util.dart"; import "package:photos/utils/navigation_util.dart"; +import "package:pro_image_editor/models/editor_configs/main_editor_configs.dart"; import 'package:pro_image_editor/pro_image_editor.dart'; class NewImageEditor extends StatefulWidget { @@ -177,6 +178,7 @@ class _NewImageEditorState extends State { final colorScheme = getEnteColorScheme(context); final textTheme = getEnteTextTheme(context); return Scaffold( + resizeToAvoidBottomInset: false, backgroundColor: colorScheme.backgroundBase, body: PopScope( canPop: false, @@ -203,12 +205,38 @@ class _NewImageEditorState extends State { ), ), configs: ProImageEditorConfigs( - imageGeneration: const ImageGenerationConfigs( + imageEditorTheme: ImageEditorTheme( + appBarBackgroundColor: colorScheme.backgroundBase, + background: colorScheme.backgroundBase, + bottomBarBackgroundColor: colorScheme.backgroundBase, + filterEditor: FilterEditorTheme( + background: colorScheme.backgroundBase, + ), + paintingEditor: PaintingEditorTheme( + background: colorScheme.backgroundBase, + ), + textEditor: const TextEditorTheme( + background: Colors.transparent, + textFieldMargin: EdgeInsets.only(top: kToolbarHeight), + ), + cropRotateEditor: CropRotateEditorTheme( + background: colorScheme.backgroundBase, + cropCornerColor: + Theme.of(context).colorScheme.imageEditorPrimaryColor, + ), + tuneEditor: TuneEditorTheme( + background: colorScheme.backgroundBase, + ), + emojiEditor: EmojiEditorTheme( + backgroundColor: colorScheme.backgroundBase, + ), + ), + imageGenerationConfigs: const ImageGenerationConfigs( jpegQuality: 100, generateInsideSeparateThread: true, pngLevel: 0, ), - layerInteraction: const LayerInteractionConfigs( + layerInteraction: const LayerInteraction( hideToolbarOnInteraction: false, ), theme: ThemeData( @@ -222,132 +250,9 @@ class _NewImageEditorState extends State { ), brightness: isLightMode ? Brightness.light : Brightness.dark, ), - mainEditor: MainEditorConfigs( - enableCloseButton: false, - style: MainEditorStyle( - appBarBackground: colorScheme.backgroundBase, - background: colorScheme.backgroundBase, - bottomBarBackground: colorScheme.backgroundBase, - ), - widgets: MainEditorWidgets( - removeLayerArea: (removeAreaKey, editor, rebuildStream) { - return Align( - alignment: Alignment.bottomCenter, - child: StreamBuilder( - stream: rebuildStream, - builder: (_, __) { - final isHovered = - editor.layerInteractionManager.hoverRemoveBtn; - - return AnimatedContainer( - key: removeAreaKey, - duration: const Duration(milliseconds: 150), - height: 56, - width: 56, - margin: const EdgeInsets.only(bottom: 24), - decoration: BoxDecoration( - color: isHovered - ? colorScheme.warning400.withOpacity(0.8) - : Colors.white, - shape: BoxShape.circle, - ), - padding: const EdgeInsets.all(12), - child: Center( - child: SvgPicture.asset( - "assets/image-editor/image-editor-delete.svg", - colorFilter: ColorFilter.mode( - isHovered - ? Colors.white - : colorScheme.warning400.withOpacity(0.8), - BlendMode.srcIn, - ), - ), - ), - ); - }, - ), - ); - }, - appBar: (editor, rebuildStream) { - return ReactiveCustomAppbar( - builder: (context) { - return ImageEditorAppBar( - enableRedo: editor.canRedo, - enableUndo: editor.canUndo, - key: const Key('image_editor_app_bar'), - redo: () => editor.redoAction(), - undo: () => editor.undoAction(), - configs: editor.configs, - done: () async { - final Uint8List bytes = await editorKey.currentState! - .captureEditorImage(); - await saveImage(bytes); - }, - close: () { - _showExitConfirmationDialog(context); - }, - isMainEditor: true, - ); - }, - stream: rebuildStream, - ); - }, - bottomBar: (editor, rebuildStream, key) => ReactiveCustomWidget( - key: key, - builder: (context) { - return ImageEditorMainBottomBar( - key: _mainEditorBarKey, - editor: editor, - configs: editor.configs, - callbacks: editor.callbacks, - ); - }, - stream: rebuildStream, - ), - ), - ), - paintEditor: PaintEditorConfigs( - style: PaintEditorStyle( - background: colorScheme.backgroundBase, - initialStrokeWidth: 5, - ), - widgets: PaintEditorWidgets( - appBar: (editor, rebuildStream) { - return ReactiveCustomAppbar( - builder: (context) { - return ImageEditorAppBar( - enableRedo: editor.canRedo, - enableUndo: editor.canUndo, - key: const Key('image_editor_app_bar'), - redo: () => editor.redoAction(), - undo: () => editor.undoAction(), - configs: editor.configs, - done: () => editor.done(), - close: () => editor.close(), - ); - }, - stream: rebuildStream, - ); - }, - colorPicker: - (paintEditor, rebuildStream, currentColor, setColor) => - null, - bottomBar: (editorState, rebuildStream) { - return ReactiveCustomWidget( - builder: (context) { - return ImageEditorPaintBar( - configs: editorState.configs, - callbacks: editorState.callbacks, - editor: editorState, - i18nColor: 'Color', - ); - }, - stream: rebuildStream, - ); - }, - ), - ), - textEditor: TextEditorConfigs( + mainEditorConfigs: const MainEditorConfigs(), + paintEditorConfigs: const PaintEditorConfigs(enabled: true), + textEditorConfigs: TextEditorConfigs( canToggleBackgroundMode: true, canToggleTextAlign: true, customTextStyles: [ @@ -356,98 +261,9 @@ class _NewImageEditorState extends State { GoogleFonts.dmSerifText(), GoogleFonts.comicNeue(), ], - style: const TextEditorStyle( - background: Colors.transparent, - textFieldMargin: EdgeInsets.only(top: kToolbarHeight), - ), - widgets: TextEditorWidgets( - appBar: (textEditor, rebuildStream) => ReactiveCustomAppbar( - builder: (context) { - return ImageEditorAppBar( - key: const Key('image_editor_app_bar'), - configs: textEditor.configs, - done: () => textEditor.done(), - close: () => textEditor.close(), - ); - }, - stream: rebuildStream, - ), - bodyItems: (editor, rebuildStream) { - return [ - ReactiveCustomWidget( - builder: (context) { - return Positioned.fill( - child: GestureDetector( - onTap: () {}, - child: Container( - color: Colors.transparent, - ), - ), - ); - }, - stream: rebuildStream, - ), - ]; - }, - colorPicker: - (textEditor, rebuildStream, currentColor, setColor) => null, - bottomBar: (editorState, rebuildStream) { - return ReactiveCustomWidget( - builder: (context) { - return ImageEditorTextBar( - configs: editorState.configs, - callbacks: editorState.callbacks, - editor: editorState, - ); - }, - stream: rebuildStream, - ); - }, - ), ), - cropRotateEditor: CropRotateEditorConfigs( - style: CropRotateEditorStyle( - background: colorScheme.backgroundBase, - cropCornerColor: - Theme.of(context).colorScheme.imageEditorPrimaryColor, - ), - widgets: CropRotateEditorWidgets( - appBar: (editor, rebuildStream) { - return ReactiveCustomAppbar( - builder: (context) { - return ImageEditorAppBar( - key: const Key('image_editor_app_bar'), - configs: editor.configs, - done: () => editor.done(), - close: () => editor.close(), - enableRedo: editor.canRedo, - enableUndo: editor.canUndo, - redo: () => editor.redoAction(), - undo: () => editor.undoAction(), - ); - }, - stream: rebuildStream, - ); - }, - bottomBar: (cropRotateEditor, rebuildStream) => - ReactiveCustomWidget( - stream: rebuildStream, - builder: (_) => ImageEditorCropRotateBar( - configs: cropRotateEditor.configs, - callbacks: cropRotateEditor.callbacks, - editor: cropRotateEditor, - ), - ), - ), - ), - filterEditor: FilterEditorConfigs( - fadeInUpDuration: fadeInDuration, - fadeInUpStaggerDelayDuration: fadeInDelay, - style: FilterEditorStyle( - filterListSpacing: 7, - background: colorScheme.backgroundBase, - ), - widgets: FilterEditorWidgets( + customWidgets: ImageEditorCustomWidgets( + filterEditor: CustomWidgetsFilterEditor( slider: ( editorState, rebuildStream, @@ -491,12 +307,7 @@ class _NewImageEditorState extends State { ); }, ), - ), - tuneEditor: TuneEditorConfigs( - style: TuneEditorStyle( - background: colorScheme.backgroundBase, - ), - widgets: TuneEditorWidgets( + tuneEditor: CustomWidgetsTuneEditor( appBar: (editor, rebuildStream) { return ReactiveCustomAppbar( builder: (context) { @@ -527,28 +338,223 @@ class _NewImageEditorState extends State { ); }, ), - ), - blurEditor: const BlurEditorConfigs( - enabled: false, - ), - emojiEditor: EmojiEditorConfigs( - icons: const EmojiEditorIcons(), - style: EmojiEditorStyle( - backgroundColor: colorScheme.backgroundBase, - emojiViewConfig: const EmojiViewConfig( - gridPadding: EdgeInsets.zero, - horizontalSpacing: 0, - verticalSpacing: 0, - recentsLimit: 40, - loadingIndicator: Center(child: CircularProgressIndicator()), - replaceEmojiOnLimitExceed: false, + mainEditor: CustomWidgetsMainEditor( + removeLayerArea: (key, rebuildStream) { + return ReactiveCustomWidget( + key: key, + builder: (context) { + return Align( + alignment: Alignment.bottomCenter, + child: StreamBuilder( + stream: rebuildStream, + builder: (context, snapshot) { + final isHovered = editorKey.currentState + !.layerInteractionManager.hoverRemoveBtn; + + return AnimatedContainer( + key: key, + duration: const Duration(milliseconds: 150), + height: 56, + width: 56, + margin: const EdgeInsets.only(bottom: 24), + decoration: BoxDecoration( + color: isHovered + ? colorScheme.warning400.withOpacity(0.8) + : Colors.white, + shape: BoxShape.circle, + ), + padding: const EdgeInsets.all(12), + child: Center( + child: SvgPicture.asset( + "assets/image-editor/image-editor-delete.svg", + colorFilter: ColorFilter.mode( + isHovered + ? Colors.white + : colorScheme.warning400 + .withOpacity(0.8), + BlendMode.srcIn, + ), + ), + ), + ); + }, + ), + ); + }, + stream: rebuildStream, + ); + }, + appBar: (editor, rebuildStream) { + return ReactiveCustomAppbar( + builder: (context) { + return ImageEditorAppBar( + enableRedo: editor.canRedo, + enableUndo: editor.canUndo, + key: const Key('image_editor_app_bar'), + redo: () => editor.redoAction(), + undo: () => editor.undoAction(), + configs: editor.configs, + done: () async { + final Uint8List bytes = await editorKey.currentState! + .captureEditorImage(); + await saveImage(bytes); + }, + close: () { + _showExitConfirmationDialog(context); + }, + isMainEditor: true, + ); + }, + stream: rebuildStream, + ); + }, + bottomBar: (editor, rebuildStream, key) => ReactiveCustomWidget( + key: key, + builder: (context) { + return ImageEditorMainBottomBar( + key: _mainEditorBarKey, + editor: editor, + configs: editor.configs, + callbacks: editor.callbacks, + ); + }, + stream: rebuildStream, ), - bottomActionBarConfig: const BottomActionBarConfig( - enabled: false, + ), + paintEditor: CustomWidgetsPaintEditor( + appBar: (editor, rebuildStream) { + return ReactiveCustomAppbar( + builder: (context) { + return ImageEditorAppBar( + enableRedo: editor.canRedo, + enableUndo: editor.canUndo, + key: const Key('image_editor_app_bar'), + redo: () => editor.redoAction(), + undo: () => editor.undoAction(), + configs: editor.configs, + done: () => editor.done(), + close: () => editor.close(), + ); + }, + stream: rebuildStream, + ); + }, + colorPicker: + (paintEditor, rebuildStream, currentColor, setColor) => + null, + bottomBar: (editorState, rebuildStream) { + return ReactiveCustomWidget( + builder: (context) { + return ImageEditorPaintBar( + configs: editorState.configs, + callbacks: editorState.callbacks, + editor: editorState, + i18nColor: 'Color', + ); + }, + stream: rebuildStream, + ); + }, + ), + textEditor: CustomWidgetsTextEditor( + appBar: (textEditor, rebuildStream) => ReactiveCustomAppbar( + builder: (context) { + return ImageEditorAppBar( + key: const Key('image_editor_app_bar'), + configs: textEditor.configs, + done: () => textEditor.done(), + close: () => textEditor.close(), + ); + }, + stream: rebuildStream, + ), + bodyItems: (editor, rebuildStream) { + return [ + ReactiveCustomWidget( + builder: (context) { + return Positioned.fill( + child: GestureDetector( + onTap: () {}, + child: Container( + color: Colors.transparent, + ), + ), + ); + }, + stream: rebuildStream, + ), + ]; + }, + colorPicker: + (textEditor, rebuildStream, currentColor, setColor) => null, + bottomBar: (editorState, rebuildStream) { + return ReactiveCustomWidget( + builder: (context) { + return ImageEditorTextBar( + configs: editorState.configs, + callbacks: editorState.callbacks, + editor: editorState, + ); + }, + stream: rebuildStream, + ); + }, + ), + cropRotateEditor: CustomWidgetsCropRotateEditor( + appBar: (editor, rebuildStream) { + return ReactiveCustomAppbar( + builder: (context) { + return ImageEditorAppBar( + key: const Key('image_editor_app_bar'), + configs: editor.configs, + done: () => editor.done(), + close: () => editor.close(), + enableRedo: editor.canRedo, + enableUndo: editor.canUndo, + redo: () => editor.redoAction(), + undo: () => editor.undoAction(), + ); + }, + stream: rebuildStream, + ); + }, + bottomBar: (cropRotateEditor, rebuildStream) => + ReactiveCustomWidget( + stream: rebuildStream, + builder: (_) => ImageEditorCropRotateBar( + configs: cropRotateEditor.configs, + callbacks: cropRotateEditor.callbacks, + editor: cropRotateEditor, + ), ), ), ), - stickerEditor: const StickerEditorConfigs(enabled: false), + cropRotateEditorConfigs: const CropRotateEditorConfigs( + canChangeAspectRatio: true, + canFlip: true, + canRotate: true, + canReset: true, + enabled: true, + ), + filterEditorConfigs: const FilterEditorConfigs( + enabled: true, + fadeInUpDuration: fadeInDuration, + fadeInUpStaggerDelayDuration: fadeInDelay, + ), + tuneEditorConfigs: const TuneEditorConfigs(enabled: true), + blurEditorConfigs: const BlurEditorConfigs( + enabled: false, + ), + emojiEditorConfigs: const EmojiEditorConfigs( + enabled: true, + checkPlatformCompatibility: true, + ), + stickerEditorConfigs: StickerEditorConfigs( + enabled: false, + buildStickers: (setLayer, scrollController) { + return const SizedBox.shrink(); + }, + ), ), ), ), diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_paint_bar.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_paint_bar.dart index 48f7b2a040..0e4d1dd44f 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_paint_bar.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_paint_bar.dart @@ -18,7 +18,7 @@ class ImageEditorPaintBar extends StatefulWidget with SimpleConfigsAccess { required this.i18nColor, }); - final PaintEditorState editor; + final PaintingEditorState editor; @override final ProImageEditorConfigs configs; From 064da1be0831604904be74873aa076f861e56332 Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Tue, 29 Jul 2025 08:48:31 +0530 Subject: [PATCH 18/28] fix: downgrade pro_image_editor dependency from 7.2.0 to 6.0.0 for compatibility --- mobile/apps/photos/pubspec.lock | 339 ++++++++++++++++---------------- mobile/apps/photos/pubspec.yaml | 2 +- 2 files changed, 175 insertions(+), 166 deletions(-) diff --git a/mobile/apps/photos/pubspec.lock b/mobile/apps/photos/pubspec.lock index a4417cd068..f376e463b2 100644 --- a/mobile/apps/photos/pubspec.lock +++ b/mobile/apps/photos/pubspec.lock @@ -5,23 +5,23 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab" + sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 url: "https://pub.dev" source: hosted - version: "76.0.0" + version: "72.0.0" _flutterfire_internals: dependency: transitive description: name: _flutterfire_internals - sha256: "401dd18096f5eaa140404ccbbbf346f83c850e6f27049698a7ee75a3488ddb32" + sha256: ff0a84a2734d9e1089f8aedd5c0af0061b82fb94e95260d943404e0ef2134b11 url: "https://pub.dev" source: hosted - version: "1.3.52" + version: "1.3.59" _macros: dependency: transitive description: dart source: sdk - version: "0.3.3" + version: "0.3.2" adaptive_theme: dependency: "direct main" description: @@ -34,10 +34,10 @@ packages: dependency: transitive description: name: analyzer - sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" + sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 url: "https://pub.dev" source: hosted - version: "6.11.0" + version: "6.7.0" android_intent_plus: dependency: "direct main" description: @@ -114,18 +114,18 @@ packages: dependency: transitive description: name: args - sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.7.0" asn1lib: dependency: transitive description: name: asn1lib - sha256: "4bae5ae63e6d6dd17c4aac8086f3dec26c0236f6a0f03416c6c19d830c367cf5" + sha256: "9a8f69025044eb466b9b60ef3bc3ac99b4dc6c158ae9c56d25eeccf5bc56d024" url: "https://pub.dev" source: hosted - version: "1.5.8" + version: "1.6.5" async: dependency: "direct main" description: @@ -227,10 +227,10 @@ packages: dependency: transitive description: name: built_value - sha256: "28a712df2576b63c6c005c465989a348604960c0958d28be5303ba9baa841ac2" + sha256: "0b1b12a0a549605e5f04476031cd0bc91ead1d7c8e830773a18ee54179b3cb62" url: "https://pub.dev" source: hosted - version: "8.9.3" + version: "8.11.0" cached_network_image: dependency: "direct main" description: @@ -260,7 +260,7 @@ packages: description: path: "." ref: multicast_version - resolved-ref: "1f39cd4d6efa9363e77b2439f0317bae0c92dda1" + resolved-ref: af6378574352884beab6cddec462c7fdfc9a8c35 url: "https://github.com/guyluz11/flutter_cast.git" source: git version: "2.0.9" @@ -289,6 +289,14 @@ packages: url: "https://github.com/ente-io/chewie.git" source: git version: "1.10.0" + cli_config: + dependency: transitive + description: + name: cli_config + sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec + url: "https://pub.dev" + source: hosted + version: "0.2.0" cli_util: dependency: transitive description: @@ -317,10 +325,10 @@ packages: dependency: "direct main" description: name: collection - sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.19.0" + version: "1.18.0" computer: dependency: "direct main" description: @@ -334,10 +342,10 @@ packages: dependency: "direct main" description: name: connectivity_plus - sha256: "04bf81bb0b77de31557b58d052b24b3eee33f09a6e7a8c68a3e247c7df19ec27" + sha256: "051849e2bd7c7b3bc5844ea0d096609ddc3a859890ec3a9ac4a65a2620cc1f99" url: "https://pub.dev" source: hosted - version: "6.1.3" + version: "6.1.4" connectivity_plus_platform_interface: dependency: transitive description: @@ -358,18 +366,18 @@ packages: dependency: transitive description: name: coverage - sha256: e3493833ea012784c740e341952298f1cc77f1f01b1bbc3eb4eecf6984fb7f43 + sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.15.0" cronet_http: dependency: transitive description: name: cronet_http - sha256: "3af9c4d57bf07ef4b307e77b22be4ad61bea19ee6ff65e62184863f3a09f1415" + sha256: df26af0de7c4eff46c53c190b5590e22457bfce6ea679aedb1e6326197f27d6f url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" cross_file: dependency: transitive description: @@ -398,10 +406,10 @@ packages: dependency: transitive description: name: cupertino_http - sha256: "6fcf79586ad872ddcd6004d55c8c2aab3cdf0337436e8f99837b1b6c30665d0c" + sha256: "8fb9e2c36d0732d9d96abd76683406b57e78a2514e27c962e0c603dbe6f2e3f8" url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "2.2.0" cupertino_icons: dependency: "direct main" description: @@ -470,10 +478,10 @@ packages: dependency: transitive description: name: dio_web_adapter - sha256: e485c7a39ff2b384fa1d7e09b4e25f755804de8384358049124830b04fc4f93a + sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" dots_indicator: dependency: "direct main" description: @@ -652,17 +660,18 @@ packages: description: path: "flutter/flutter" ref: android-packaged - resolved-ref: "6d5d27a8c259eda6292f204a27fba53da70af20e" + resolved-ref: e33d4d2f49a25af6bc493e9114350434e6c34ab4 url: "https://github.com/ente-io/ffmpeg-kit" source: git version: "6.0.3" ffmpeg_kit_flutter_platform_interface: dependency: transitive description: - name: ffmpeg_kit_flutter_platform_interface - sha256: addf046ae44e190ad0101b2fde2ad909a3cd08a2a109f6106d2f7048b7abedee - url: "https://pub.dev" - source: hosted + path: "flutter/flutter_platform_interface" + ref: android-packaged + resolved-ref: e33d4d2f49a25af6bc493e9114350434e6c34ab4 + url: "https://github.com/ente-io/ffmpeg-kit" + source: git version: "0.2.1" figma_squircle: dependency: "direct main" @@ -692,50 +701,50 @@ packages: dependency: "direct main" description: name: firebase_core - sha256: "6a4ea0f1d533443c8afc3d809cd36a4e2b8f2e2e711f697974f55bb31d71d1b8" + sha256: "7be63a3f841fc9663342f7f3a011a42aef6a61066943c90b1c434d79d5c995c5" url: "https://pub.dev" source: hosted - version: "3.12.0" + version: "3.15.2" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface - sha256: d7253d255ff10f85cfd2adaba9ac17bae878fa3ba577462451163bd9f1d1f0bf + sha256: "5dbc900677dcbe5873d22ad7fbd64b047750124f1f9b7ebe2a33b9ddccc838eb" url: "https://pub.dev" source: hosted - version: "5.4.0" + version: "6.0.0" firebase_core_web: dependency: transitive description: name: firebase_core_web - sha256: e47f5c2776de018fa19bc9f6f723df136bc75cdb164d64b65305babd715c8e41 + sha256: "0ed0dc292e8f9ac50992e2394e9d336a0275b6ae400d64163fdf0a8a8b556c37" url: "https://pub.dev" source: hosted - version: "2.21.0" + version: "2.24.1" firebase_messaging: dependency: "direct main" description: name: firebase_messaging - sha256: "8755a083a20bac4485e8b46d223f6f2eab34e659a76a75f8cf3cded53bc98a15" + sha256: "60be38574f8b5658e2f22b7e311ff2064bea835c248424a383783464e8e02fcc" url: "https://pub.dev" source: hosted - version: "15.2.3" + version: "15.2.10" firebase_messaging_platform_interface: dependency: transitive description: name: firebase_messaging_platform_interface - sha256: "8cc771079677460de53ad8fcca5bc3074d58c5fc4f9d89b19585e5bfd9c64292" + sha256: "685e1771b3d1f9c8502771ccc9f91485b376ffe16d553533f335b9183ea99754" url: "https://pub.dev" source: hosted - version: "4.6.3" + version: "4.6.10" firebase_messaging_web: dependency: transitive description: name: firebase_messaging_web - sha256: caa73059b0396c97f691683c4cfc3f897c8543801579b7dd4851c431d8e4e091 + sha256: "0d1be17bc89ed3ff5001789c92df678b2e963a51b6fa2bdb467532cc9dbed390" url: "https://pub.dev" source: hosted - version: "3.10.3" + version: "3.10.10" fixnum: dependency: "direct main" description: @@ -934,10 +943,10 @@ packages: dependency: "direct main" description: name: flutter_local_notifications - sha256: b94a50aabbe56ef254f95f3be75640f99120429f0a153b2dc30143cffc9bfdf3 + sha256: "20ca0a9c82ce0c855ac62a2e580ab867f3fbea82680a90647f7953832d0850ae" url: "https://pub.dev" source: hosted - version: "19.2.1" + version: "19.4.0" flutter_local_notifications_linux: dependency: transitive description: @@ -950,18 +959,18 @@ packages: dependency: transitive description: name: flutter_local_notifications_platform_interface - sha256: "2569b973fc9d1f63a37410a9f7c1c552081226c597190cb359ef5d5762d1631c" + sha256: "277d25d960c15674ce78ca97f57d0bae2ee401c844b6ac80fcd972a9c99d09fe" url: "https://pub.dev" source: hosted - version: "9.0.0" + version: "9.1.0" flutter_local_notifications_windows: dependency: transitive description: name: flutter_local_notifications_windows - sha256: f8fc0652a601f83419d623c85723a3e82ad81f92b33eaa9bcc21ea1b94773e6e + sha256: ed46d7ae4ec9d19e4c8fa2badac5fe27ba87a3fe387343ce726f927af074ec98 url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.2" flutter_localizations: dependency: "direct main" description: flutter @@ -1011,10 +1020,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "615a505aef59b151b46bbeef55b36ce2b6ed299d160c51d84281946f0aa0ce0e" + sha256: "1c2b787f99bdca1f3718543f81d38aa1b124817dfeb9fb196201bea85b6134bf" url: "https://pub.dev" source: hosted - version: "2.0.24" + version: "2.0.26" flutter_secure_storage: dependency: "direct main" description: @@ -1027,10 +1036,10 @@ packages: dependency: transitive description: name: flutter_secure_storage_linux - sha256: bf7404619d7ab5c0a1151d7c4e802edad8f33535abfbeff2f9e1fe1274e2d705 + sha256: be76c1d24a97d0b98f8b54bce6b481a380a6590df992d0098f868ad54dc8f688 url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "1.2.3" flutter_secure_storage_macos: dependency: transitive description: @@ -1100,10 +1109,10 @@ packages: dependency: "direct main" description: name: flutter_svg - sha256: c200fd79c918a40c5cd50ea0877fa13f81bdaf6f0a5d3dbcc2a13e3285d6aa1b + sha256: d44bf546b13025ec7353091516f6881f1d4c633993cb109c3916c3a0159dadf1 url: "https://pub.dev" source: hosted - version: "2.0.17" + version: "2.1.0" flutter_test: dependency: "direct dev" description: flutter @@ -1113,10 +1122,10 @@ packages: dependency: "direct main" description: name: flutter_timezone - sha256: bc286cecb0366d88e6c4644e3962ebd1ce1d233abc658eb1e0cd803389f84b64 + sha256: "13b2109ad75651faced4831bf262e32559e44aa549426eab8a597610d385d934" url: "https://pub.dev" source: hosted - version: "4.1.0" + version: "4.1.1" flutter_web_plugins: dependency: transitive description: flutter @@ -1219,10 +1228,10 @@ packages: dependency: transitive description: name: html - sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" + sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" url: "https://pub.dev" source: hosted - version: "0.15.5" + version: "0.15.6" html_unescape: dependency: "direct main" description: @@ -1235,10 +1244,10 @@ packages: dependency: "direct main" description: name: http - sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f + sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" http_client_helper: dependency: transitive description: @@ -1315,10 +1324,10 @@ packages: dependency: "direct main" description: name: in_app_purchase - sha256: "11a40f148eeb4f681a0572003e2b33432e110c90c1bbb4f9ef83b81ec0c4f737" + sha256: "5cddd7f463f3bddb1d37a72b95066e840d5822d66291331d7f8f05ce32c24b6c" url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.3" in_app_purchase_android: dependency: transitive description: @@ -1339,10 +1348,10 @@ packages: dependency: transitive description: name: in_app_purchase_storekit - sha256: "276831961023055b55a2156c1fc043f50f6215ff49fb0f5f2273da6eeb510ecf" + sha256: "02f08d5688fc2776e3e386ff7d3071b7b375ea8222e8e6bd027b15c0708e4045" url: "https://pub.dev" source: hosted - version: "0.3.21" + version: "0.4.0" integration_test: dependency: "direct dev" description: flutter @@ -1376,18 +1385,18 @@ packages: dependency: transitive description: name: iso_base_media - sha256: "0f5594feef1fba98179a2df95d1afbdda952de0c7a2e35e6815093f7c00aaf06" + sha256: "0a94fa4ff4ce7e6894d7afc96c1eee6911c12827f8cf184ca752ce3437a818a1" url: "https://pub.dev" source: hosted - version: "4.5.2" + version: "4.6.1" jni: dependency: transitive description: name: jni - sha256: f377c585ea9c08d48b427dc2e03780af2889d1bb094440da853c6883c1acba4b + sha256: d2c361082d554d4593c3012e26f6b188f902acd291330f13d6427641a92b3da1 url: "https://pub.dev" source: hosted - version: "0.10.1" + version: "0.14.2" js: dependency: "direct overridden" description: @@ -1432,18 +1441,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.7" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "3.0.8" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: @@ -1456,10 +1465,10 @@ packages: dependency: "direct main" description: name: like_button - sha256: "08e6a45b78888412df5d351786c550205ad3a677e72a0820d5bbc0b063c8a463" + sha256: "8b349521182ea6252b7fe1eaaad5932a9f55f94c3e87849376cfc25c78bac53a" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.1.0" lints: dependency: transitive description: @@ -1488,10 +1497,10 @@ packages: dependency: "direct main" description: name: local_auth_android - sha256: "6763aaf8965f21822624cb2fd3c03d2a8b3791037b5efb0fe4b13e110f5afc92" + sha256: "8bba79f4f0f7bc812fce2ca20915d15618c37721246ba6c3ef2aa7a763a90cf2" url: "https://pub.dev" source: hosted - version: "1.0.46" + version: "1.0.47" local_auth_darwin: dependency: transitive description: @@ -1528,10 +1537,10 @@ packages: dependency: transitive description: name: logger - sha256: be4b23575aac7ebf01f225a241eb7f6b5641eeaf43c6a8613510fc2f8cf187d1 + sha256: "2621da01aabaf223f8f961e751f2c943dbb374dc3559b982f200ccedadaa6999" url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.6.0" logging: dependency: "direct main" description: @@ -1552,10 +1561,10 @@ packages: dependency: transitive description: name: macros - sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656" + sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" url: "https://pub.dev" source: hosted - version: "0.1.3-main.0" + version: "0.1.2-main.4" maps_launcher: dependency: "direct main" description: @@ -1594,24 +1603,24 @@ packages: description: path: media_kit ref: HEAD - resolved-ref: "3c4ff28c43d20e68f8d587956b2f525292c25a80" + resolved-ref: c9617f570b8c0ba02857e721997f78c053a856c1 url: "https://github.com/media-kit/media-kit" source: git - version: "1.1.11" + version: "1.2.0" media_kit_libs_android_video: dependency: transitive description: name: media_kit_libs_android_video - sha256: "9dd8012572e4aff47516e55f2597998f0a378e3d588d0fad0ca1f11a53ae090c" + sha256: adff9b571b8ead0867f9f91070f8df39562078c0eb3371d88b9029a2d547d7b7 url: "https://pub.dev" source: hosted - version: "1.3.6" + version: "1.3.7" media_kit_libs_ios_video: dependency: "direct main" description: path: "libs/ios/media_kit_libs_ios_video" ref: HEAD - resolved-ref: "3c4ff28c43d20e68f8d587956b2f525292c25a80" + resolved-ref: c9617f570b8c0ba02857e721997f78c053a856c1 url: "https://github.com/media-kit/media-kit" source: git version: "1.1.4" @@ -1619,10 +1628,10 @@ packages: dependency: transitive description: name: media_kit_libs_linux - sha256: e186891c31daa6bedab4d74dcdb4e8adfccc7d786bfed6ad81fe24a3b3010310 + sha256: "2b473399a49ec94452c4d4ae51cfc0f6585074398d74216092bf3d54aac37ecf" url: "https://pub.dev" source: hosted - version: "1.1.3" + version: "1.2.1" media_kit_libs_macos_video: dependency: transitive description: @@ -1636,27 +1645,27 @@ packages: description: path: "libs/universal/media_kit_libs_video" ref: HEAD - resolved-ref: "3c4ff28c43d20e68f8d587956b2f525292c25a80" + resolved-ref: c9617f570b8c0ba02857e721997f78c053a856c1 url: "https://github.com/media-kit/media-kit" source: git - version: "1.0.5" + version: "1.0.6" media_kit_libs_windows_video: dependency: transitive description: name: media_kit_libs_windows_video - sha256: "32654572167825c42c55466f5d08eee23ea11061c84aa91b09d0e0f69bdd0887" + sha256: dff76da2778729ab650229e6b4ec6ec111eb5151431002cbd7ea304ff1f112ab url: "https://pub.dev" source: hosted - version: "1.0.10" + version: "1.0.11" media_kit_video: dependency: "direct main" description: path: media_kit_video ref: HEAD - resolved-ref: "3c4ff28c43d20e68f8d587956b2f525292c25a80" + resolved-ref: c9617f570b8c0ba02857e721997f78c053a856c1 url: "https://github.com/media-kit/media-kit" source: git - version: "1.2.5" + version: "1.3.0" meta: dependency: transitive description: @@ -1720,7 +1729,7 @@ packages: description: path: "." ref: HEAD - resolved-ref: "7814e2c61ee1fa74cef73b946eb08519c35bdaa5" + resolved-ref: "64e47a446bf3b64f012f2076481cebea51ca27cf" url: "https://github.com/ente-io/motionphoto.git" source: git version: "0.0.1" @@ -1737,10 +1746,10 @@ packages: dependency: transitive description: name: multicast_dns - sha256: "0a568c8411ab0979ab8cd4af1c29b6d316d854ab81592463ccceb92b35fde813" + sha256: de72ada5c3db6fdd6ad4ae99452fe05fb403c4bb37c67ceb255ddd37d2b5b1eb url: "https://pub.dev" source: hosted - version: "0.3.2+8" + version: "0.3.3" nanoid: dependency: "direct main" description: @@ -1753,10 +1762,10 @@ packages: dependency: "direct main" description: name: native_dio_adapter - sha256: "7420bc9517b2abe09810199a19924617b45690a44ecfb0616ac9babc11875c03" + sha256: "1c51bd42027861d27ccad462ba0903f5e3197461cc6d59a0bb8658cb5ad7bd01" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.5.0" native_video_player: dependency: "direct main" description: @@ -1793,10 +1802,10 @@ packages: dependency: transitive description: name: objective_c - sha256: "62e79ab8c3ed6f6a340ea50dd48d65898f5d70425d404f0d99411f6e56e04584" + sha256: "9f034ba1eeca53ddb339bc8f4813cb07336a849cd735559b60cdc068ecce2dc7" url: "https://pub.dev" source: hosted - version: "4.1.0" + version: "7.1.0" octo_image: dependency: transitive description: @@ -1834,26 +1843,26 @@ packages: dependency: transitive description: name: package_config - sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67" + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.2.0" package_info_plus: dependency: "direct main" description: name: package_info_plus - sha256: "67eae327b1b0faf761964a1d2e5d323c797f3799db0e85aa232db8d9e922bc35" + sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191" url: "https://pub.dev" source: hosted - version: "8.2.1" + version: "8.3.0" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: "205ec83335c2ab9107bbba3f8997f9356d72ca3c715d2f038fc773d0366b4c76" + sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.2.0" panorama: dependency: "direct main" description: @@ -1963,10 +1972,10 @@ packages: dependency: transitive description: name: permission_handler_apple - sha256: f84a188e79a35c687c132a0a0556c254747a08561e99ab933f12f6ca71ef3c98 + sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 url: "https://pub.dev" source: hosted - version: "9.4.6" + version: "9.4.7" permission_handler_html: dependency: transitive description: @@ -2003,10 +2012,10 @@ packages: dependency: "direct main" description: name: photo_manager - sha256: "0bc7548fd3111eb93a3b0abf1c57364e40aeda32512c100085a48dade60e574f" + sha256: a0d9a7a9bc35eda02d33766412bde6d883a8b0acb86bbe37dac5f691a0894e8a url: "https://pub.dev" source: hosted - version: "3.6.4" + version: "3.7.1" photo_manager_image_provider: dependency: transitive description: @@ -2084,10 +2093,10 @@ packages: dependency: "direct main" description: name: pro_image_editor - sha256: "1df9d15d514d958c740fc6aeacc41cc94b77cdcd8d72dac13c8f3a781c5680da" + sha256: ee86d144ec76957578fb3dc7dee3d5e9cd03383cb153eb58f531be16ac528c63 url: "https://pub.dev" source: hosted - version: "7.2.0" + version: "6.0.0" process: dependency: transitive description: @@ -2116,18 +2125,18 @@ packages: dependency: transitive description: name: provider - sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84" url: "https://pub.dev" source: hosted - version: "6.1.2" + version: "6.1.5" pub_semver: dependency: transitive description: name: pub_semver - sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd" + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.2.0" pubspec_parse: dependency: transitive description: @@ -2148,10 +2157,10 @@ packages: dependency: transitive description: name: random_access_source - sha256: dc86934da2cc4777334f43916234410f232032738c519c0c3452147c5d4fec89 + sha256: "26d1509a9fd935ab9c77102ab4c94b343d36216387d985975c380efe450b81b8" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "3.0.0" receive_sharing_intent: dependency: "direct main" description: @@ -2181,10 +2190,10 @@ packages: dependency: transitive description: name: screen_brightness_android - sha256: ff9141bed547db02233e7dd88f990ab01973a0c8a8c04ddb855c7b072f33409a + sha256: fb5fa43cb89d0c9b8534556c427db1e97e46594ac5d66ebdcf16063b773d54ed url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" screen_brightness_platform_interface: dependency: transitive description: @@ -2245,18 +2254,18 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a" + sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" url: "https://pub.dev" source: hosted - version: "2.5.2" + version: "2.5.3" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: a768fc8ede5f0c8e6150476e14f38e2417c0864ca36bb4582be8e21925a03c22 + sha256: "9f9f3d372d4304723e6136663bb291c0b93f5e4c8a4a6314347f481a33bda2b1" url: "https://pub.dev" source: hosted - version: "2.4.6" + version: "2.4.7" shared_preferences_foundation: dependency: transitive description: @@ -2333,7 +2342,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.0" + version: "0.0.99" source_gen: dependency: transitive description: @@ -2434,18 +2443,18 @@ packages: dependency: transitive description: name: sqlite3 - sha256: "32b632dda27d664f85520093ed6f735ae5c49b5b75345afb8b19411bc59bb53d" + sha256: dd806fff004a0aeb01e208b858dbc649bc72104670d425a81a6dd17698535f6e url: "https://pub.dev" source: hosted - version: "2.7.4" + version: "2.8.0" sqlite3_flutter_libs: dependency: "direct main" description: name: sqlite3_flutter_libs - sha256: "57fafacd815c981735406215966ff7caaa8eab984b094f52e692accefcbd9233" + sha256: fd996da5515a73aacd0a04ae7063db5fe8df42670d974df4c3ee538c652eef2e url: "https://pub.dev" source: hosted - version: "0.5.30" + version: "0.5.38" sqlite_async: dependency: "direct main" description: @@ -2458,10 +2467,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.11.1" step_progress_indicator: dependency: "direct main" description: @@ -2490,10 +2499,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.2.0" styled_text: dependency: "direct main" description: @@ -2554,26 +2563,26 @@ packages: dependency: "direct dev" description: name: test - sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f" + sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e" url: "https://pub.dev" source: hosted - version: "1.25.8" + version: "1.25.7" test_api: dependency: transitive description: name: test_api - sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.7.3" + version: "0.7.2" test_core: dependency: transitive description: name: test_core - sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d" + sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696" url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.4" thermal: dependency: "direct main" description: @@ -2682,10 +2691,10 @@ packages: dependency: transitive description: name: url_launcher_ios - sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626" + sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" url: "https://pub.dev" source: hosted - version: "6.3.2" + version: "6.3.3" url_launcher_linux: dependency: transitive description: @@ -2812,10 +2821,10 @@ packages: dependency: transitive description: name: video_player_avfoundation - sha256: "84b4752745eeccb6e75865c9aab39b3d28eb27ba5726d352d45db8297fbd75bc" + sha256: "9ee764e5cd2fc1e10911ae8ad588e1a19db3b6aa9a6eb53c127c42d3a3c3f22f" url: "https://pub.dev" source: hosted - version: "2.7.0" + version: "2.7.1" video_player_platform_interface: dependency: transitive description: @@ -2828,10 +2837,10 @@ packages: dependency: transitive description: name: video_player_web - sha256: "3ef40ea6d72434edbfdba4624b90fd3a80a0740d260667d91e7ecd2d79e13476" + sha256: e8bba2e5d1e159d5048c9a491bb2a7b29c535c612bb7d10c1e21107f5bd365ba url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.3.5" video_thumbnail: dependency: "direct main" description: @@ -2853,74 +2862,74 @@ packages: dependency: transitive description: name: vm_service - sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "14.3.0" + version: "14.2.5" volume_controller: dependency: transitive description: name: volume_controller - sha256: "30863a51338db47fe16f92902b1a6c4ee5e15c9287b46573d7c2eb6be1f197d2" + sha256: d75039e69c0d90e7810bfd47e3eedf29ff8543ea7a10392792e81f9bded7edf5 url: "https://pub.dev" source: hosted - version: "3.3.1" + version: "3.4.0" wakelock_plus: dependency: "direct main" description: name: wakelock_plus - sha256: "36c88af0b930121941345306d259ec4cc4ecca3b151c02e3a9e71aede83c615e" + sha256: a474e314c3e8fb5adef1f9ae2d247e57467ad557fa7483a2b895bc1b421c5678 url: "https://pub.dev" source: hosted - version: "1.2.10" + version: "1.3.2" wakelock_plus_platform_interface: dependency: transitive description: name: wakelock_plus_platform_interface - sha256: "70e780bc99796e1db82fe764b1e7dcb89a86f1e5b3afb1db354de50f2e41eb7a" + sha256: e10444072e50dbc4999d7316fd303f7ea53d31c824aa5eb05d7ccbdd98985207 url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "1.2.3" watcher: dependency: "direct overridden" description: name: watcher - sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" + sha256: "0b7fd4a0bbc4b92641dbf20adfd7e3fd1398fe17102d94b674234563e110088a" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" web: dependency: transitive description: name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" web_socket: dependency: transitive description: name: web_socket - sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" url: "https://pub.dev" source: hosted - version: "0.1.6" + version: "1.0.1" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5" + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" webdriver: dependency: transitive description: name: webdriver - sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" + sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "3.0.3" webkit_inspection_protocol: dependency: transitive description: @@ -3019,4 +3028,4 @@ packages: version: "3.1.3" sdks: dart: ">=3.5.0 <4.0.0" - flutter: ">=3.27.0" + flutter: ">=3.24.0" diff --git a/mobile/apps/photos/pubspec.yaml b/mobile/apps/photos/pubspec.yaml index 59fc710426..8906f4139e 100644 --- a/mobile/apps/photos/pubspec.yaml +++ b/mobile/apps/photos/pubspec.yaml @@ -174,7 +174,7 @@ dependencies: git: url: https://github.com/eddyuan/privacy_screen.git ref: 855418e - pro_image_editor: ^7.2.0 + pro_image_editor: 6.0.0 receive_sharing_intent: # pub.dev is behind git: url: https://github.com/KasemJaffer/receive_sharing_intent.git From 93259dc28c5316248a28560793c909ee5cb4c378 Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Tue, 29 Jul 2025 12:38:15 +0530 Subject: [PATCH 19/28] feat: update filter presets and improve filter selection handling in image editor --- .../image_editor/image_editor_filter_bar.dart | 78 ++++++++++++++++++- .../image_editor/image_editor_page_new.dart | 12 ++- 2 files changed, 85 insertions(+), 5 deletions(-) diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_filter_bar.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_filter_bar.dart index 1fc6927c6e..58e76268e1 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_filter_bar.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_filter_bar.dart @@ -2,7 +2,83 @@ import 'package:figma_squircle/figma_squircle.dart'; import 'package:flutter/material.dart'; import "package:photos/ente_theme_data.dart"; import "package:photos/theme/ente_theme.dart"; -import 'package:pro_image_editor/pro_image_editor.dart'; +import 'package:pro_image_editor/pro_image_editor.dart'; + +final filterList = [ + FilterModel( + name: "Juno", + filters: [ + ColorFilterAddons.rgbScale(1.01, 1.04, 1), + ColorFilterAddons.saturation(0.3), + ], + ), + FilterModel( + name: 'Perpetua', + filters: [ + ColorFilterAddons.rgbScale(1.05, 1.1, 1), + ], + ), + FilterModel( + name: 'Reyes', + filters: [ + ColorFilterAddons.sepia(0.4), + ColorFilterAddons.brightness(0.13), + ColorFilterAddons.contrast(-.05), + ], + ), + FilterModel( + name: 'Aden', + filters: [ + ColorFilterAddons.colorOverlay(228, 130, 225, 0.13), + ColorFilterAddons.saturation(-0.2), + ], + ), + FilterModel( + name: "New preset", + filters: [ + ColorFilterAddons.hue(-0.6), + ColorFilterAddons.rgbScale(0.8, 1.0, 1.2), + ColorFilterAddons.saturation(-0.8), + ColorFilterAddons.contrast(-0.6), + ], + ), + FilterModel( + name: 'Amaro', + filters: [ + ColorFilterAddons.saturation(0.3), + ColorFilterAddons.brightness(0.15), + ], + ), + FilterModel( + name: 'Clarendon', + filters: [ + ColorFilterAddons.brightness(.1), + ColorFilterAddons.contrast(.1), + ColorFilterAddons.saturation(.15), + ], + ), + FilterModel( + name: 'Brooklyn', + filters: [ + ColorFilterAddons.colorOverlay(25, 240, 252, 0.05), + ColorFilterAddons.sepia(0.3), + ], + ), + FilterModel( + name: 'Sierra', + filters: [ + ColorFilterAddons.contrast(-0.15), + ColorFilterAddons.saturation(0.1), + ], + ), + FilterModel( + name: 'Inkwell', + filters: [ + ColorFilterAddons.contrast(0.2), + ColorFilterAddons.grayscale(), + ], + ), +]; class ImageEditorFilterBar extends StatefulWidget { const ImageEditorFilterBar({ diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart index f72f9f386f..e5232d2669 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart @@ -288,7 +288,10 @@ class _NewImageEditorState extends State { return ImageEditorFilterBar( filterModel: filter, isSelected: isSelected, - onSelectFilter: onSelectFilter, + onSelectFilter: () { + onSelectFilter.call(); + editorKey.currentState?.setState(() {}); + }, editorImage: editorImage, filterKey: filterKey, ); @@ -348,8 +351,8 @@ class _NewImageEditorState extends State { child: StreamBuilder( stream: rebuildStream, builder: (context, snapshot) { - final isHovered = editorKey.currentState - !.layerInteractionManager.hoverRemoveBtn; + final isHovered = editorKey.currentState! + .layerInteractionManager.hoverRemoveBtn; return AnimatedContainer( key: key, @@ -536,10 +539,11 @@ class _NewImageEditorState extends State { canReset: true, enabled: true, ), - filterEditorConfigs: const FilterEditorConfigs( + filterEditorConfigs: FilterEditorConfigs( enabled: true, fadeInUpDuration: fadeInDuration, fadeInUpStaggerDelayDuration: fadeInDelay, + filterList: filterList, ), tuneEditorConfigs: const TuneEditorConfigs(enabled: true), blurEditorConfigs: const BlurEditorConfigs( From 926715a4a8386d25e0e6d974579e4e6a53bd0e20 Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Tue, 29 Jul 2025 13:07:10 +0530 Subject: [PATCH 20/28] fix: handle zero display value in circular progress animation --- .../ui/tools/editor/image_editor/image_editor_tune_bar.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_tune_bar.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_tune_bar.dart index 1ebc163103..a7b5c69da4 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_tune_bar.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_tune_bar.dart @@ -315,7 +315,9 @@ class _CircularProgressWithValueState extends State AnimatedBuilder( animation: _progressAnimation, builder: (context, child) { - final animatedValue = _progressAnimation.value; + final animatedValue = + displayValue == 0 ? 0.0 : _progressAnimation.value; + final isClockwise = _isClockwise(animatedValue, widget.min, widget.max); final progressValue = _normalizeValueForProgress( From ce48e2610a530e488ee87a342436165bddc39f35 Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Tue, 29 Jul 2025 13:13:31 +0530 Subject: [PATCH 21/28] feat: enable zoom in main editor and refractor code --- .../image_editor/image_editor_page_new.dart | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart index e5232d2669..8a879b96f0 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart @@ -250,18 +250,6 @@ class _NewImageEditorState extends State { ), brightness: isLightMode ? Brightness.light : Brightness.dark, ), - mainEditorConfigs: const MainEditorConfigs(), - paintEditorConfigs: const PaintEditorConfigs(enabled: true), - textEditorConfigs: TextEditorConfigs( - canToggleBackgroundMode: true, - canToggleTextAlign: true, - customTextStyles: [ - GoogleFonts.inter(), - GoogleFonts.giveYouGlory(), - GoogleFonts.dmSerifText(), - GoogleFonts.comicNeue(), - ], - ), customWidgets: ImageEditorCustomWidgets( filterEditor: CustomWidgetsFilterEditor( slider: ( @@ -532,6 +520,18 @@ class _NewImageEditorState extends State { ), ), ), + mainEditorConfigs: const MainEditorConfigs(enableZoom: true), + paintEditorConfigs: const PaintEditorConfigs(enabled: true), + textEditorConfigs: TextEditorConfigs( + canToggleBackgroundMode: true, + canToggleTextAlign: true, + customTextStyles: [ + GoogleFonts.inter(), + GoogleFonts.giveYouGlory(), + GoogleFonts.dmSerifText(), + GoogleFonts.comicNeue(), + ], + ), cropRotateEditorConfigs: const CropRotateEditorConfigs( canChangeAspectRatio: true, canFlip: true, From ec0520bd2fdcd6335b167fbde4c74a2a174fe662 Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Tue, 29 Jul 2025 14:44:22 +0530 Subject: [PATCH 22/28] fix: update text editor configuration to disable text editing --- .../image_editor_main_bottom_bar.dart | 17 +++++------------ .../image_editor/image_editor_page_new.dart | 1 + 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_main_bottom_bar.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_main_bottom_bar.dart index de578abfec..3321e645c1 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_main_bottom_bar.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_main_bottom_bar.dart @@ -89,7 +89,7 @@ class ImageEditorMainBottomBarState extends State mainAxisSize: MainAxisSize.min, children: [ CircularIconButton( - svgPath: "assets/image-editor/image-editor-crop.svg", + svgPath: "assets/image-editor/image-editor-crop.svg", label: "Crop", onTap: () { widget.editor.openCropRotateEditor(); @@ -97,28 +97,21 @@ class ImageEditorMainBottomBarState extends State ), CircularIconButton( svgPath: - "assets/image-editor/image-editor-filter.svg", + "assets/image-editor/image-editor-filter.svg", label: "Filter", onTap: () { widget.editor.openFilterEditor(); }, ), CircularIconButton( - svgPath: "assets/image-editor/image-editor-text.svg", - label: "Text", - onTap: () { - widget.editor.openTextEditor(); - }, - ), - CircularIconButton( - svgPath: "assets/image-editor/image-editor-tune.svg", + svgPath: "assets/image-editor/image-editor-tune.svg", label: "Adjust", onTap: () { widget.editor.openTuneEditor(); }, ), CircularIconButton( - svgPath: "assets/image-editor/image-editor-paint.svg", + svgPath: "assets/image-editor/image-editor-paint.svg", label: "Draw", onTap: () { widget.editor.openPaintingEditor(); @@ -126,7 +119,7 @@ class ImageEditorMainBottomBarState extends State ), CircularIconButton( svgPath: - "assets/image-editor/image-editor-sticker.svg", + "assets/image-editor/image-editor-sticker.svg", label: "Sticker", onTap: () { widget.editor.openEmojiEditor(); diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart index 8a879b96f0..bceca00685 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart @@ -523,6 +523,7 @@ class _NewImageEditorState extends State { mainEditorConfigs: const MainEditorConfigs(enableZoom: true), paintEditorConfigs: const PaintEditorConfigs(enabled: true), textEditorConfigs: TextEditorConfigs( + enabled: false, canToggleBackgroundMode: true, canToggleTextAlign: true, customTextStyles: [ From 02a09ea206a1684228d5f88da187518128c8efdf Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Tue, 29 Jul 2025 19:32:25 +0530 Subject: [PATCH 23/28] fix: remove unused google_fonts dependency and update related configurations --- .../image_editor/image_editor_page_new.dart | 9 +--- mobile/apps/photos/pubspec.lock | 44 ++++++++----------- mobile/apps/photos/pubspec.yaml | 1 - 3 files changed, 19 insertions(+), 35 deletions(-) diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart index bceca00685..f99799378e 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_page_new.dart @@ -7,7 +7,6 @@ import 'dart:ui' as ui show Image; import 'package:flutter/material.dart'; import "package:flutter_image_compress/flutter_image_compress.dart"; import "package:flutter_svg/svg.dart"; -import "package:google_fonts/google_fonts.dart"; import "package:logging/logging.dart"; import 'package:path/path.dart' as path; import "package:photo_manager/photo_manager.dart"; @@ -522,16 +521,10 @@ class _NewImageEditorState extends State { ), mainEditorConfigs: const MainEditorConfigs(enableZoom: true), paintEditorConfigs: const PaintEditorConfigs(enabled: true), - textEditorConfigs: TextEditorConfigs( + textEditorConfigs: const TextEditorConfigs( enabled: false, canToggleBackgroundMode: true, canToggleTextAlign: true, - customTextStyles: [ - GoogleFonts.inter(), - GoogleFonts.giveYouGlory(), - GoogleFonts.dmSerifText(), - GoogleFonts.comicNeue(), - ], ), cropRotateEditorConfigs: const CropRotateEditorConfigs( canChangeAspectRatio: true, diff --git a/mobile/apps/photos/pubspec.lock b/mobile/apps/photos/pubspec.lock index 2988443213..bd467f28e3 100644 --- a/mobile/apps/photos/pubspec.lock +++ b/mobile/apps/photos/pubspec.lock @@ -325,10 +325,10 @@ packages: dependency: "direct main" description: name: collection - sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.19.0" + version: "1.18.0" computer: dependency: "direct main" description: @@ -1184,14 +1184,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.3" - google_fonts: - dependency: "direct main" - description: - name: google_fonts - sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82 - url: "https://pub.dev" - source: hosted - version: "6.2.1" graphs: dependency: transitive description: @@ -1441,18 +1433,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.7" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "3.0.8" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: @@ -2467,10 +2459,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.11.1" step_progress_indicator: dependency: "direct main" description: @@ -2499,10 +2491,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.2.0" styled_text: dependency: "direct main" description: @@ -2563,26 +2555,26 @@ packages: dependency: "direct dev" description: name: test - sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f" + sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e" url: "https://pub.dev" source: hosted - version: "1.25.8" + version: "1.25.7" test_api: dependency: transitive description: name: test_api - sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.7.3" + version: "0.7.2" test_core: dependency: transitive description: name: test_core - sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d" + sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696" url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.4" thermal: dependency: "direct main" description: @@ -2862,10 +2854,10 @@ packages: dependency: transitive description: name: vm_service - sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "14.3.0" + version: "14.2.5" volume_controller: dependency: transitive description: diff --git a/mobile/apps/photos/pubspec.yaml b/mobile/apps/photos/pubspec.yaml index 8906f4139e..0107e70148 100644 --- a/mobile/apps/photos/pubspec.yaml +++ b/mobile/apps/photos/pubspec.yaml @@ -109,7 +109,6 @@ dependencies: fluttertoast: ^8.0.6 fraction: ^5.0.2 freezed_annotation: ^2.4.1 - google_fonts: ^6.2.1 home_widget: ^0.7.0+1 html_unescape: ^2.0.0 http: ^1.1.0 From aaa53d7dc479c4f57d747bae15b4a8e4b365205d Mon Sep 17 00:00:00 2001 From: ashilkn Date: Tue, 29 Jul 2025 20:15:33 +0530 Subject: [PATCH 24/28] Fix build error --- mobile/apps/photos/pubspec.lock | 10 +++++----- mobile/apps/photos/pubspec.yaml | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/mobile/apps/photos/pubspec.lock b/mobile/apps/photos/pubspec.lock index bd467f28e3..f80b8e1f5f 100644 --- a/mobile/apps/photos/pubspec.lock +++ b/mobile/apps/photos/pubspec.lock @@ -371,13 +371,13 @@ packages: source: hosted version: "1.15.0" cronet_http: - dependency: transitive + dependency: "direct overridden" description: name: cronet_http - sha256: df26af0de7c4eff46c53c190b5590e22457bfce6ea679aedb1e6326197f27d6f + sha256: "5ed075c59b2d4bd43af4e73d906b8082e98ecd2af9c625327370ef28361bf635" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.3.4" cross_file: dependency: transitive description: @@ -1385,10 +1385,10 @@ packages: dependency: transitive description: name: jni - sha256: d2c361082d554d4593c3012e26f6b188f902acd291330f13d6427641a92b3da1 + sha256: "459727a9daf91bdfb39b014cf3c186cf77f0136124a274ac83c186e12262ac4e" url: "https://pub.dev" source: hosted - version: "0.14.2" + version: "0.12.2" js: dependency: "direct overridden" description: diff --git a/mobile/apps/photos/pubspec.yaml b/mobile/apps/photos/pubspec.yaml index 0107e70148..df407d9914 100644 --- a/mobile/apps/photos/pubspec.yaml +++ b/mobile/apps/photos/pubspec.yaml @@ -217,6 +217,7 @@ dependencies: xml: ^6.3.0 dependency_overrides: + cronet_http: "1.3.4" # Remove this after removing dependency from flutter_sodium. # Newer flutter packages depends on ffi > 2.0.0 while flutter_sodium depends on ffi < 2.0.0 ffi: 2.1.0 From dccc880b682eb2bc1a81a945f84849c67e23c6e8 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Tue, 29 Jul 2025 20:16:20 +0530 Subject: [PATCH 25/28] Fix build error --- mobile/apps/photos/pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/mobile/apps/photos/pubspec.yaml b/mobile/apps/photos/pubspec.yaml index df407d9914..76594a6a28 100644 --- a/mobile/apps/photos/pubspec.yaml +++ b/mobile/apps/photos/pubspec.yaml @@ -217,6 +217,7 @@ dependencies: xml: ^6.3.0 dependency_overrides: + # See if app builds after removing this override once flutter is updated to 3.27 cronet_http: "1.3.4" # Remove this after removing dependency from flutter_sodium. # Newer flutter packages depends on ffi > 2.0.0 while flutter_sodium depends on ffi < 2.0.0 From d62f1d50caf4aadc0ffb9f9576c8ab51d8d4015f Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Wed, 30 Jul 2025 14:41:03 +0530 Subject: [PATCH 26/28] fix: update filter names and orders in image editor --- .../image_editor/image_editor_filter_bar.dart | 68 ++++++++++--------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_filter_bar.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_filter_bar.dart index 58e76268e1..6fae72b031 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_filter_bar.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_filter_bar.dart @@ -2,24 +2,29 @@ import 'package:figma_squircle/figma_squircle.dart'; import 'package:flutter/material.dart'; import "package:photos/ente_theme_data.dart"; import "package:photos/theme/ente_theme.dart"; -import 'package:pro_image_editor/pro_image_editor.dart'; +import 'package:pro_image_editor/pro_image_editor.dart'; final filterList = [ + const FilterModel( + name: "None", + filters: [], + ), FilterModel( - name: "Juno", + name: 'Pop', + filters: [ + ColorFilterAddons.saturation(0.3), + ColorFilterAddons.brightness(0.15), + ], + ), + FilterModel( + name: "Amber", filters: [ ColorFilterAddons.rgbScale(1.01, 1.04, 1), ColorFilterAddons.saturation(0.3), ], ), FilterModel( - name: 'Perpetua', - filters: [ - ColorFilterAddons.rgbScale(1.05, 1.1, 1), - ], - ), - FilterModel( - name: 'Reyes', + name: 'Dust', filters: [ ColorFilterAddons.sepia(0.4), ColorFilterAddons.brightness(0.13), @@ -27,30 +32,36 @@ final filterList = [ ], ), FilterModel( - name: 'Aden', + name: 'Carbon', + filters: [ + ColorFilterAddons.contrast(0.2), + ColorFilterAddons.grayscale(), + ], + ), + FilterModel( + name: 'Glacier', + filters: [ + ColorFilterAddons.hue(-0.6), + ColorFilterAddons.rgbScale(0.8, 1.0, 1.2), + ColorFilterAddons.saturation(-0.08), + ColorFilterAddons.contrast(-0.06), + ], + ), + FilterModel( + name: 'Haze', filters: [ ColorFilterAddons.colorOverlay(228, 130, 225, 0.13), ColorFilterAddons.saturation(-0.2), ], ), FilterModel( - name: "New preset", + name: 'Meadow', filters: [ - ColorFilterAddons.hue(-0.6), - ColorFilterAddons.rgbScale(0.8, 1.0, 1.2), - ColorFilterAddons.saturation(-0.8), - ColorFilterAddons.contrast(-0.6), + ColorFilterAddons.rgbScale(1.05, 1.1, 1), ], ), FilterModel( - name: 'Amaro', - filters: [ - ColorFilterAddons.saturation(0.3), - ColorFilterAddons.brightness(0.15), - ], - ), - FilterModel( - name: 'Clarendon', + name: 'Zest', filters: [ ColorFilterAddons.brightness(.1), ColorFilterAddons.contrast(.1), @@ -58,26 +69,19 @@ final filterList = [ ], ), FilterModel( - name: 'Brooklyn', + name: 'Retro', filters: [ ColorFilterAddons.colorOverlay(25, 240, 252, 0.05), ColorFilterAddons.sepia(0.3), ], ), FilterModel( - name: 'Sierra', + name: 'Sepia', filters: [ ColorFilterAddons.contrast(-0.15), ColorFilterAddons.saturation(0.1), ], ), - FilterModel( - name: 'Inkwell', - filters: [ - ColorFilterAddons.contrast(0.2), - ColorFilterAddons.grayscale(), - ], - ), ]; class ImageEditorFilterBar extends StatefulWidget { From be5e1a9840dcdc1d6639975a50fa8434822a7d66 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Wed, 30 Jul 2025 14:49:57 +0530 Subject: [PATCH 27/28] Update pubspec.lock --- mobile/apps/photos/pubspec.lock | 279 ++++++++++++++++---------------- mobile/apps/photos/pubspec.yaml | 2 - 2 files changed, 135 insertions(+), 146 deletions(-) diff --git a/mobile/apps/photos/pubspec.lock b/mobile/apps/photos/pubspec.lock index f80b8e1f5f..b5f0505424 100644 --- a/mobile/apps/photos/pubspec.lock +++ b/mobile/apps/photos/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: ff0a84a2734d9e1089f8aedd5c0af0061b82fb94e95260d943404e0ef2134b11 + sha256: "401dd18096f5eaa140404ccbbbf346f83c850e6f27049698a7ee75a3488ddb32" url: "https://pub.dev" source: hosted - version: "1.3.59" + version: "1.3.52" _macros: dependency: transitive description: dart @@ -114,18 +114,18 @@ packages: dependency: transitive description: name: args - sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 url: "https://pub.dev" source: hosted - version: "2.7.0" + version: "2.6.0" asn1lib: dependency: transitive description: name: asn1lib - sha256: "9a8f69025044eb466b9b60ef3bc3ac99b4dc6c158ae9c56d25eeccf5bc56d024" + sha256: "4bae5ae63e6d6dd17c4aac8086f3dec26c0236f6a0f03416c6c19d830c367cf5" url: "https://pub.dev" source: hosted - version: "1.6.5" + version: "1.5.8" async: dependency: "direct main" description: @@ -227,10 +227,10 @@ packages: dependency: transitive description: name: built_value - sha256: "0b1b12a0a549605e5f04476031cd0bc91ead1d7c8e830773a18ee54179b3cb62" + sha256: "28a712df2576b63c6c005c465989a348604960c0958d28be5303ba9baa841ac2" url: "https://pub.dev" source: hosted - version: "8.11.0" + version: "8.9.3" cached_network_image: dependency: "direct main" description: @@ -260,7 +260,7 @@ packages: description: path: "." ref: multicast_version - resolved-ref: af6378574352884beab6cddec462c7fdfc9a8c35 + resolved-ref: "1f39cd4d6efa9363e77b2439f0317bae0c92dda1" url: "https://github.com/guyluz11/flutter_cast.git" source: git version: "2.0.9" @@ -289,14 +289,6 @@ packages: url: "https://github.com/ente-io/chewie.git" source: git version: "1.10.0" - cli_config: - dependency: transitive - description: - name: cli_config - sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec - url: "https://pub.dev" - source: hosted - version: "0.2.0" cli_util: dependency: transitive description: @@ -342,10 +334,10 @@ packages: dependency: "direct main" description: name: connectivity_plus - sha256: "051849e2bd7c7b3bc5844ea0d096609ddc3a859890ec3a9ac4a65a2620cc1f99" + sha256: "04bf81bb0b77de31557b58d052b24b3eee33f09a6e7a8c68a3e247c7df19ec27" url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "6.1.3" connectivity_plus_platform_interface: dependency: transitive description: @@ -366,18 +358,18 @@ packages: dependency: transitive description: name: coverage - sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d" + sha256: e3493833ea012784c740e341952298f1cc77f1f01b1bbc3eb4eecf6984fb7f43 url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.11.1" cronet_http: - dependency: "direct overridden" + dependency: transitive description: name: cronet_http - sha256: "5ed075c59b2d4bd43af4e73d906b8082e98ecd2af9c625327370ef28361bf635" + sha256: "3af9c4d57bf07ef4b307e77b22be4ad61bea19ee6ff65e62184863f3a09f1415" url: "https://pub.dev" source: hosted - version: "1.3.4" + version: "1.3.2" cross_file: dependency: transitive description: @@ -406,10 +398,10 @@ packages: dependency: transitive description: name: cupertino_http - sha256: "8fb9e2c36d0732d9d96abd76683406b57e78a2514e27c962e0c603dbe6f2e3f8" + sha256: "6fcf79586ad872ddcd6004d55c8c2aab3cdf0337436e8f99837b1b6c30665d0c" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.0.2" cupertino_icons: dependency: "direct main" description: @@ -478,10 +470,10 @@ packages: dependency: transitive description: name: dio_web_adapter - sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78" + sha256: e485c7a39ff2b384fa1d7e09b4e25f755804de8384358049124830b04fc4f93a url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.0" dots_indicator: dependency: "direct main" description: @@ -660,18 +652,17 @@ packages: description: path: "flutter/flutter" ref: android-packaged - resolved-ref: e33d4d2f49a25af6bc493e9114350434e6c34ab4 + resolved-ref: "6d5d27a8c259eda6292f204a27fba53da70af20e" url: "https://github.com/ente-io/ffmpeg-kit" source: git version: "6.0.3" ffmpeg_kit_flutter_platform_interface: dependency: transitive description: - path: "flutter/flutter_platform_interface" - ref: android-packaged - resolved-ref: e33d4d2f49a25af6bc493e9114350434e6c34ab4 - url: "https://github.com/ente-io/ffmpeg-kit" - source: git + name: ffmpeg_kit_flutter_platform_interface + sha256: addf046ae44e190ad0101b2fde2ad909a3cd08a2a109f6106d2f7048b7abedee + url: "https://pub.dev" + source: hosted version: "0.2.1" figma_squircle: dependency: "direct main" @@ -701,50 +692,50 @@ packages: dependency: "direct main" description: name: firebase_core - sha256: "7be63a3f841fc9663342f7f3a011a42aef6a61066943c90b1c434d79d5c995c5" + sha256: "6a4ea0f1d533443c8afc3d809cd36a4e2b8f2e2e711f697974f55bb31d71d1b8" url: "https://pub.dev" source: hosted - version: "3.15.2" + version: "3.12.0" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface - sha256: "5dbc900677dcbe5873d22ad7fbd64b047750124f1f9b7ebe2a33b9ddccc838eb" + sha256: d7253d255ff10f85cfd2adaba9ac17bae878fa3ba577462451163bd9f1d1f0bf url: "https://pub.dev" source: hosted - version: "6.0.0" + version: "5.4.0" firebase_core_web: dependency: transitive description: name: firebase_core_web - sha256: "0ed0dc292e8f9ac50992e2394e9d336a0275b6ae400d64163fdf0a8a8b556c37" + sha256: e47f5c2776de018fa19bc9f6f723df136bc75cdb164d64b65305babd715c8e41 url: "https://pub.dev" source: hosted - version: "2.24.1" + version: "2.21.0" firebase_messaging: dependency: "direct main" description: name: firebase_messaging - sha256: "60be38574f8b5658e2f22b7e311ff2064bea835c248424a383783464e8e02fcc" + sha256: "8755a083a20bac4485e8b46d223f6f2eab34e659a76a75f8cf3cded53bc98a15" url: "https://pub.dev" source: hosted - version: "15.2.10" + version: "15.2.3" firebase_messaging_platform_interface: dependency: transitive description: name: firebase_messaging_platform_interface - sha256: "685e1771b3d1f9c8502771ccc9f91485b376ffe16d553533f335b9183ea99754" + sha256: "8cc771079677460de53ad8fcca5bc3074d58c5fc4f9d89b19585e5bfd9c64292" url: "https://pub.dev" source: hosted - version: "4.6.10" + version: "4.6.3" firebase_messaging_web: dependency: transitive description: name: firebase_messaging_web - sha256: "0d1be17bc89ed3ff5001789c92df678b2e963a51b6fa2bdb467532cc9dbed390" + sha256: caa73059b0396c97f691683c4cfc3f897c8543801579b7dd4851c431d8e4e091 url: "https://pub.dev" source: hosted - version: "3.10.10" + version: "3.10.3" fixnum: dependency: "direct main" description: @@ -943,10 +934,10 @@ packages: dependency: "direct main" description: name: flutter_local_notifications - sha256: "20ca0a9c82ce0c855ac62a2e580ab867f3fbea82680a90647f7953832d0850ae" + sha256: b94a50aabbe56ef254f95f3be75640f99120429f0a153b2dc30143cffc9bfdf3 url: "https://pub.dev" source: hosted - version: "19.4.0" + version: "19.2.1" flutter_local_notifications_linux: dependency: transitive description: @@ -959,18 +950,18 @@ packages: dependency: transitive description: name: flutter_local_notifications_platform_interface - sha256: "277d25d960c15674ce78ca97f57d0bae2ee401c844b6ac80fcd972a9c99d09fe" + sha256: "2569b973fc9d1f63a37410a9f7c1c552081226c597190cb359ef5d5762d1631c" url: "https://pub.dev" source: hosted - version: "9.1.0" + version: "9.0.0" flutter_local_notifications_windows: dependency: transitive description: name: flutter_local_notifications_windows - sha256: ed46d7ae4ec9d19e4c8fa2badac5fe27ba87a3fe387343ce726f927af074ec98 + sha256: f8fc0652a601f83419d623c85723a3e82ad81f92b33eaa9bcc21ea1b94773e6e url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.0.0" flutter_localizations: dependency: "direct main" description: flutter @@ -1020,10 +1011,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "1c2b787f99bdca1f3718543f81d38aa1b124817dfeb9fb196201bea85b6134bf" + sha256: "615a505aef59b151b46bbeef55b36ce2b6ed299d160c51d84281946f0aa0ce0e" url: "https://pub.dev" source: hosted - version: "2.0.26" + version: "2.0.24" flutter_secure_storage: dependency: "direct main" description: @@ -1036,10 +1027,10 @@ packages: dependency: transitive description: name: flutter_secure_storage_linux - sha256: be76c1d24a97d0b98f8b54bce6b481a380a6590df992d0098f868ad54dc8f688 + sha256: bf7404619d7ab5c0a1151d7c4e802edad8f33535abfbeff2f9e1fe1274e2d705 url: "https://pub.dev" source: hosted - version: "1.2.3" + version: "1.2.2" flutter_secure_storage_macos: dependency: transitive description: @@ -1109,10 +1100,10 @@ packages: dependency: "direct main" description: name: flutter_svg - sha256: d44bf546b13025ec7353091516f6881f1d4c633993cb109c3916c3a0159dadf1 + sha256: c200fd79c918a40c5cd50ea0877fa13f81bdaf6f0a5d3dbcc2a13e3285d6aa1b url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.0.17" flutter_test: dependency: "direct dev" description: flutter @@ -1122,10 +1113,10 @@ packages: dependency: "direct main" description: name: flutter_timezone - sha256: "13b2109ad75651faced4831bf262e32559e44aa549426eab8a597610d385d934" + sha256: bc286cecb0366d88e6c4644e3962ebd1ce1d233abc658eb1e0cd803389f84b64 url: "https://pub.dev" source: hosted - version: "4.1.1" + version: "4.1.0" flutter_web_plugins: dependency: transitive description: flutter @@ -1220,10 +1211,10 @@ packages: dependency: transitive description: name: html - sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" + sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" url: "https://pub.dev" source: hosted - version: "0.15.6" + version: "0.15.5" html_unescape: dependency: "direct main" description: @@ -1236,10 +1227,10 @@ packages: dependency: "direct main" description: name: http - sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b" + sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.3.0" http_client_helper: dependency: transitive description: @@ -1316,10 +1307,10 @@ packages: dependency: "direct main" description: name: in_app_purchase - sha256: "5cddd7f463f3bddb1d37a72b95066e840d5822d66291331d7f8f05ce32c24b6c" + sha256: "11a40f148eeb4f681a0572003e2b33432e110c90c1bbb4f9ef83b81ec0c4f737" url: "https://pub.dev" source: hosted - version: "3.2.3" + version: "3.2.1" in_app_purchase_android: dependency: transitive description: @@ -1340,10 +1331,10 @@ packages: dependency: transitive description: name: in_app_purchase_storekit - sha256: "02f08d5688fc2776e3e386ff7d3071b7b375ea8222e8e6bd027b15c0708e4045" + sha256: "276831961023055b55a2156c1fc043f50f6215ff49fb0f5f2273da6eeb510ecf" url: "https://pub.dev" source: hosted - version: "0.4.0" + version: "0.3.21" integration_test: dependency: "direct dev" description: flutter @@ -1377,18 +1368,18 @@ packages: dependency: transitive description: name: iso_base_media - sha256: "0a94fa4ff4ce7e6894d7afc96c1eee6911c12827f8cf184ca752ce3437a818a1" + sha256: "0f5594feef1fba98179a2df95d1afbdda952de0c7a2e35e6815093f7c00aaf06" url: "https://pub.dev" source: hosted - version: "4.6.1" + version: "4.5.2" jni: dependency: transitive description: name: jni - sha256: "459727a9daf91bdfb39b014cf3c186cf77f0136124a274ac83c186e12262ac4e" + sha256: f377c585ea9c08d48b427dc2e03780af2889d1bb094440da853c6883c1acba4b url: "https://pub.dev" source: hosted - version: "0.12.2" + version: "0.10.1" js: dependency: "direct overridden" description: @@ -1457,10 +1448,10 @@ packages: dependency: "direct main" description: name: like_button - sha256: "8b349521182ea6252b7fe1eaaad5932a9f55f94c3e87849376cfc25c78bac53a" + sha256: "08e6a45b78888412df5d351786c550205ad3a677e72a0820d5bbc0b063c8a463" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.0.5" lints: dependency: transitive description: @@ -1489,10 +1480,10 @@ packages: dependency: "direct main" description: name: local_auth_android - sha256: "8bba79f4f0f7bc812fce2ca20915d15618c37721246ba6c3ef2aa7a763a90cf2" + sha256: "6763aaf8965f21822624cb2fd3c03d2a8b3791037b5efb0fe4b13e110f5afc92" url: "https://pub.dev" source: hosted - version: "1.0.47" + version: "1.0.46" local_auth_darwin: dependency: transitive description: @@ -1529,10 +1520,10 @@ packages: dependency: transitive description: name: logger - sha256: "2621da01aabaf223f8f961e751f2c943dbb374dc3559b982f200ccedadaa6999" + sha256: be4b23575aac7ebf01f225a241eb7f6b5641eeaf43c6a8613510fc2f8cf187d1 url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.5.0" logging: dependency: "direct main" description: @@ -1595,24 +1586,24 @@ packages: description: path: media_kit ref: HEAD - resolved-ref: c9617f570b8c0ba02857e721997f78c053a856c1 + resolved-ref: "3c4ff28c43d20e68f8d587956b2f525292c25a80" url: "https://github.com/media-kit/media-kit" source: git - version: "1.2.0" + version: "1.1.11" media_kit_libs_android_video: dependency: transitive description: name: media_kit_libs_android_video - sha256: adff9b571b8ead0867f9f91070f8df39562078c0eb3371d88b9029a2d547d7b7 + sha256: "9dd8012572e4aff47516e55f2597998f0a378e3d588d0fad0ca1f11a53ae090c" url: "https://pub.dev" source: hosted - version: "1.3.7" + version: "1.3.6" media_kit_libs_ios_video: dependency: "direct main" description: path: "libs/ios/media_kit_libs_ios_video" ref: HEAD - resolved-ref: c9617f570b8c0ba02857e721997f78c053a856c1 + resolved-ref: "3c4ff28c43d20e68f8d587956b2f525292c25a80" url: "https://github.com/media-kit/media-kit" source: git version: "1.1.4" @@ -1620,10 +1611,10 @@ packages: dependency: transitive description: name: media_kit_libs_linux - sha256: "2b473399a49ec94452c4d4ae51cfc0f6585074398d74216092bf3d54aac37ecf" + sha256: e186891c31daa6bedab4d74dcdb4e8adfccc7d786bfed6ad81fe24a3b3010310 url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.1.3" media_kit_libs_macos_video: dependency: transitive description: @@ -1637,27 +1628,27 @@ packages: description: path: "libs/universal/media_kit_libs_video" ref: HEAD - resolved-ref: c9617f570b8c0ba02857e721997f78c053a856c1 + resolved-ref: "3c4ff28c43d20e68f8d587956b2f525292c25a80" url: "https://github.com/media-kit/media-kit" source: git - version: "1.0.6" + version: "1.0.5" media_kit_libs_windows_video: dependency: transitive description: name: media_kit_libs_windows_video - sha256: dff76da2778729ab650229e6b4ec6ec111eb5151431002cbd7ea304ff1f112ab + sha256: "32654572167825c42c55466f5d08eee23ea11061c84aa91b09d0e0f69bdd0887" url: "https://pub.dev" source: hosted - version: "1.0.11" + version: "1.0.10" media_kit_video: dependency: "direct main" description: path: media_kit_video ref: HEAD - resolved-ref: c9617f570b8c0ba02857e721997f78c053a856c1 + resolved-ref: "3c4ff28c43d20e68f8d587956b2f525292c25a80" url: "https://github.com/media-kit/media-kit" source: git - version: "1.3.0" + version: "1.2.5" meta: dependency: transitive description: @@ -1721,7 +1712,7 @@ packages: description: path: "." ref: HEAD - resolved-ref: "64e47a446bf3b64f012f2076481cebea51ca27cf" + resolved-ref: "7814e2c61ee1fa74cef73b946eb08519c35bdaa5" url: "https://github.com/ente-io/motionphoto.git" source: git version: "0.0.1" @@ -1738,10 +1729,10 @@ packages: dependency: transitive description: name: multicast_dns - sha256: de72ada5c3db6fdd6ad4ae99452fe05fb403c4bb37c67ceb255ddd37d2b5b1eb + sha256: "0a568c8411ab0979ab8cd4af1c29b6d316d854ab81592463ccceb92b35fde813" url: "https://pub.dev" source: hosted - version: "0.3.3" + version: "0.3.2+8" nanoid: dependency: "direct main" description: @@ -1754,10 +1745,10 @@ packages: dependency: "direct main" description: name: native_dio_adapter - sha256: "1c51bd42027861d27ccad462ba0903f5e3197461cc6d59a0bb8658cb5ad7bd01" + sha256: "7420bc9517b2abe09810199a19924617b45690a44ecfb0616ac9babc11875c03" url: "https://pub.dev" source: hosted - version: "1.5.0" + version: "1.4.0" native_video_player: dependency: "direct main" description: @@ -1794,10 +1785,10 @@ packages: dependency: transitive description: name: objective_c - sha256: "9f034ba1eeca53ddb339bc8f4813cb07336a849cd735559b60cdc068ecce2dc7" + sha256: "62e79ab8c3ed6f6a340ea50dd48d65898f5d70425d404f0d99411f6e56e04584" url: "https://pub.dev" source: hosted - version: "7.1.0" + version: "4.1.0" octo_image: dependency: transitive description: @@ -1835,26 +1826,26 @@ packages: dependency: transitive description: name: package_config - sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.1.1" package_info_plus: dependency: "direct main" description: name: package_info_plus - sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191" + sha256: "67eae327b1b0faf761964a1d2e5d323c797f3799db0e85aa232db8d9e922bc35" url: "https://pub.dev" source: hosted - version: "8.3.0" + version: "8.2.1" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c" + sha256: "205ec83335c2ab9107bbba3f8997f9356d72ca3c715d2f038fc773d0366b4c76" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.1.0" panorama: dependency: "direct main" description: @@ -1964,10 +1955,10 @@ packages: dependency: transitive description: name: permission_handler_apple - sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 + sha256: f84a188e79a35c687c132a0a0556c254747a08561e99ab933f12f6ca71ef3c98 url: "https://pub.dev" source: hosted - version: "9.4.7" + version: "9.4.6" permission_handler_html: dependency: transitive description: @@ -2004,10 +1995,10 @@ packages: dependency: "direct main" description: name: photo_manager - sha256: a0d9a7a9bc35eda02d33766412bde6d883a8b0acb86bbe37dac5f691a0894e8a + sha256: "0bc7548fd3111eb93a3b0abf1c57364e40aeda32512c100085a48dade60e574f" url: "https://pub.dev" source: hosted - version: "3.7.1" + version: "3.6.4" photo_manager_image_provider: dependency: transitive description: @@ -2117,18 +2108,18 @@ packages: dependency: transitive description: name: provider - sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84" + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c url: "https://pub.dev" source: hosted - version: "6.1.5" + version: "6.1.2" pub_semver: dependency: transitive description: name: pub_semver - sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.1.5" pubspec_parse: dependency: transitive description: @@ -2149,10 +2140,10 @@ packages: dependency: transitive description: name: random_access_source - sha256: "26d1509a9fd935ab9c77102ab4c94b343d36216387d985975c380efe450b81b8" + sha256: dc86934da2cc4777334f43916234410f232032738c519c0c3452147c5d4fec89 url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "2.1.0" receive_sharing_intent: dependency: "direct main" description: @@ -2182,10 +2173,10 @@ packages: dependency: transitive description: name: screen_brightness_android - sha256: fb5fa43cb89d0c9b8534556c427db1e97e46594ac5d66ebdcf16063b773d54ed + sha256: ff9141bed547db02233e7dd88f990ab01973a0c8a8c04ddb855c7b072f33409a url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.0" screen_brightness_platform_interface: dependency: transitive description: @@ -2246,18 +2237,18 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" + sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a" url: "https://pub.dev" source: hosted - version: "2.5.3" + version: "2.5.2" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "9f9f3d372d4304723e6136663bb291c0b93f5e4c8a4a6314347f481a33bda2b1" + sha256: a768fc8ede5f0c8e6150476e14f38e2417c0864ca36bb4582be8e21925a03c22 url: "https://pub.dev" source: hosted - version: "2.4.7" + version: "2.4.6" shared_preferences_foundation: dependency: transitive description: @@ -2435,18 +2426,18 @@ packages: dependency: transitive description: name: sqlite3 - sha256: dd806fff004a0aeb01e208b858dbc649bc72104670d425a81a6dd17698535f6e + sha256: "32b632dda27d664f85520093ed6f735ae5c49b5b75345afb8b19411bc59bb53d" url: "https://pub.dev" source: hosted - version: "2.8.0" + version: "2.7.4" sqlite3_flutter_libs: dependency: "direct main" description: name: sqlite3_flutter_libs - sha256: fd996da5515a73aacd0a04ae7063db5fe8df42670d974df4c3ee538c652eef2e + sha256: "57fafacd815c981735406215966ff7caaa8eab984b094f52e692accefcbd9233" url: "https://pub.dev" source: hosted - version: "0.5.38" + version: "0.5.30" sqlite_async: dependency: "direct main" description: @@ -2683,10 +2674,10 @@ packages: dependency: transitive description: name: url_launcher_ios - sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" + sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626" url: "https://pub.dev" source: hosted - version: "6.3.3" + version: "6.3.2" url_launcher_linux: dependency: transitive description: @@ -2813,10 +2804,10 @@ packages: dependency: transitive description: name: video_player_avfoundation - sha256: "9ee764e5cd2fc1e10911ae8ad588e1a19db3b6aa9a6eb53c127c42d3a3c3f22f" + sha256: "84b4752745eeccb6e75865c9aab39b3d28eb27ba5726d352d45db8297fbd75bc" url: "https://pub.dev" source: hosted - version: "2.7.1" + version: "2.7.0" video_player_platform_interface: dependency: transitive description: @@ -2829,10 +2820,10 @@ packages: dependency: transitive description: name: video_player_web - sha256: e8bba2e5d1e159d5048c9a491bb2a7b29c535c612bb7d10c1e21107f5bd365ba + sha256: "3ef40ea6d72434edbfdba4624b90fd3a80a0740d260667d91e7ecd2d79e13476" url: "https://pub.dev" source: hosted - version: "2.3.5" + version: "2.3.4" video_thumbnail: dependency: "direct main" description: @@ -2862,58 +2853,58 @@ packages: dependency: transitive description: name: volume_controller - sha256: d75039e69c0d90e7810bfd47e3eedf29ff8543ea7a10392792e81f9bded7edf5 + sha256: "30863a51338db47fe16f92902b1a6c4ee5e15c9287b46573d7c2eb6be1f197d2" url: "https://pub.dev" source: hosted - version: "3.4.0" + version: "3.3.1" wakelock_plus: dependency: "direct main" description: name: wakelock_plus - sha256: a474e314c3e8fb5adef1f9ae2d247e57467ad557fa7483a2b895bc1b421c5678 + sha256: "36c88af0b930121941345306d259ec4cc4ecca3b151c02e3a9e71aede83c615e" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.2.10" wakelock_plus_platform_interface: dependency: transitive description: name: wakelock_plus_platform_interface - sha256: e10444072e50dbc4999d7316fd303f7ea53d31c824aa5eb05d7ccbdd98985207 + sha256: "70e780bc99796e1db82fe764b1e7dcb89a86f1e5b3afb1db354de50f2e41eb7a" url: "https://pub.dev" source: hosted - version: "1.2.3" + version: "1.2.2" watcher: dependency: "direct overridden" description: name: watcher - sha256: "0b7fd4a0bbc4b92641dbf20adfd7e3fd1398fe17102d94b674234563e110088a" + sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.1" web: dependency: transitive description: name: web - sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.0" web_socket: dependency: transitive description: name: web_socket - sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "0.1.6" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 + sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.2" webdriver: dependency: transitive description: diff --git a/mobile/apps/photos/pubspec.yaml b/mobile/apps/photos/pubspec.yaml index 76594a6a28..0107e70148 100644 --- a/mobile/apps/photos/pubspec.yaml +++ b/mobile/apps/photos/pubspec.yaml @@ -217,8 +217,6 @@ dependencies: xml: ^6.3.0 dependency_overrides: - # See if app builds after removing this override once flutter is updated to 3.27 - cronet_http: "1.3.4" # Remove this after removing dependency from flutter_sodium. # Newer flutter packages depends on ffi > 2.0.0 while flutter_sodium depends on ffi < 2.0.0 ffi: 2.1.0 From bc00276316b06e6df5df6d9e33cb79789a09c98c Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Wed, 30 Jul 2025 16:03:45 +0530 Subject: [PATCH 28/28] feat: add Glacier filter with matrix adjustments for saturation, contrast, hue, and temperature --- .../image_editor/image_editor_filter_bar.dart | 104 +++++++++++++++++- 1 file changed, 99 insertions(+), 5 deletions(-) diff --git a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_filter_bar.dart b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_filter_bar.dart index 6fae72b031..8a29cdba52 100644 --- a/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_filter_bar.dart +++ b/mobile/apps/photos/lib/ui/tools/editor/image_editor/image_editor_filter_bar.dart @@ -4,6 +4,100 @@ import "package:photos/ente_theme_data.dart"; import "package:photos/theme/ente_theme.dart"; import 'package:pro_image_editor/pro_image_editor.dart'; +class GlacierFilterMatrix { + static const saturation = [ + 0.97, + 0.02, + 0.00, + 0.00, + 0.00, + 0.01, + 0.98, + 0.00, + 0.00, + 0.00, + 0.01, + 0.02, + 0.96, + 0.00, + 0.00, + 0.00, + 0.00, + 0.00, + 1.00, + 0.00, + ]; + + static const contrast = [ + 0.94, + 0.00, + 0.00, + 0.00, + 7.07, + 0.00, + 0.94, + 0.00, + 0.00, + 7.07, + 0.00, + 0.00, + 0.94, + 0.00, + 7.07, + 0.00, + 0.00, + 0.00, + 1.00, + 0.00, + ]; + + static const hue = [ + 1.01, + 0.40, + -0.41, + 0.00, + 0.00, + -0.04, + 0.91, + 0.14, + 0.00, + 0.00, + 0.38, + -0.25, + 0.87, + 0.00, + 0.00, + 0.00, + 0.00, + 0.00, + 1.00, + 0.00, + ]; + + static const temperature = [ + 0.80, + 0.00, + 0.00, + 0.00, + 0.00, + 0.00, + 1.00, + 0.00, + 0.00, + 0.00, + 0.00, + 0.00, + 1.00, + 0.00, + 0.00, + 0.00, + 0.00, + 0.00, + 1.00, + 0.00, + ]; +} + final filterList = [ const FilterModel( name: "None", @@ -38,13 +132,13 @@ final filterList = [ ColorFilterAddons.grayscale(), ], ), - FilterModel( + const FilterModel( name: 'Glacier', filters: [ - ColorFilterAddons.hue(-0.6), - ColorFilterAddons.rgbScale(0.8, 1.0, 1.2), - ColorFilterAddons.saturation(-0.08), - ColorFilterAddons.contrast(-0.06), + GlacierFilterMatrix.saturation, + GlacierFilterMatrix.temperature, + GlacierFilterMatrix.hue, + GlacierFilterMatrix.contrast, ], ), FilterModel(