From 9a643c76e99f67d686ae4d75ce6b67a7014dcc28 Mon Sep 17 00:00:00 2001 From: Nithish Sri Ram <115037539+Nithish-Sri-Ram@users.noreply.github.com> Date: Thu, 2 Jan 2025 23:25:16 +0530 Subject: [PATCH 1/3] Enabled user to choose the save location --- lib/ui/shared/dialogs/save_image_dialog.dart | 23 +++++++++++++------- pubspec.yaml | 1 + 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/ui/shared/dialogs/save_image_dialog.dart b/lib/ui/shared/dialogs/save_image_dialog.dart index 3e6280bf..3ae70c1e 100644 --- a/lib/ui/shared/dialogs/save_image_dialog.dart +++ b/lib/ui/shared/dialogs/save_image_dialog.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; - +import 'package:file_picker/file_picker.dart'; // Add file picker import 'package:paintroid/core/enums/image_format.dart'; import 'package:paintroid/core/models/image_meta_data.dart'; import 'package:paintroid/ui/shared/image_format_info.dart'; @@ -32,23 +32,30 @@ class _SaveImageDialogState extends State { @override void initState() { super.initState(); - if (widget.savingProject) { selectedFormat = ImageFormat.catrobatImage; } } - void _dismissDialogWithData() { + Future _dismissDialogWithData() async { + final directoryPath = await FilePicker.platform.getDirectoryPath(); + if (directoryPath == null) { + // User canceled the picker + return; + } + late ImageMetaData data; switch (selectedFormat) { case ImageFormat.png: - data = PngMetaData(nameFieldController.text); + data = PngMetaData('${directoryPath}/${nameFieldController.text}.png'); break; case ImageFormat.jpg: - data = JpgMetaData(nameFieldController.text, imageQualityValue); + data = JpgMetaData( + '${directoryPath}/${nameFieldController.text}.jpg', imageQualityValue); break; case ImageFormat.catrobatImage: - data = CatrobatImageMetaData(nameFieldController.text); + data = CatrobatImageMetaData( + '${directoryPath}/${nameFieldController.text}.catrobat'); break; } Navigator.of(context).pop(data); @@ -120,10 +127,10 @@ class _SaveImageDialogState extends State { TextButton get _saveButton { return TextButton( - onPressed: () { + onPressed: () async { final formState = formKey.currentState; if (formState != null && formState.validate()) { - _dismissDialogWithData(); + await _dismissDialogWithData(); } }, child: Text( diff --git a/pubspec.yaml b/pubspec.yaml index c267575f..fdc76060 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,6 +40,7 @@ dependencies: file_picker: ^5.3.1 floor: ^1.2.0 sqflite: ^2.3.0 + win32: 5.8.0 colorpicker: path: packages/colorpicker From e523efcf9653db000931ba4bd6c81586b341727f Mon Sep 17 00:00:00 2001 From: Nithish Sri Ram <115037539+Nithish-Sri-Ram@users.noreply.github.com> Date: Thu, 2 Jan 2025 23:13:33 +0530 Subject: [PATCH 2/3] Can store images at specific location mentioned by the user --- pubspec.lock | 82 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 29 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 41146529..16af116d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -284,18 +284,18 @@ packages: dependency: transitive description: name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.3" file: dependency: transitive description: name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "7.0.0" file_picker: dependency: "direct main" description: @@ -607,10 +607,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.18.1" + version: "0.19.0" io: dependency: transitive description: @@ -651,6 +651,30 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + url: "https://pub.dev" + source: hosted + version: "10.0.5" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" lints: dependency: transitive description: @@ -679,26 +703,26 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.15.0" mime: dependency: transitive description: @@ -751,10 +775,10 @@ packages: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_drawing: dependency: transitive description: @@ -871,10 +895,10 @@ packages: dependency: transitive description: name: platform - sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102 + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.5" plugin_platform_interface: dependency: transitive description: @@ -895,10 +919,10 @@ packages: dependency: transitive description: name: process - sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" url: "https://pub.dev" source: hosted - version: "4.2.4" + version: "5.0.2" pub_semver: dependency: transitive description: @@ -1196,10 +1220,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.2" timing: dependency: transitive description: @@ -1316,10 +1340,10 @@ packages: dependency: transitive description: name: vm_service - sha256: c538be99af830f478718b51630ec1b6bee5e74e52c8a802d328d9e71d35d2583 + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "11.10.0" + version: "14.2.5" watcher: dependency: transitive description: @@ -1348,18 +1372,18 @@ packages: dependency: transitive description: name: webdriver - sha256: "3c923e918918feeb90c4c9fdf1fe39220fa4c0e8e2c0fffaded174498ef86c49" + sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" win32: - dependency: transitive + dependency: "direct main" description: name: win32 - sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8" + sha256: "84ba388638ed7a8cb3445a320c8273136ab2631cd5f2c57888335504ddab1bc2" url: "https://pub.dev" source: hosted - version: "5.2.0" + version: "5.8.0" win32_registry: dependency: transitive description: @@ -1393,5 +1417,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.2.0 <4.0.0" - flutter: ">=3.16.0" + dart: ">=3.5.0 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" From 05461f6689ad912b8602c8cdf0a7a63babae6d60 Mon Sep 17 00:00:00 2001 From: Nithish Sri Ram <115037539+Nithish-Sri-Ram@users.noreply.github.com> Date: Sun, 26 Jan 2025 21:14:25 +0530 Subject: [PATCH 3/3] Refactor Save Image --- lib/ui/shared/dialogs/save_image_dialog.dart | 60 +++++++++++++++++--- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/lib/ui/shared/dialogs/save_image_dialog.dart b/lib/ui/shared/dialogs/save_image_dialog.dart index 3ae70c1e..9d33535c 100644 --- a/lib/ui/shared/dialogs/save_image_dialog.dart +++ b/lib/ui/shared/dialogs/save_image_dialog.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:file_picker/file_picker.dart'; // Add file picker +import 'package:file_picker/file_picker.dart'; import 'package:paintroid/core/enums/image_format.dart'; import 'package:paintroid/core/models/image_meta_data.dart'; import 'package:paintroid/ui/shared/image_format_info.dart'; @@ -25,6 +25,8 @@ class SaveImageDialog extends StatefulWidget { class _SaveImageDialogState extends State { final TextEditingController nameFieldController = TextEditingController(); + final TextEditingController savePathController = + TextEditingController(text: 'default/save/path'); final formKey = GlobalKey(debugLabel: 'SaveImageDialog Form'); var selectedFormat = ImageFormat.jpg; var imageQualityValue = 100; @@ -38,24 +40,25 @@ class _SaveImageDialogState extends State { } Future _dismissDialogWithData() async { - final directoryPath = await FilePicker.platform.getDirectoryPath(); - if (directoryPath == null) { - // User canceled the picker + final directoryPath = savePathController.text; + if (directoryPath.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Please specify a valid save path.'))); return; } late ImageMetaData data; switch (selectedFormat) { case ImageFormat.png: - data = PngMetaData('${directoryPath}/${nameFieldController.text}.png'); + data = PngMetaData('$directoryPath/${nameFieldController.text}.png'); break; case ImageFormat.jpg: data = JpgMetaData( - '${directoryPath}/${nameFieldController.text}.jpg', imageQualityValue); + '$directoryPath/${nameFieldController.text}.jpg', imageQualityValue); break; case ImageFormat.catrobatImage: data = CatrobatImageMetaData( - '${directoryPath}/${nameFieldController.text}.catrobat'); + '$directoryPath/${nameFieldController.text}.catrobat'); break; } Navigator.of(context).pop(data); @@ -88,6 +91,14 @@ class _SaveImageDialogState extends State { height: 16, color: PaintroidTheme.of(context).onSurfaceVariantColor, ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: _savePathTextField, + ), + Divider( + height: 16, + color: PaintroidTheme.of(context).onSurfaceVariantColor, + ), if (!widget.savingProject) Column( children: [ @@ -191,6 +202,41 @@ class _SaveImageDialogState extends State { ); } + Padding get _savePathTextField { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: TextFormField( + controller: savePathController, + decoration: InputDecoration( + labelStyle: const TextStyle(fontWeight: FontWeight.bold), + hintText: 'Enter custom save path or use default', + suffixIcon: IconButton( + icon: const Icon(Icons.folder_open), + onPressed: () async { + final directoryPath = await FilePicker.platform.getDirectoryPath(); + if (directoryPath != null) { + setState(() { + savePathController.text = directoryPath; + }); + } + }, + ), + filled: true, + fillColor: PaintroidTheme.of(context).secondaryContainerColor, + border: const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(8)), + ), + ), + validator: (path) { + if (path == null || path.isEmpty) { + return 'Please specify a save path'; + } + return null; + }, + ), + ); + } + Row get _imageFormatDropdown { return Row( children: [