diff --git a/lib/services/sydney_service.dart b/lib/services/sydney_service.dart index 9451b0a..47292cf 100644 --- a/lib/services/sydney_service.dart +++ b/lib/services/sydney_service.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'package:image/image.dart' as img; import 'dart:typed_data'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; @@ -81,7 +82,15 @@ class SydneyService extends GetConnect { (event) => MessageEvent(event.type, jsonDecode(event.content))); } - Future uploadImage(Uint8List image) async { + Future uploadImage(Uint8List bytes) async { + final processImage = img.Command() + ..decodeImage(bytes) + ..encodeJpg(quality: 90); + + final imageResult = await processImage.executeThread(); + + final image = imageResult.outputBytes; + final form = FormData({ "cookies": cookies.value, "file": MultipartFile(image, filename: "image.png") @@ -90,6 +99,10 @@ class SydneyService extends GetConnect { final resp = await post(_uploadImageUrl!.toString(), form, headers: _authHeaders); + if (resp.statusCode != 200) { + throw Exception("Failed to upload image: ${resp.statusCode}"); + } + return resp.bodyString!; } diff --git a/lib/widgets/image_upload_dialog.dart b/lib/widgets/image_upload_dialog.dart index 2b670fe..4eebcd4 100644 --- a/lib/widgets/image_upload_dialog.dart +++ b/lib/widgets/image_upload_dialog.dart @@ -1,6 +1,7 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:pasteboard/pasteboard.dart'; import 'package:sydney_webui/controller.dart'; class ImageUploadDialog extends StatelessWidget { @@ -20,17 +21,40 @@ class ImageUploadDialog extends StatelessWidget { imageUrl.value = textEditController.text; }); - void uploadImage() async { + void pickAndUploadImage() async { isUploading.value = true; - final file = await FilePicker.platform.pickFiles(type: FileType.image); - if (file == null) { + try { + final result = + await FilePicker.platform.pickFiles(type: FileType.image); + + if (result == null) { + isUploading.value = false; + return; + } + + textEditController.text = await controller.sydneyService + .uploadImage(result.files.first.bytes!); + } catch (e) { + Get.snackbar('Error occurred', 'Failed to upload image: $e'); + } finally { isUploading.value = false; - return; } + } + + void pasteAndUploadImage() async { + isUploading.value = true; + try { + final image = await Pasteboard.image; + + if (image == null) { + isUploading.value = false; + return; + } + textEditController.text = - await controller.sydneyService.uploadImage(file.files.first.bytes!); + await controller.sydneyService.uploadImage(image); } catch (e) { Get.snackbar('Error occurred', 'Failed to upload image: $e'); } finally { @@ -63,7 +87,26 @@ class ImageUploadDialog extends StatelessWidget { )), const SizedBox(width: 8), ElevatedButton( - onPressed: uploadImage, + onPressed: pasteAndUploadImage, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Obx( + () => isUploading.value + ? const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator()) + : const Icon(Icons.paste), + ), + const SizedBox(width: 8), + const Text('Paste Image') + ], + ), + ), + const SizedBox(width: 8), + ElevatedButton( + onPressed: pickAndUploadImage, child: Row( mainAxisSize: MainAxisSize.min, children: [ @@ -76,7 +119,7 @@ class ImageUploadDialog extends StatelessWidget { : const Icon(Icons.upload_file), ), const SizedBox(width: 8), - const Text('Upload Image') + const Text('Pick Image') ], ), ), diff --git a/pubspec.lock b/pubspec.lock index 2085d06..ef990d0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + archive: + dependency: transitive + description: + name: archive + sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b" + url: "https://pub.dev" + source: hosted + version: "3.4.9" args: dependency: transitive description: @@ -49,6 +57,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" crypto: dependency: transitive description: @@ -176,6 +192,22 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + image: + dependency: "direct main" + description: + name: image + sha256: "028f61960d56f26414eb616b48b04eb37d700cbe477b7fb09bf1d7ce57fd9271" + url: "https://pub.dev" + source: hosted + version: "4.1.3" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" lints: dependency: transitive description: @@ -216,6 +248,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.10.0" + pasteboard: + dependency: "direct main" + description: + name: pasteboard + sha256: "1c8b6a8b3f1d12e55d4e9404433cda1b4abe66db6b17bc2d2fb5965772c04674" + url: "https://pub.dev" + source: hosted + version: "0.2.0" path: dependency: transitive description: @@ -272,6 +312,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" platform: dependency: transitive description: @@ -288,6 +336,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.7" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + url: "https://pub.dev" + source: hosted + version: "3.7.3" sky_engine: dependency: transitive description: flutter @@ -381,6 +437,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.3" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" sdks: dart: ">=3.2.3 <4.0.0" flutter: ">=3.13.0" diff --git a/pubspec.yaml b/pubspec.yaml index 20a64b2..c364ba9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -37,6 +37,8 @@ dependencies: google_fonts: markdown: flutter_highlighter: + pasteboard: + image: dev_dependencies: flutter_test: