From 27b3ca25b71b8afc3714aee3b24320b0b2761bea Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Mon, 6 Oct 2025 12:24:09 +0800 Subject: [PATCH] :lipstick: Optimize compose --- lib/screens/posts/compose.dart | 520 ++++------------------ lib/screens/posts/compose_article.dart | 79 +--- lib/widgets/post/compose_form_fields.dart | 9 +- lib/widgets/post/compose_toolbar.dart | 198 +++++--- 4 files changed, 235 insertions(+), 571 deletions(-) diff --git a/lib/screens/posts/compose.dart b/lib/screens/posts/compose.dart index 097ad191..9488807e 100644 --- a/lib/screens/posts/compose.dart +++ b/lib/screens/posts/compose.dart @@ -8,19 +8,18 @@ import 'package:island/models/file.dart'; import 'package:island/models/post.dart'; import 'package:island/screens/creators/publishers_form.dart'; import 'package:island/screens/posts/compose_article.dart'; -import 'package:island/services/responsive.dart'; +import 'package:island/screens/posts/post_detail.dart'; +import 'package:island/services/compose_storage_db.dart'; import 'package:island/widgets/app_scaffold.dart'; -import 'package:island/widgets/attachment_uploader.dart'; -import 'package:island/widgets/content/attachment_preview.dart'; import 'package:island/widgets/content/cloud_files.dart'; +import 'package:island/widgets/post/compose_attachments.dart'; +import 'package:island/widgets/post/compose_form_fields.dart'; +import 'package:island/widgets/post/compose_info_banner.dart'; +import 'package:island/widgets/post/compose_settings_sheet.dart'; import 'package:island/widgets/post/compose_shared.dart'; +import 'package:island/widgets/post/compose_toolbar.dart'; import 'package:island/widgets/post/post_item.dart'; import 'package:island/widgets/post/publishers_modal.dart'; -import 'package:island/screens/posts/post_detail.dart'; -import 'package:island/widgets/post/compose_settings_sheet.dart'; -import 'package:island/services/compose_storage_db.dart'; -// DraftManagerSheet is now imported through compose_toolbar.dart -import 'package:island/widgets/post/compose_toolbar.dart'; import 'package:material_symbols_icons/symbols.dart'; import 'package:styled_widget/styled_widget.dart'; @@ -92,9 +91,6 @@ class PostComposeScreen extends HookConsumerWidget { return ArticleComposeScreen(originalPost: originalPost); } - // Otherwise, continue with regular post compose - final theme = Theme.of(context); - // When editing, preserve the original replied/forwarded post references final effectiveRepliedPost = repliedPost ?? originalPost?.repliedPost; final effectiveForwardedPost = forwardedPost ?? originalPost?.forwardedPost; @@ -210,109 +206,6 @@ class PostComposeScreen extends HookConsumerWidget { ); } - Widget buildWideAttachmentGrid() { - return GridView.builder( - shrinkWrap: true, - padding: EdgeInsets.zero, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - crossAxisSpacing: 8, - mainAxisSpacing: 8, - ), - itemCount: state.attachments.value.length, - itemBuilder: (context, idx) { - final progressMap = state.attachmentProgress.value; - return AttachmentPreview( - item: state.attachments.value[idx], - progress: progressMap[idx], - onRequestUpload: () async { - final config = await showModalBottomSheet( - context: context, - isScrollControlled: true, - builder: - (context) => AttachmentUploaderSheet( - ref: ref, - state: state, - index: idx, - ), - ); - if (config != null) { - await ComposeLogic.uploadAttachment( - ref, - state, - idx, - poolId: config.poolId, - ); - } - }, - onDelete: () => ComposeLogic.deleteAttachment(ref, state, idx), - onUpdate: - (value) => ComposeLogic.updateAttachment(state, value, idx), - onMove: (delta) { - state.attachments.value = ComposeLogic.moveAttachment( - state.attachments.value, - idx, - delta, - ); - }, - ); - }, - ); - } - - Widget buildNarrowAttachmentList() { - return Column( - children: [ - for (var idx = 0; idx < state.attachments.value.length; idx++) - Container( - margin: const EdgeInsets.only(bottom: 8), - child: () { - final progressMap = state.attachmentProgress.value; - return AttachmentPreview( - item: state.attachments.value[idx], - progress: progressMap[idx], - onRequestUpload: () async { - final config = - await showModalBottomSheet( - context: context, - isScrollControlled: true, - builder: - (context) => AttachmentUploaderSheet( - ref: ref, - state: state, - index: idx, - ), - ); - if (config != null) { - await ComposeLogic.uploadAttachment( - ref, - state, - idx, - poolId: config.poolId, - ); - } - }, - onDelete: - () => ComposeLogic.deleteAttachment(ref, state, idx), - onUpdate: - (value) => - ComposeLogic.updateAttachment(state, value, idx), - onMove: (delta) { - state.attachments.value = ComposeLogic.moveAttachment( - state.attachments.value, - idx, - delta, - ); - }, - ); - }(), - ), - ], - ); - } - - // Build UI return PopScope( onPopInvoked: (_) { if (originalPost == null) { @@ -362,7 +255,57 @@ class PostComposeScreen extends HookConsumerWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ // Reply/Forward info section - _buildInfoBanner(context), + ComposeInfoBanner( + originalPost: originalPost, + replyingTo: repliedPost, + forwardingTo: forwardedPost, + onReferencePostTap: (context, post) { + showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: + (context) => DraggableScrollableSheet( + initialChildSize: 0.7, + maxChildSize: 0.9, + minChildSize: 0.5, + builder: + (context, scrollController) => Container( + decoration: BoxDecoration( + color: + Theme.of(context).scaffoldBackgroundColor, + borderRadius: const BorderRadius.vertical( + top: Radius.circular(16), + ), + ), + child: Column( + children: [ + Container( + width: 40, + height: 4, + margin: const EdgeInsets.symmetric( + vertical: 8, + ), + decoration: BoxDecoration( + color: + Theme.of(context).colorScheme.outline, + borderRadius: BorderRadius.circular(2), + ), + ), + Expanded( + child: SingleChildScrollView( + controller: scrollController, + padding: const EdgeInsets.all(16), + child: PostItem(item: post), + ), + ), + ], + ), + ), + ), + ); + }, + ), // Main content area Expanded( @@ -414,78 +357,27 @@ class PostComposeScreen extends HookConsumerWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - TextField( - controller: state.titleController, - decoration: InputDecoration( - hintText: 'postTitle'.tr(), - border: InputBorder.none, - isCollapsed: true, - contentPadding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - ), - style: theme.textTheme.titleMedium, - onTapOutside: - (_) => - FocusManager.instance.primaryFocus - ?.unfocus(), + ComposeFormFields( + state: state, + showPublisherAvatar: false, + onPublisherTap: () { + showModalBottomSheet( + isScrollControlled: true, + context: context, + builder: + (context) => const PublisherModal(), + ).then((value) { + if (value != null) { + state.currentPublisher.value = value; + } + }); + }, ), - TextField( - controller: state.descriptionController, - decoration: InputDecoration( - hintText: 'postDescription'.tr(), - border: InputBorder.none, - isCollapsed: true, - contentPadding: const EdgeInsets.fromLTRB( - 8, - 4, - 8, - 12, - ), - ), - style: theme.textTheme.bodyMedium, - minLines: 1, - maxLines: 3, - onTapOutside: - (_) => - FocusManager.instance.primaryFocus - ?.unfocus(), - ), - // Content field with borderless design - TextField( - controller: state.contentController, - style: theme.textTheme.bodyMedium, - decoration: InputDecoration( - border: InputBorder.none, - hintText: 'postContent'.tr(), - isCollapsed: true, - contentPadding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - ), - maxLines: null, - onTapOutside: - (_) => - FocusManager.instance.primaryFocus - ?.unfocus(), - ), - const Gap(8), - - // Attachments preview - if (state.attachments.value.isNotEmpty) - LayoutBuilder( - builder: (context, constraints) { - final isWide = isWideScreen(context); - return isWide - ? buildWideAttachmentGrid() - : buildNarrowAttachmentList(); - }, - ) - else - const SizedBox.shrink(), + ComposeAttachments( + state: state, + isCompact: false, + ), ], ), ), @@ -503,262 +395,4 @@ class PostComposeScreen extends HookConsumerWidget { ), ); } - - Widget _buildInfoBanner(BuildContext context) { - // When editing, preserve the original replied/forwarded post references - final effectiveRepliedPost = - initialState?.replyingTo ?? originalPost?.repliedPost; - final effectiveForwardedPost = - initialState?.forwardingTo ?? originalPost?.forwardedPost; - - // Show editing banner when editing a post - if (originalPost != null) { - return Column( - children: [ - Container( - width: double.infinity, - color: Theme.of(context).colorScheme.primaryContainer, - child: Row( - children: [ - Icon( - Symbols.edit, - size: 16, - color: Theme.of(context).colorScheme.onPrimaryContainer, - ), - const Gap(8), - Text( - 'postEditing'.tr(), - style: Theme.of(context).textTheme.labelMedium?.copyWith( - color: Theme.of(context).colorScheme.onPrimaryContainer, - ), - ), - ], - ).padding(horizontal: 16, vertical: 8), - ), - // Show reply/forward banners below editing banner if they exist - if (effectiveRepliedPost != null) - Container( - width: double.infinity, - color: Theme.of(context).colorScheme.surfaceContainerHigh, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Symbols.reply, size: 16), - const Gap(4), - Text( - 'postReplyingTo'.tr(), - style: Theme.of(context).textTheme.labelMedium, - ), - ], - ), - const Gap(8), - _buildCompactReferencePost(context, effectiveRepliedPost), - ], - ).padding(all: 16), - ), - if (effectiveForwardedPost != null) - Container( - width: double.infinity, - color: Theme.of(context).colorScheme.surfaceContainerHigh, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Symbols.forward, size: 16), - const Gap(4), - Text( - 'postForwardingTo'.tr(), - style: Theme.of(context).textTheme.labelMedium, - ), - ], - ), - const Gap(8), - _buildCompactReferencePost(context, effectiveForwardedPost), - ], - ).padding(all: 16), - ), - ], - ); - } - - // Show banner for replies (including when editing a reply) - if (effectiveRepliedPost != null) { - return Container( - width: double.infinity, - color: Theme.of(context).colorScheme.surfaceContainerHigh, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Symbols.reply, size: 16), - const Gap(4), - Text( - 'postReplyingTo'.tr(), - style: Theme.of(context).textTheme.labelMedium, - ), - ], - ), - const Gap(8), - _buildCompactReferencePost(context, effectiveRepliedPost), - ], - ).padding(all: 16), - ); - } - - // Show banner for forwards (including when editing a forward) - if (effectiveForwardedPost != null) { - return Container( - width: double.infinity, - color: Theme.of(context).colorScheme.surfaceContainerHigh, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Symbols.forward, size: 16), - const Gap(4), - Text( - 'postForwardingTo'.tr(), - style: Theme.of(context).textTheme.labelMedium, - ), - ], - ), - const Gap(8), - _buildCompactReferencePost(context, effectiveForwardedPost), - ], - ).padding(all: 16), - ); - } - - return const SizedBox.shrink(); - } - - Widget _buildCompactReferencePost(BuildContext context, SnPost post) { - return GestureDetector( - onTap: () { - showModalBottomSheet( - context: context, - isScrollControlled: true, - backgroundColor: Colors.transparent, - builder: - (context) => DraggableScrollableSheet( - initialChildSize: 0.7, - maxChildSize: 0.9, - minChildSize: 0.5, - builder: - (context, scrollController) => Container( - decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor, - borderRadius: const BorderRadius.vertical( - top: Radius.circular(16), - ), - ), - child: Column( - children: [ - Container( - width: 40, - height: 4, - margin: const EdgeInsets.symmetric(vertical: 8), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.outline, - borderRadius: BorderRadius.circular(2), - ), - ), - Expanded( - child: SingleChildScrollView( - controller: scrollController, - padding: const EdgeInsets.all(16), - child: PostItem(item: post), - ), - ), - ], - ), - ), - ), - ); - }, - child: Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - borderRadius: BorderRadius.circular(8), - border: Border.all( - color: Theme.of(context).colorScheme.outline.withOpacity(0.3), - ), - ), - child: Row( - children: [ - ProfilePictureWidget( - fileId: post.publisher.picture?.id, - radius: 16, - ), - const Gap(8), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - post.publisher.nick, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - ), - ), - if (post.title?.isNotEmpty ?? false) - Text( - post.title!, - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 13, - color: Theme.of(context).colorScheme.onSurface, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - if (post.content?.isNotEmpty ?? false) - Text( - post.content!, - style: TextStyle( - fontSize: 12, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - if (post.attachments.isNotEmpty) - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - Symbols.attach_file, - size: 12, - color: Theme.of(context).colorScheme.secondary, - ), - const Gap(4), - Text( - 'postHasAttachments'.plural(post.attachments.length), - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontSize: 11, - ), - ), - ], - ), - ], - ), - ), - Icon( - Symbols.open_in_full, - size: 16, - color: Theme.of(context).colorScheme.outline, - ), - ], - ), - ), - ); - } } diff --git a/lib/screens/posts/compose_article.dart b/lib/screens/posts/compose_article.dart index ae90287c..39abf0c1 100644 --- a/lib/screens/posts/compose_article.dart +++ b/lib/screens/posts/compose_article.dart @@ -7,21 +7,20 @@ import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:island/models/file.dart'; import 'package:island/models/post.dart'; - import 'package:island/screens/creators/publishers_form.dart'; +import 'package:island/screens/posts/post_detail.dart'; +import 'package:island/services/compose_storage_db.dart'; import 'package:island/services/responsive.dart'; import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/attachment_uploader.dart'; -import 'package:island/screens/posts/post_detail.dart'; import 'package:island/widgets/content/attachment_preview.dart'; import 'package:island/widgets/content/cloud_files.dart'; import 'package:island/widgets/content/markdown.dart'; +import 'package:island/widgets/post/compose_form_fields.dart'; import 'package:island/widgets/post/compose_shared.dart'; import 'package:island/widgets/post/compose_settings_sheet.dart'; -import 'package:island/services/compose_storage_db.dart'; import 'package:island/widgets/post/compose_toolbar.dart'; import 'package:island/widgets/post/publishers_modal.dart'; - import 'package:material_symbols_icons/symbols.dart'; import 'package:styled_widget/styled_widget.dart'; @@ -233,64 +232,20 @@ class ArticleComposeScreen extends HookConsumerWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - TextField( - controller: state.titleController, - decoration: InputDecoration( - hintText: 'postTitle'.tr(), - border: InputBorder.none, - isCollapsed: true, - contentPadding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - ), - style: theme.textTheme.titleMedium, - onTapOutside: - (_) => FocusManager.instance.primaryFocus?.unfocus(), - ), - TextField( - controller: state.descriptionController, - decoration: InputDecoration( - hintText: 'postDescription'.tr(), - border: InputBorder.none, - isCollapsed: true, - contentPadding: const EdgeInsets.fromLTRB(8, 4, 8, 12), - ), - style: theme.textTheme.bodyMedium, - minLines: 1, - maxLines: 3, - onTapOutside: - (_) => FocusManager.instance.primaryFocus?.unfocus(), - ), - Expanded( - child: KeyboardListener( - focusNode: FocusNode(), - onKeyEvent: - (event) => ComposeLogic.handleKeyPress( - event, - state, - ref, - context, - originalPost: originalPost, - ), - child: TextField( - controller: state.contentController, - style: theme.textTheme.bodyMedium, - decoration: InputDecoration( - border: InputBorder.none, - hintText: 'postContent'.tr(), - contentPadding: const EdgeInsets.symmetric( - vertical: 16, - horizontal: 8, - ), - ), - maxLines: null, - expands: true, - textAlignVertical: TextAlignVertical.top, - onTapOutside: - (_) => FocusManager.instance.primaryFocus?.unfocus(), - ), - ), + ComposeFormFields( + state: state, + showPublisherAvatar: false, + onPublisherTap: () { + showModalBottomSheet( + isScrollControlled: true, + context: context, + builder: (context) => const PublisherModal(), + ).then((value) { + if (value != null) { + state.currentPublisher.value = value; + } + }); + }, ), // Attachments preview diff --git a/lib/widgets/post/compose_form_fields.dart b/lib/widgets/post/compose_form_fields.dart index dfe7d084..fc02b5aa 100644 --- a/lib/widgets/post/compose_form_fields.dart +++ b/lib/widgets/post/compose_form_fields.dart @@ -1,3 +1,4 @@ +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:island/widgets/content/cloud_files.dart'; import 'package:island/widgets/post/compose_shared.dart'; @@ -29,6 +30,7 @@ class ComposeFormFields extends StatelessWidget { // Publisher profile picture if (showPublisherAvatar) GestureDetector( + onTap: onPublisherTap, child: ProfilePictureWidget( fileId: state.currentPublisher.value?.picture?.id, radius: 20, @@ -37,7 +39,6 @@ class ComposeFormFields extends StatelessWidget { ? Icons.question_mark : null, ), - onTap: onPublisherTap, ), // Post content form @@ -79,7 +80,7 @@ class ComposeFormFields extends StatelessWidget { controller: state.titleController, enabled: enabled && state.currentPublisher.value != null, decoration: InputDecoration( - hintText: 'postTitle', + hintText: 'postTitle'.tr(), border: InputBorder.none, isCollapsed: true, contentPadding: const EdgeInsets.symmetric( @@ -97,7 +98,7 @@ class ComposeFormFields extends StatelessWidget { controller: state.descriptionController, enabled: enabled && state.currentPublisher.value != null, decoration: InputDecoration( - hintText: 'postDescription', + hintText: 'postDescription'.tr(), border: InputBorder.none, isCollapsed: true, contentPadding: const EdgeInsets.fromLTRB(8, 4, 8, 12), @@ -116,7 +117,7 @@ class ComposeFormFields extends StatelessWidget { style: theme.textTheme.bodyMedium, decoration: InputDecoration( border: InputBorder.none, - hintText: 'postContent', + hintText: 'postContent'.tr(), isCollapsed: true, contentPadding: const EdgeInsets.symmetric( vertical: 8, diff --git a/lib/widgets/post/compose_toolbar.dart b/lib/widgets/post/compose_toolbar.dart index a0554831..0cb081ca 100644 --- a/lib/widgets/post/compose_toolbar.dart +++ b/lib/widgets/post/compose_toolbar.dart @@ -96,45 +96,86 @@ class ComposeToolbar extends HookConsumerWidget { scrollDirection: Axis.horizontal, child: Row( children: [ - IconButton( - onPressed: pickPhotoMedia, - tooltip: 'addPhoto'.tr(), - icon: const Icon(Symbols.add_a_photo), - color: colorScheme.primary, - visualDensity: const VisualDensity( - horizontal: -4, - vertical: -2, - ), - ), - IconButton( - onPressed: pickVideoMedia, - tooltip: 'addVideo'.tr(), - icon: const Icon(Symbols.videocam), - color: colorScheme.primary, - visualDensity: const VisualDensity( - horizontal: -4, - vertical: -2, - ), - ), - IconButton( - onPressed: addAudio, - tooltip: 'addAudio'.tr(), - icon: const Icon(Symbols.mic), - color: colorScheme.primary, - visualDensity: const VisualDensity( - horizontal: -4, - vertical: -2, - ), - ), - IconButton( - onPressed: pickGeneralFile, - tooltip: 'uploadFile'.tr(), - icon: const Icon(Symbols.file_upload), - color: colorScheme.primary, - visualDensity: const VisualDensity( - horizontal: -4, - vertical: -2, - ), + MenuAnchor( + builder: + (context, controller, child) => IconButton( + onPressed: () { + if (controller.isOpen) { + controller.close(); + } else { + controller.open(); + } + }, + tooltip: 'uploadFile'.tr(), + icon: const Icon(Symbols.file_upload), + color: colorScheme.primary, + visualDensity: const VisualDensity( + horizontal: -4, + vertical: -2, + ), + ), + menuChildren: [ + MenuItemButton( + onPressed: () { + pickPhotoMedia(); + }, + style: ButtonStyle( + padding: WidgetStatePropertyAll( + EdgeInsets.symmetric( + horizontal: 16, + vertical: 16, + ), + ), + ), + leadingIcon: const Icon(Symbols.add_a_photo), + child: Text('addPhoto'.tr()), + ), + MenuItemButton( + onPressed: () { + pickVideoMedia(); + }, + leadingIcon: const Icon(Symbols.videocam), + style: ButtonStyle( + padding: WidgetStatePropertyAll( + EdgeInsets.symmetric( + horizontal: 16, + vertical: 16, + ), + ), + ), + child: Text('addVideo'.tr()), + ), + MenuItemButton( + onPressed: () { + addAudio(); + }, + leadingIcon: const Icon(Symbols.mic), + style: ButtonStyle( + padding: WidgetStatePropertyAll( + EdgeInsets.symmetric( + horizontal: 16, + vertical: 16, + ), + ), + ), + child: Text('addAudio'.tr()), + ), + MenuItemButton( + onPressed: () { + pickGeneralFile(); + }, + leadingIcon: const Icon(Symbols.file_upload), + style: ButtonStyle( + padding: WidgetStatePropertyAll( + EdgeInsets.symmetric( + horizontal: 16, + vertical: 16, + ), + ), + ), + child: Text('uploadFile'.tr()), + ), + ], ), IconButton( onPressed: linkAttachment, @@ -249,29 +290,62 @@ class ComposeToolbar extends HookConsumerWidget { scrollDirection: Axis.horizontal, child: Row( children: [ - IconButton( - onPressed: pickPhotoMedia, - tooltip: 'addPhoto'.tr(), - icon: const Icon(Symbols.add_a_photo), - color: colorScheme.primary, - ), - IconButton( - onPressed: pickVideoMedia, - tooltip: 'addVideo'.tr(), - icon: const Icon(Symbols.videocam), - color: colorScheme.primary, - ), - IconButton( - onPressed: addAudio, - tooltip: 'addAudio'.tr(), - icon: const Icon(Symbols.mic), - color: colorScheme.primary, - ), - IconButton( - onPressed: pickGeneralFile, - tooltip: 'uploadFile'.tr(), - icon: const Icon(Symbols.file_upload), - color: colorScheme.primary, + MenuAnchor( + builder: + (context, controller, child) => IconButton( + onPressed: () { + if (controller.isOpen) { + controller.close(); + } else { + controller.open(); + } + }, + tooltip: 'uploadFile'.tr(), + icon: const Icon(Symbols.file_upload), + color: colorScheme.primary, + ), + menuChildren: [ + MenuItemButton( + onPressed: () { + pickPhotoMedia(); + }, + leadingIcon: const Icon(Symbols.add_a_photo), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Text('addPhoto'.tr()), + ), + ), + MenuItemButton( + onPressed: () { + pickVideoMedia(); + }, + leadingIcon: const Icon(Symbols.videocam), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Text('addVideo'.tr()), + ), + ), + MenuItemButton( + onPressed: () { + addAudio(); + }, + leadingIcon: const Icon(Symbols.mic), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Text('addAudio'.tr()), + ), + ), + MenuItemButton( + onPressed: () { + pickGeneralFile(); + }, + leadingIcon: const Icon(Symbols.file_upload), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Text('uploadFile'.tr()), + ), + ), + ], ), IconButton( onPressed: linkAttachment,