💄 Optimize attachment in article

This commit is contained in:
2025-08-17 13:02:52 +08:00
parent 5d4b896f70
commit 466e354679
4 changed files with 103 additions and 76 deletions

View File

@@ -841,5 +841,8 @@
"messageJumpNotLoaded": "The referenced message was not loaded, unable to jump to it.", "messageJumpNotLoaded": "The referenced message was not loaded, unable to jump to it.",
"postUnlinkRealm": "No linked realm", "postUnlinkRealm": "No linked realm",
"postSlug": "Slug", "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"
} }

View File

@@ -816,5 +816,7 @@
"messageJumpNotLoaded": "引用的消息没有被加载,无法跳转。", "messageJumpNotLoaded": "引用的消息没有被加载,无法跳转。",
"postUnlinkRealm": "不关联领域", "postUnlinkRealm": "不关联领域",
"postSlug": "别名", "postSlug": "别名",
"postSlugHint": "这个别名可以用于在网页通过 URL 浏览到你的帖子,它应该在同一发布者中是唯一。" "postSlugHint": "这个别名可以用于在网页通过 URL 浏览到你的帖子,它应该在同一发布者中是唯一。",
"attachmentOnDevice": "离线",
"attachmentOnCloud": "在线"
} }

View File

@@ -89,6 +89,9 @@ class ArticleComposeScreen extends HookConsumerWidget {
}, [state]); }, [state]);
final showPreview = useState(false); final showPreview = useState(false);
final isAttachmentsExpanded = useState(
true,
); // New state for attachments section
// Initialize publisher once when data is available // Initialize publisher once when data is available
useEffect(() { useEffect(() {
@@ -297,16 +300,33 @@ class ArticleComposeScreen extends HookConsumerWidget {
valueListenable: state.attachments, valueListenable: state.attachments,
builder: (context, attachments, _) { builder: (context, attachments, _) {
if (attachments.isEmpty) return const SizedBox.shrink(); if (attachments.isEmpty) return const SizedBox.shrink();
return Column( 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, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const Gap(16), Text('attachments').tr(),
Text( Text(
'articleAttachmentHint'.tr(), 'articleAttachmentHint'.tr(),
style: Theme.of(context).textTheme.bodySmall?.copyWith( style: Theme.of(
color: Theme.of(context).colorScheme.onSurfaceVariant, context,
).textTheme.bodySmall?.copyWith(
color:
Theme.of(
context,
).colorScheme.onSurfaceVariant,
), ),
).padding(bottom: 8), ),
],
),
children: [
ValueListenableBuilder<Map<int, double>>( ValueListenableBuilder<Map<int, double>>(
valueListenable: state.attachmentProgress, valueListenable: state.attachmentProgress,
builder: (context, progressMap, _) { builder: (context, progressMap, _) {
@@ -314,11 +334,16 @@ class ArticleComposeScreen extends HookConsumerWidget {
runSpacing: 8, runSpacing: 8,
spacing: 8, spacing: 8,
children: [ children: [
for (var idx = 0; idx < attachments.length; idx++) for (
var idx = 0;
idx < attachments.length;
idx++
)
SizedBox( SizedBox(
width: 280, width: 180,
height: 280, height: 180,
child: AttachmentPreview( child: AttachmentPreview(
isCompact: true,
item: attachments[idx], item: attachments[idx],
progress: progressMap[idx], progress: progressMap[idx],
onRequestUpload: onRequestUpload:
@@ -340,15 +365,6 @@ class ArticleComposeScreen extends HookConsumerWidget {
state, state,
idx, idx,
), ),
onMove: (delta) {
state
.attachments
.value = ComposeLogic.moveAttachment(
state.attachments.value,
idx,
delta,
);
},
onInsert: onInsert:
() => ComposeLogic.insertAttachment( () => ComposeLogic.insertAttachment(
ref, ref,
@@ -361,7 +377,9 @@ class ArticleComposeScreen extends HookConsumerWidget {
); );
}, },
), ),
Gap(16),
], ],
),
); );
}, },
), ),

View File

@@ -88,6 +88,7 @@ class AttachmentPreview extends HookConsumerWidget {
final Function? onInsert; final Function? onInsert;
final Function(UniversalFile)? onUpdate; final Function(UniversalFile)? onUpdate;
final Function? onRequestUpload; final Function? onRequestUpload;
final bool isCompact;
const AttachmentPreview({ const AttachmentPreview({
super.key, super.key,
@@ -98,6 +99,7 @@ class AttachmentPreview extends HookConsumerWidget {
this.onDelete, this.onDelete,
this.onUpdate, this.onUpdate,
this.onInsert, this.onInsert,
this.isCompact = false,
}); });
// GlobalKey for selector // GlobalKey for selector
@@ -458,9 +460,10 @@ class AttachmentPreview extends HookConsumerWidget {
size: 16, size: 16,
color: Colors.white, color: Colors.white,
), ),
const Gap(8), if (!isCompact) const Gap(8),
if (!isCompact)
Text( Text(
'On-cloud', 'attachmentOnCloud'.tr(),
style: TextStyle(color: Colors.white), style: TextStyle(color: Colors.white),
), ),
], ],
@@ -473,9 +476,10 @@ class AttachmentPreview extends HookConsumerWidget {
size: 16, size: 16,
color: Colors.white, color: Colors.white,
), ),
const Gap(8), if (!isCompact) const Gap(8),
if (!isCompact)
Text( Text(
'On-device', 'attachmentOnDevice'.tr(),
style: TextStyle(color: Colors.white), style: TextStyle(color: Colors.white),
), ),
], ],