From 466e354679bf92b5a986226191386f3c2ab11af1 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sun, 17 Aug 2025 13:02:52 +0800 Subject: [PATCH] :lipstick: Optimize attachment in article --- assets/i18n/en-US.json | 5 +- assets/i18n/zh-CN.json | 4 +- lib/screens/posts/compose_article.dart | 146 +++++++++++--------- lib/widgets/content/attachment_preview.dart | 24 ++-- 4 files changed, 103 insertions(+), 76 deletions(-) diff --git a/assets/i18n/en-US.json b/assets/i18n/en-US.json index 6cd6fdc2..498fe6c1 100644 --- a/assets/i18n/en-US.json +++ b/assets/i18n/en-US.json @@ -841,5 +841,8 @@ "messageJumpNotLoaded": "The referenced message was not loaded, unable to jump to it.", "postUnlinkRealm": "No linked realm", "postSlug": "Slug", - "postSlugHint": "The slug can be used to access your post via URL in the webpage, it should be publisher-wide unique." + "postSlugHint": "The slug can be used to access your post via URL in the webpage, it should be publisher-wide unique.", + "attachmentOnDevice": "On-device", + "attachmentOnCloud": "On-cloud", + "attachments": "Attachments" } diff --git a/assets/i18n/zh-CN.json b/assets/i18n/zh-CN.json index b8f1207a..af10e589 100644 --- a/assets/i18n/zh-CN.json +++ b/assets/i18n/zh-CN.json @@ -816,5 +816,7 @@ "messageJumpNotLoaded": "引用的消息没有被加载,无法跳转。", "postUnlinkRealm": "不关联领域", "postSlug": "别名", - "postSlugHint": "这个别名可以用于在网页通过 URL 浏览到你的帖子,它应该在同一发布者中是唯一。" + "postSlugHint": "这个别名可以用于在网页通过 URL 浏览到你的帖子,它应该在同一发布者中是唯一。", + "attachmentOnDevice": "离线", + "attachmentOnCloud": "在线" } diff --git a/lib/screens/posts/compose_article.dart b/lib/screens/posts/compose_article.dart index 4b3e20b8..c848d131 100644 --- a/lib/screens/posts/compose_article.dart +++ b/lib/screens/posts/compose_article.dart @@ -89,6 +89,9 @@ class ArticleComposeScreen extends HookConsumerWidget { }, [state]); final showPreview = useState(false); + final isAttachmentsExpanded = useState( + true, + ); // New state for attachments section // Initialize publisher once when data is available useEffect(() { @@ -297,71 +300,86 @@ class ArticleComposeScreen extends HookConsumerWidget { valueListenable: state.attachments, builder: (context, attachments, _) { if (attachments.isEmpty) return const SizedBox.shrink(); - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Gap(16), - Text( - 'articleAttachmentHint'.tr(), - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ).padding(bottom: 8), - ValueListenableBuilder>( - valueListenable: state.attachmentProgress, - builder: (context, progressMap, _) { - return Wrap( - runSpacing: 8, - spacing: 8, - children: [ - for (var idx = 0; idx < attachments.length; idx++) - SizedBox( - width: 280, - height: 280, - child: AttachmentPreview( - item: attachments[idx], - progress: progressMap[idx], - onRequestUpload: - () => ComposeLogic.uploadAttachment( - ref, - state, - idx, - ), - onUpdate: - (value) => - ComposeLogic.updateAttachment( - state, - value, - idx, - ), - onDelete: - () => ComposeLogic.deleteAttachment( - ref, - state, - idx, - ), - onMove: (delta) { - state - .attachments - .value = ComposeLogic.moveAttachment( - state.attachments.value, - idx, - delta, - ); - }, - onInsert: - () => ComposeLogic.insertAttachment( - ref, - state, - idx, - ), - ), - ), - ], - ); - }, + return Theme( + data: Theme.of( + context, + ).copyWith(dividerColor: Colors.transparent), + child: ExpansionTile( + initiallyExpanded: isAttachmentsExpanded.value, + onExpansionChanged: (expanded) { + isAttachmentsExpanded.value = expanded; + }, + title: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('attachments').tr(), + Text( + 'articleAttachmentHint'.tr(), + style: Theme.of( + context, + ).textTheme.bodySmall?.copyWith( + color: + Theme.of( + context, + ).colorScheme.onSurfaceVariant, + ), + ), + ], ), - ], + children: [ + ValueListenableBuilder>( + valueListenable: state.attachmentProgress, + builder: (context, progressMap, _) { + return Wrap( + runSpacing: 8, + spacing: 8, + children: [ + for ( + var idx = 0; + idx < attachments.length; + idx++ + ) + SizedBox( + width: 180, + height: 180, + child: AttachmentPreview( + isCompact: true, + item: attachments[idx], + progress: progressMap[idx], + onRequestUpload: + () => ComposeLogic.uploadAttachment( + ref, + state, + idx, + ), + onUpdate: + (value) => + ComposeLogic.updateAttachment( + state, + value, + idx, + ), + onDelete: + () => ComposeLogic.deleteAttachment( + ref, + state, + idx, + ), + onInsert: + () => ComposeLogic.insertAttachment( + ref, + state, + idx, + ), + ), + ), + ], + ); + }, + ), + Gap(16), + ], + ), ); }, ), diff --git a/lib/widgets/content/attachment_preview.dart b/lib/widgets/content/attachment_preview.dart index 713459d2..42164f5e 100644 --- a/lib/widgets/content/attachment_preview.dart +++ b/lib/widgets/content/attachment_preview.dart @@ -88,6 +88,7 @@ class AttachmentPreview extends HookConsumerWidget { final Function? onInsert; final Function(UniversalFile)? onUpdate; final Function? onRequestUpload; + final bool isCompact; const AttachmentPreview({ super.key, @@ -98,6 +99,7 @@ class AttachmentPreview extends HookConsumerWidget { this.onDelete, this.onUpdate, this.onInsert, + this.isCompact = false, }); // GlobalKey for selector @@ -458,11 +460,12 @@ class AttachmentPreview extends HookConsumerWidget { size: 16, color: Colors.white, ), - const Gap(8), - Text( - 'On-cloud', - style: TextStyle(color: Colors.white), - ), + if (!isCompact) const Gap(8), + if (!isCompact) + Text( + 'attachmentOnCloud'.tr(), + style: TextStyle(color: Colors.white), + ), ], ) : Row( @@ -473,11 +476,12 @@ class AttachmentPreview extends HookConsumerWidget { size: 16, color: Colors.white, ), - const Gap(8), - Text( - 'On-device', - style: TextStyle(color: Colors.white), - ), + if (!isCompact) const Gap(8), + if (!isCompact) + Text( + 'attachmentOnDevice'.tr(), + style: TextStyle(color: Colors.white), + ), ], ), ),