✨ Paste to add attachment
This commit is contained in:
@ -86,7 +86,10 @@ class PostWriteMedia {
|
||||
if (file != null) {
|
||||
return file!;
|
||||
} else if (raw != null) {
|
||||
return XFile.fromData(raw!, name: name);
|
||||
return XFile.fromData(
|
||||
raw!,
|
||||
name: name,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -256,6 +259,9 @@ class PostWriteController extends ChangeNotifier {
|
||||
media.name,
|
||||
'interactive',
|
||||
null,
|
||||
mimetype: media.raw != null && media.type == PostWriteMediaType.image
|
||||
? 'image/png'
|
||||
: null,
|
||||
);
|
||||
|
||||
final item = await attach.chunkedUploadParts(
|
||||
|
@ -130,8 +130,9 @@ class SnAttachmentProvider {
|
||||
int size,
|
||||
String filename,
|
||||
String pool,
|
||||
Map<String, dynamic>? metadata,
|
||||
) async {
|
||||
Map<String, dynamic>? metadata, {
|
||||
String? mimetype,
|
||||
}) async {
|
||||
final fileAlt = filename.contains('.')
|
||||
? filename.substring(0, filename.lastIndexOf('.'))
|
||||
: filename;
|
||||
@ -139,8 +140,10 @@ class SnAttachmentProvider {
|
||||
filename.substring(filename.lastIndexOf('.') + 1).toLowerCase();
|
||||
|
||||
String? mimetypeOverride;
|
||||
if (mimetypeOverrides.keys.contains(fileExt)) {
|
||||
if (mimetype == null && mimetypeOverrides.keys.contains(fileExt)) {
|
||||
mimetypeOverride = mimetypeOverrides[fileExt];
|
||||
} else {
|
||||
mimetypeOverride = mimetype;
|
||||
}
|
||||
|
||||
final resp = await _sn.client.post('/cgi/uc/attachments/multipart', data: {
|
||||
|
@ -9,6 +9,7 @@ import 'package:gap/gap.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:pasteboard/pasteboard.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:surface/controllers/post_write_controller.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
|
||||
void dispose() {
|
||||
_writeController.dispose();
|
||||
@ -369,15 +382,39 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
|
||||
scrollDirection: Axis.vertical,
|
||||
child: Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: _writeController.isBusy
|
||||
? null
|
||||
: _selectMedia,
|
||||
PopupMenuButton(
|
||||
icon: Icon(
|
||||
Symbols.add_photo_alternate,
|
||||
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();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:pasteboard/pasteboard.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:surface/controllers/chat_message_controller.dart';
|
||||
@ -72,6 +73,9 @@ class ChatMessageInputState extends State<ChatMessageInput> {
|
||||
media.name,
|
||||
'interactive',
|
||||
null,
|
||||
mimetype: media.raw != null && media.type == PostWriteMediaType.image
|
||||
? 'image/png'
|
||||
: null,
|
||||
);
|
||||
|
||||
final item = await attach.chunkedUploadParts(
|
||||
@ -133,6 +137,19 @@ class ChatMessageInputState extends State<ChatMessageInput> {
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
void _pasteMedia() async {
|
||||
final imageBytes = await Pasteboard.image;
|
||||
if (imageBytes == null) return;
|
||||
_attachments.add(
|
||||
PostWriteMedia.fromBytes(
|
||||
imageBytes,
|
||||
'attachmentPastedImage'.tr(),
|
||||
PostWriteMediaType.image,
|
||||
),
|
||||
);
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_contentController.dispose();
|
||||
@ -266,12 +283,37 @@ class ChatMessageInputState extends State<ChatMessageInput> {
|
||||
),
|
||||
),
|
||||
const Gap(8),
|
||||
IconButton(
|
||||
onPressed: _isBusy ? null : _selectMedia,
|
||||
PopupMenuButton(
|
||||
icon: Icon(
|
||||
Symbols.add_photo_alternate,
|
||||
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(
|
||||
onPressed: _isBusy ? null : _sendMessage,
|
||||
|
Reference in New Issue
Block a user