💄 Better attachment editor previewing
This commit is contained in:
parent
9765b200b9
commit
1e4b44a78b
@ -112,7 +112,6 @@ class PostEditorController extends GetxController {
|
|||||||
Future<void> editAttachment(BuildContext context) {
|
Future<void> editAttachment(BuildContext context) {
|
||||||
return showModalBottomSheet(
|
return showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
|
||||||
builder: (context) => AttachmentEditorPopup(
|
builder: (context) => AttachmentEditorPopup(
|
||||||
usage: 'i.attachment',
|
usage: 'i.attachment',
|
||||||
current: attachments,
|
current: attachments,
|
||||||
|
@ -4,6 +4,7 @@ import 'dart:math' as math;
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:desktop_drop/desktop_drop.dart';
|
import 'package:desktop_drop/desktop_drop.dart';
|
||||||
|
import 'package:dismissible_page/dismissible_page.dart';
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_animate/flutter_animate.dart';
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
@ -16,6 +17,7 @@ import 'package:solian/models/attachment.dart';
|
|||||||
import 'package:solian/platform.dart';
|
import 'package:solian/platform.dart';
|
||||||
import 'package:solian/providers/auth.dart';
|
import 'package:solian/providers/auth.dart';
|
||||||
import 'package:solian/providers/content/attachment.dart';
|
import 'package:solian/providers/content/attachment.dart';
|
||||||
|
import 'package:solian/widgets/attachments/attachment_fullscreen.dart';
|
||||||
import 'package:solian/widgets/attachments/attachment_item.dart';
|
import 'package:solian/widgets/attachments/attachment_item.dart';
|
||||||
|
|
||||||
class AttachmentEditorPopup extends StatefulWidget {
|
class AttachmentEditorPopup extends StatefulWidget {
|
||||||
@ -42,7 +44,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
|
|
||||||
List<Attachment?> _attachments = List.empty(growable: true);
|
List<Attachment?> _attachments = List.empty(growable: true);
|
||||||
|
|
||||||
Future<void> pickPhotoToUpload() async {
|
Future<void> _pickPhotoToUpload() async {
|
||||||
final AuthProvider auth = Get.find();
|
final AuthProvider auth = Get.find();
|
||||||
if (auth.isAuthorized.isFalse) return;
|
if (auth.isAuthorized.isFalse) return;
|
||||||
|
|
||||||
@ -54,7 +56,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
for (final media in medias) {
|
for (final media in medias) {
|
||||||
final file = File(media.path);
|
final file = File(media.path);
|
||||||
try {
|
try {
|
||||||
await uploadAttachment(
|
await _uploadAttachment(
|
||||||
await file.readAsBytes(),
|
await file.readAsBytes(),
|
||||||
file.path,
|
file.path,
|
||||||
null,
|
null,
|
||||||
@ -67,7 +69,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
setState(() => _isBusy = false);
|
setState(() => _isBusy = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> pickVideoToUpload() async {
|
Future<void> _pickVideoToUpload() async {
|
||||||
final AuthProvider auth = Get.find();
|
final AuthProvider auth = Get.find();
|
||||||
if (auth.isAuthorized.isFalse) return;
|
if (auth.isAuthorized.isFalse) return;
|
||||||
|
|
||||||
@ -79,7 +81,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
final file = File(media.path);
|
final file = File(media.path);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await uploadAttachment(await file.readAsBytes(), file.path, null);
|
await _uploadAttachment(await file.readAsBytes(), file.path, null);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
context.showErrorDialog(err);
|
context.showErrorDialog(err);
|
||||||
}
|
}
|
||||||
@ -87,7 +89,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
setState(() => _isBusy = false);
|
setState(() => _isBusy = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> pickFileToUpload() async {
|
Future<void> _pickFileToUpload() async {
|
||||||
final AuthProvider auth = Get.find();
|
final AuthProvider auth = Get.find();
|
||||||
if (auth.isAuthorized.isFalse) return;
|
if (auth.isAuthorized.isFalse) return;
|
||||||
|
|
||||||
@ -102,7 +104,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
|
|
||||||
for (final file in files) {
|
for (final file in files) {
|
||||||
try {
|
try {
|
||||||
await uploadAttachment(await file.readAsBytes(), file.path, null);
|
await _uploadAttachment(await file.readAsBytes(), file.path, null);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
context.showErrorDialog(err);
|
context.showErrorDialog(err);
|
||||||
}
|
}
|
||||||
@ -111,7 +113,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
setState(() => _isBusy = false);
|
setState(() => _isBusy = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> takeMediaToUpload(bool isVideo) async {
|
Future<void> _takeMediaToUpload(bool isVideo) async {
|
||||||
final AuthProvider auth = Get.find();
|
final AuthProvider auth = Get.find();
|
||||||
if (auth.isAuthorized.isFalse) return;
|
if (auth.isAuthorized.isFalse) return;
|
||||||
|
|
||||||
@ -127,7 +129,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
|
|
||||||
final file = File(media.path);
|
final file = File(media.path);
|
||||||
try {
|
try {
|
||||||
await uploadAttachment(await file.readAsBytes(), file.path, null);
|
await _uploadAttachment(await file.readAsBytes(), file.path, null);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
context.showErrorDialog(err);
|
context.showErrorDialog(err);
|
||||||
}
|
}
|
||||||
@ -135,18 +137,18 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
setState(() => _isBusy = false);
|
setState(() => _isBusy = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pasteFileToUpload() async {
|
void _pasteFileToUpload() async {
|
||||||
final data = await Pasteboard.image;
|
final data = await Pasteboard.image;
|
||||||
if (data == null) return;
|
if (data == null) return;
|
||||||
|
|
||||||
setState(() => _isBusy = true);
|
setState(() => _isBusy = true);
|
||||||
|
|
||||||
uploadAttachment(data, 'Pasted Image', null);
|
_uploadAttachment(data, 'Pasted Image', null);
|
||||||
|
|
||||||
setState(() => _isBusy = false);
|
setState(() => _isBusy = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> uploadAttachment(
|
Future<void> _uploadAttachment(
|
||||||
Uint8List data, String path, Map<String, dynamic>? metadata) async {
|
Uint8List data, String path, Map<String, dynamic>? metadata) async {
|
||||||
final AttachmentProvider provider = Get.find();
|
final AttachmentProvider provider = Get.find();
|
||||||
try {
|
try {
|
||||||
@ -188,7 +190,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
return '${(bytes / math.pow(k, i)).toStringAsFixed(dm)} ${sizes[i]}';
|
return '${(bytes / math.pow(k, i)).toStringAsFixed(dm)} ${sizes[i]}';
|
||||||
}
|
}
|
||||||
|
|
||||||
void revertMetadataList() {
|
void _revertMetadataList() {
|
||||||
final AttachmentProvider provider = Get.find();
|
final AttachmentProvider provider = Get.find();
|
||||||
|
|
||||||
if (widget.current.isEmpty) {
|
if (widget.current.isEmpty) {
|
||||||
@ -215,7 +217,17 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void showEdit(Attachment element, int index) {
|
void _showAttachmentPreview(Attachment element) {
|
||||||
|
context.pushTransparentRoute(
|
||||||
|
AttachmentFullScreen(
|
||||||
|
parentId: 'attachment-editor-preview',
|
||||||
|
item: element,
|
||||||
|
),
|
||||||
|
rootNavigator: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showEdit(Attachment element, int index) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
@ -234,15 +246,68 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
Widget _buildListEntry(Attachment element, int index) {
|
||||||
void initState() {
|
var fileType = element.mimetype.split('/').firstOrNull;
|
||||||
super.initState();
|
fileType ??= 'unknown';
|
||||||
revertMetadataList();
|
|
||||||
|
final canBePreview = fileType.toLowerCase() == 'image';
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.only(left: 16, right: 8, bottom: 16),
|
||||||
|
child: Card(
|
||||||
|
color: Theme.of(context).colorScheme.surface,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 54,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
element.alt,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
maxLines: 1,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontFamily: 'monospace'),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'${fileType[0].toUpperCase()}${fileType.substring(1)} · ${_formatBytes(element.size)}',
|
||||||
|
style: const TextStyle(fontSize: 12),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
color: Colors.teal,
|
||||||
|
icon: const Icon(Icons.preview),
|
||||||
|
visualDensity: const VisualDensity(horizontal: -4),
|
||||||
|
onPressed: canBePreview
|
||||||
|
? () => _showAttachmentPreview(element)
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
visualDensity: const VisualDensity(horizontal: -4),
|
||||||
|
icon: const Icon(Icons.more_horiz),
|
||||||
|
onPressed: () => _showEdit(element, index),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).paddingSymmetric(vertical: 8, horizontal: 16),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void initState() {
|
||||||
super.dispose();
|
super.initState();
|
||||||
|
_revertMetadataList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -250,14 +315,12 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
const density = VisualDensity(horizontal: 0, vertical: 0);
|
const density = VisualDensity(horizontal: 0, vertical: 0);
|
||||||
|
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
child: SizedBox(
|
|
||||||
height: MediaQuery.of(context).size.height * 0.85,
|
|
||||||
child: DropTarget(
|
child: DropTarget(
|
||||||
onDragDone: (detail) async {
|
onDragDone: (detail) async {
|
||||||
setState(() => _isBusy = true);
|
setState(() => _isBusy = true);
|
||||||
for (final file in detail.files) {
|
for (final file in detail.files) {
|
||||||
final data = await file.readAsBytes();
|
final data = await file.readAsBytes();
|
||||||
uploadAttachment(data, file.path, null);
|
_uploadAttachment(data, file.path, null);
|
||||||
}
|
}
|
||||||
setState(() => _isBusy = false);
|
setState(() => _isBusy = false);
|
||||||
},
|
},
|
||||||
@ -281,71 +344,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
itemCount: _attachments.length,
|
itemCount: _attachments.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final element = _attachments[index];
|
final element = _attachments[index];
|
||||||
var fileType = element!.mimetype.split('/').firstOrNull;
|
return _buildListEntry(element!, index);
|
||||||
fileType ??= 'unknown';
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
left: 16, right: 8, bottom: 16),
|
|
||||||
child: Card(
|
|
||||||
color: Theme.of(context).colorScheme.surface,
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
height: 280,
|
|
||||||
child: ClipRRect(
|
|
||||||
borderRadius: const BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(8),
|
|
||||||
topRight: Radius.circular(8),
|
|
||||||
),
|
|
||||||
child: AttachmentItem(
|
|
||||||
parentId: 'attachment-editor',
|
|
||||||
item: element,
|
|
||||||
showBadge: false,
|
|
||||||
showHideButton: false,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 54,
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment:
|
|
||||||
CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
element.alt,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
maxLines: 1,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontFamily: 'monospace'),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'${fileType[0].toUpperCase()}${fileType.substring(1)} · ${_formatBytes(element.size)}',
|
|
||||||
style:
|
|
||||||
const TextStyle(fontSize: 12),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
shape: const CircleBorder(),
|
|
||||||
foregroundColor:
|
|
||||||
Theme.of(context).primaryColor,
|
|
||||||
),
|
|
||||||
icon: const Icon(Icons.more_horiz),
|
|
||||||
onPressed: () => showEdit(element, index),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
).paddingSymmetric(vertical: 8, horizontal: 16),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
@ -361,42 +360,44 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
alignment: WrapAlignment.center,
|
alignment: WrapAlignment.center,
|
||||||
runAlignment: WrapAlignment.center,
|
runAlignment: WrapAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
if (PlatformInfo.isDesktop || PlatformInfo.isIOS || PlatformInfo.isWeb)
|
if (PlatformInfo.isDesktop ||
|
||||||
|
PlatformInfo.isIOS ||
|
||||||
|
PlatformInfo.isWeb)
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
icon: const Icon(Icons.paste),
|
icon: const Icon(Icons.paste),
|
||||||
label: Text('attachmentAddClipboard'.tr),
|
label: Text('attachmentAddClipboard'.tr),
|
||||||
style: const ButtonStyle(visualDensity: density),
|
style: const ButtonStyle(visualDensity: density),
|
||||||
onPressed: () => pasteFileToUpload(),
|
onPressed: () => _pasteFileToUpload(),
|
||||||
),
|
),
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
icon: const Icon(Icons.add_photo_alternate),
|
icon: const Icon(Icons.add_photo_alternate),
|
||||||
label: Text('attachmentAddGalleryPhoto'.tr),
|
label: Text('attachmentAddGalleryPhoto'.tr),
|
||||||
style: const ButtonStyle(visualDensity: density),
|
style: const ButtonStyle(visualDensity: density),
|
||||||
onPressed: () => pickPhotoToUpload(),
|
onPressed: () => _pickPhotoToUpload(),
|
||||||
),
|
),
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
icon: const Icon(Icons.add_road),
|
icon: const Icon(Icons.add_road),
|
||||||
label: Text('attachmentAddGalleryVideo'.tr),
|
label: Text('attachmentAddGalleryVideo'.tr),
|
||||||
style: const ButtonStyle(visualDensity: density),
|
style: const ButtonStyle(visualDensity: density),
|
||||||
onPressed: () => pickVideoToUpload(),
|
onPressed: () => _pickVideoToUpload(),
|
||||||
),
|
),
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
icon: const Icon(Icons.photo_camera_back),
|
icon: const Icon(Icons.photo_camera_back),
|
||||||
label: Text('attachmentAddCameraPhoto'.tr),
|
label: Text('attachmentAddCameraPhoto'.tr),
|
||||||
style: const ButtonStyle(visualDensity: density),
|
style: const ButtonStyle(visualDensity: density),
|
||||||
onPressed: () => takeMediaToUpload(false),
|
onPressed: () => _takeMediaToUpload(false),
|
||||||
),
|
),
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
icon: const Icon(Icons.video_camera_back_outlined),
|
icon: const Icon(Icons.video_camera_back_outlined),
|
||||||
label: Text('attachmentAddCameraVideo'.tr),
|
label: Text('attachmentAddCameraVideo'.tr),
|
||||||
style: const ButtonStyle(visualDensity: density),
|
style: const ButtonStyle(visualDensity: density),
|
||||||
onPressed: () => takeMediaToUpload(true),
|
onPressed: () => _takeMediaToUpload(true),
|
||||||
),
|
),
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
icon: const Icon(Icons.file_present_rounded),
|
icon: const Icon(Icons.file_present_rounded),
|
||||||
label: Text('attachmentAddFile'.tr),
|
label: Text('attachmentAddFile'.tr),
|
||||||
style: const ButtonStyle(visualDensity: density),
|
style: const ButtonStyle(visualDensity: density),
|
||||||
onPressed: () => pickFileToUpload(),
|
onPressed: () => _pickFileToUpload(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
).paddingSymmetric(horizontal: 12),
|
).paddingSymmetric(horizontal: 12),
|
||||||
@ -405,7 +406,6 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,19 +16,18 @@ import 'package:solian/widgets/attachments/attachment_item.dart';
|
|||||||
import 'package:url_launcher/url_launcher_string.dart';
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
import 'package:path/path.dart' show extension;
|
import 'package:path/path.dart' show extension;
|
||||||
|
|
||||||
class AttachmentListFullScreen extends StatefulWidget {
|
class AttachmentFullScreen extends StatefulWidget {
|
||||||
final String parentId;
|
final String parentId;
|
||||||
final Attachment item;
|
final Attachment item;
|
||||||
|
|
||||||
const AttachmentListFullScreen(
|
const AttachmentFullScreen(
|
||||||
{super.key, required this.parentId, required this.item});
|
{super.key, required this.parentId, required this.item});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AttachmentListFullScreen> createState() =>
|
State<AttachmentFullScreen> createState() => _AttachmentFullScreenState();
|
||||||
_AttachmentListFullScreenState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AttachmentListFullScreenState extends State<AttachmentListFullScreen> {
|
class _AttachmentFullScreenState extends State<AttachmentFullScreen> {
|
||||||
bool _showDetails = true;
|
bool _showDetails = true;
|
||||||
|
|
||||||
bool _isDownloading = false;
|
bool _isDownloading = false;
|
@ -9,7 +9,7 @@ import 'package:get/get.dart';
|
|||||||
import 'package:solian/models/attachment.dart';
|
import 'package:solian/models/attachment.dart';
|
||||||
import 'package:solian/widgets/attachments/attachment_item.dart';
|
import 'package:solian/widgets/attachments/attachment_item.dart';
|
||||||
import 'package:solian/providers/content/attachment.dart';
|
import 'package:solian/providers/content/attachment.dart';
|
||||||
import 'package:solian/widgets/attachments/attachment_list_fullscreen.dart';
|
import 'package:solian/widgets/attachments/attachment_fullscreen.dart';
|
||||||
|
|
||||||
class AttachmentList extends StatefulWidget {
|
class AttachmentList extends StatefulWidget {
|
||||||
final String parentId;
|
final String parentId;
|
||||||
@ -320,7 +320,7 @@ class AttachmentListEntry extends StatelessWidget {
|
|||||||
onReveal(true);
|
onReveal(true);
|
||||||
} else if (['image'].contains(item!.mimetype.split('/').first)) {
|
} else if (['image'].contains(item!.mimetype.split('/').first)) {
|
||||||
context.pushTransparentRoute(
|
context.pushTransparentRoute(
|
||||||
AttachmentListFullScreen(
|
AttachmentFullScreen(
|
||||||
parentId: parentId,
|
parentId: parentId,
|
||||||
item: item!,
|
item: item!,
|
||||||
),
|
),
|
||||||
|
@ -46,7 +46,6 @@ class _ChatMessageInputState extends State<ChatMessageInput> {
|
|||||||
void _editAttachments() {
|
void _editAttachments() {
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
|
||||||
builder: (context) => AttachmentEditorPopup(
|
builder: (context) => AttachmentEditorPopup(
|
||||||
usage: 'm.attachment',
|
usage: 'm.attachment',
|
||||||
current: _attachments,
|
current: _attachments,
|
||||||
|
Loading…
Reference in New Issue
Block a user