Paste to add attachment

This commit is contained in:
LittleSheep 2024-11-22 00:28:29 +08:00
parent b52811d66e
commit 1af90cd9e7
14 changed files with 132 additions and 12 deletions

View File

@ -171,5 +171,8 @@
"zero": "No attachments", "zero": "No attachments",
"one": "{} attachment", "one": "{} attachment",
"other": "{} attachments" "other": "{} attachments"
} },
"addAttachmentFromAlbum": "Add from album",
"addAttachmentFromClipboard": "Paste file",
"attachmentPastedImage": "Pasted Image"
} }

View File

@ -171,5 +171,8 @@
"zero": "没有附件", "zero": "没有附件",
"one": "{} 个附件", "one": "{} 个附件",
"other": "{} 个附件" "other": "{} 个附件"
} },
"addAttachmentFromAlbum": "从相册中添加附件",
"addAttachmentFromClipboard": "粘贴附件",
"attachmentPastedImage" : "粘贴的图片"
} }

View File

@ -202,6 +202,8 @@ PODS:
- nanopb/encode (3.30910.0) - nanopb/encode (3.30910.0)
- package_info_plus (0.4.5): - package_info_plus (0.4.5):
- Flutter - Flutter
- pasteboard (0.0.1):
- Flutter
- path_provider_foundation (0.0.1): - path_provider_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
@ -247,6 +249,7 @@ DEPENDENCIES:
- media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`) - media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`)
- media_kit_video (from `.symlinks/plugins/media_kit_video/ios`) - media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- pasteboard (from `.symlinks/plugins/pasteboard/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`) - screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
@ -316,6 +319,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/media_kit_video/ios" :path: ".symlinks/plugins/media_kit_video/ios"
package_info_plus: package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios" :path: ".symlinks/plugins/package_info_plus/ios"
pasteboard:
:path: ".symlinks/plugins/pasteboard/ios"
path_provider_foundation: path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin" :path: ".symlinks/plugins/path_provider_foundation/darwin"
screen_brightness_ios: screen_brightness_ios:
@ -366,6 +371,7 @@ SPEC CHECKSUMS:
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
pasteboard: 982969ebaa7c78af3e6cc7761e8f5e77565d9ce0
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851

View File

@ -86,7 +86,10 @@ class PostWriteMedia {
if (file != null) { if (file != null) {
return file!; return file!;
} else if (raw != null) { } else if (raw != null) {
return XFile.fromData(raw!, name: name); return XFile.fromData(
raw!,
name: name,
);
} }
return null; return null;
} }
@ -256,6 +259,9 @@ class PostWriteController extends ChangeNotifier {
media.name, media.name,
'interactive', 'interactive',
null, null,
mimetype: media.raw != null && media.type == PostWriteMediaType.image
? 'image/png'
: null,
); );
final item = await attach.chunkedUploadParts( final item = await attach.chunkedUploadParts(

View File

@ -130,8 +130,9 @@ class SnAttachmentProvider {
int size, int size,
String filename, String filename,
String pool, String pool,
Map<String, dynamic>? metadata, Map<String, dynamic>? metadata, {
) async { String? mimetype,
}) async {
final fileAlt = filename.contains('.') final fileAlt = filename.contains('.')
? filename.substring(0, filename.lastIndexOf('.')) ? filename.substring(0, filename.lastIndexOf('.'))
: filename; : filename;
@ -139,8 +140,10 @@ class SnAttachmentProvider {
filename.substring(filename.lastIndexOf('.') + 1).toLowerCase(); filename.substring(filename.lastIndexOf('.') + 1).toLowerCase();
String? mimetypeOverride; String? mimetypeOverride;
if (mimetypeOverrides.keys.contains(fileExt)) { if (mimetype == null && mimetypeOverrides.keys.contains(fileExt)) {
mimetypeOverride = mimetypeOverrides[fileExt]; mimetypeOverride = mimetypeOverrides[fileExt];
} else {
mimetypeOverride = mimetype;
} }
final resp = await _sn.client.post('/cgi/uc/attachments/multipart', data: { final resp = await _sn.client.post('/cgi/uc/attachments/multipart', data: {

View File

@ -9,6 +9,7 @@ import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
import 'package:pasteboard/pasteboard.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:surface/controllers/post_write_controller.dart'; import 'package:surface/controllers/post_write_controller.dart';
import 'package:surface/providers/sn_network.dart'; import 'package:surface/providers/sn_network.dart';
@ -82,6 +83,18 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
); );
} }
void _pasteMedia() async {
final imageBytes = await Pasteboard.image;
if (imageBytes == null) return;
_writeController.addAttachments([
PostWriteMedia.fromBytes(
imageBytes,
'attachmentPastedImage'.tr(),
PostWriteMediaType.image,
),
]);
}
@override @override
void dispose() { void dispose() {
_writeController.dispose(); _writeController.dispose();
@ -369,15 +382,39 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
scrollDirection: Axis.vertical, scrollDirection: Axis.vertical,
child: Row( child: Row(
children: [ children: [
IconButton( PopupMenuButton(
onPressed: _writeController.isBusy
? null
: _selectMedia,
icon: Icon( icon: Icon(
Symbols.add_photo_alternate, Symbols.add_photo_alternate,
color: color:
Theme.of(context).colorScheme.primary, Theme.of(context).colorScheme.primary,
), ),
itemBuilder: (context) => [
PopupMenuItem(
child: Row(
children: [
const Icon(Symbols.photo_library),
const Gap(16),
Text('addAttachmentFromAlbum').tr(),
],
),
onTap: () {
_selectMedia();
},
),
PopupMenuItem(
child: Row(
children: [
const Icon(Symbols.content_paste),
const Gap(16),
Text('addAttachmentFromClipboard')
.tr(),
],
),
onTap: () {
_pasteMedia();
},
),
],
), ),
], ],
), ),

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
import 'package:pasteboard/pasteboard.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:surface/controllers/chat_message_controller.dart'; import 'package:surface/controllers/chat_message_controller.dart';
@ -72,6 +73,9 @@ class ChatMessageInputState extends State<ChatMessageInput> {
media.name, media.name,
'interactive', 'interactive',
null, null,
mimetype: media.raw != null && media.type == PostWriteMediaType.image
? 'image/png'
: null,
); );
final item = await attach.chunkedUploadParts( final item = await attach.chunkedUploadParts(
@ -133,6 +137,19 @@ class ChatMessageInputState extends State<ChatMessageInput> {
setState(() {}); setState(() {});
} }
void _pasteMedia() async {
final imageBytes = await Pasteboard.image;
if (imageBytes == null) return;
_attachments.add(
PostWriteMedia.fromBytes(
imageBytes,
'attachmentPastedImage'.tr(),
PostWriteMediaType.image,
),
);
setState(() {});
}
@override @override
void dispose() { void dispose() {
_contentController.dispose(); _contentController.dispose();
@ -266,12 +283,37 @@ class ChatMessageInputState extends State<ChatMessageInput> {
), ),
), ),
const Gap(8), const Gap(8),
IconButton( PopupMenuButton(
onPressed: _isBusy ? null : _selectMedia,
icon: Icon( icon: Icon(
Symbols.add_photo_alternate, Symbols.add_photo_alternate,
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,
), ),
itemBuilder: (context) => [
PopupMenuItem(
child: Row(
children: [
const Icon(Symbols.photo_library),
const Gap(16),
Text('addAttachmentFromAlbum').tr(),
],
),
onTap: () {
_selectMedia();
},
),
PopupMenuItem(
child: Row(
children: [
const Icon(Symbols.content_paste),
const Gap(16),
Text('addAttachmentFromClipboard').tr(),
],
),
onTap: () {
_pasteMedia();
},
),
],
), ),
IconButton( IconButton(
onPressed: _isBusy ? null : _sendMessage, onPressed: _isBusy ? null : _sendMessage,

View File

@ -12,6 +12,7 @@
#include <isar_flutter_libs/isar_flutter_libs_plugin.h> #include <isar_flutter_libs/isar_flutter_libs_plugin.h>
#include <media_kit_libs_linux/media_kit_libs_linux_plugin.h> #include <media_kit_libs_linux/media_kit_libs_linux_plugin.h>
#include <media_kit_video/media_kit_video_plugin.h> #include <media_kit_video/media_kit_video_plugin.h>
#include <pasteboard/pasteboard_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h> #include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) { void fl_register_plugins(FlPluginRegistry* registry) {
@ -33,6 +34,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) media_kit_video_registrar = g_autoptr(FlPluginRegistrar) media_kit_video_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitVideoPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitVideoPlugin");
media_kit_video_plugin_register_with_registrar(media_kit_video_registrar); media_kit_video_plugin_register_with_registrar(media_kit_video_registrar);
g_autoptr(FlPluginRegistrar) pasteboard_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin");
pasteboard_plugin_register_with_registrar(pasteboard_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);

View File

@ -9,6 +9,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
isar_flutter_libs isar_flutter_libs
media_kit_libs_linux media_kit_libs_linux
media_kit_video media_kit_video
pasteboard
url_launcher_linux url_launcher_linux
) )

View File

@ -17,6 +17,7 @@ import isar_flutter_libs
import media_kit_libs_macos_video import media_kit_libs_macos_video
import media_kit_video import media_kit_video
import package_info_plus import package_info_plus
import pasteboard
import path_provider_foundation import path_provider_foundation
import screen_brightness_macos import screen_brightness_macos
import shared_preferences_foundation import shared_preferences_foundation
@ -37,6 +38,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin")) MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin"))
MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin")) MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin")) ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))

View File

@ -1202,6 +1202,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.1" version: "3.0.1"
pasteboard:
dependency: "direct main"
description:
name: pasteboard
sha256: "7bf733f3a00c7188ec1f2c6f0612854248b302cf91ef3611a2b7bb141c0f9d55"
url: "https://pub.dev"
source: hosted
version: "0.3.0"
path: path:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -87,6 +87,7 @@ dependencies:
media_kit: ^1.1.11 media_kit: ^1.1.11
media_kit_video: ^1.2.5 media_kit_video: ^1.2.5
media_kit_libs_video: ^1.0.5 media_kit_libs_video: ^1.0.5
pasteboard: ^0.3.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -14,6 +14,7 @@
#include <isar_flutter_libs/isar_flutter_libs_plugin.h> #include <isar_flutter_libs/isar_flutter_libs_plugin.h>
#include <media_kit_libs_windows_video/media_kit_libs_windows_video_plugin_c_api.h> #include <media_kit_libs_windows_video/media_kit_libs_windows_video_plugin_c_api.h>
#include <media_kit_video/media_kit_video_plugin_c_api.h> #include <media_kit_video/media_kit_video_plugin_c_api.h>
#include <pasteboard/pasteboard_plugin.h>
#include <screen_brightness_windows/screen_brightness_windows_plugin.h> #include <screen_brightness_windows/screen_brightness_windows_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h> #include <url_launcher_windows/url_launcher_windows.h>
@ -34,6 +35,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("MediaKitLibsWindowsVideoPluginCApi")); registry->GetRegistrarForPlugin("MediaKitLibsWindowsVideoPluginCApi"));
MediaKitVideoPluginCApiRegisterWithRegistrar( MediaKitVideoPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("MediaKitVideoPluginCApi")); registry->GetRegistrarForPlugin("MediaKitVideoPluginCApi"));
PasteboardPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PasteboardPlugin"));
ScreenBrightnessWindowsPluginRegisterWithRegistrar( ScreenBrightnessWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin")); registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin"));
UrlLauncherWindowsRegisterWithRegistrar( UrlLauncherWindowsRegisterWithRegistrar(

View File

@ -11,6 +11,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
isar_flutter_libs isar_flutter_libs
media_kit_libs_windows_video media_kit_libs_windows_video
media_kit_video media_kit_video
pasteboard
screen_brightness_windows screen_brightness_windows
url_launcher_windows url_launcher_windows
) )