From 30184d08b100bfc7927b07b9acec36bf615dc65d Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Fri, 21 Feb 2025 21:50:36 +0800 Subject: [PATCH] :recycle: Refactor the way to set thumbnail --- assets/translations/en-US.json | 3 +- assets/translations/zh-CN.json | 3 +- assets/translations/zh-HK.json | 3 +- assets/translations/zh-TW.json | 3 +- lib/controllers/post_write_controller.dart | 26 +++----- lib/screens/post/post_editor.dart | 53 ++++++++++++++-- lib/widgets/post/post_media_pending_list.dart | 63 ++++--------------- 7 files changed, 78 insertions(+), 76 deletions(-) diff --git a/assets/translations/en-US.json b/assets/translations/en-US.json index c529402..7b67205 100644 --- a/assets/translations/en-US.json +++ b/assets/translations/en-US.json @@ -670,5 +670,6 @@ "attachmentBillingUploaded": "Used space", "attachmentBillingDiscount": "Free space", "attachmentBillingRatio": "Usage", - "attachmentBillingHint": "Sliding Window Pricing®\nFees will only apply if the size of the file uploaded within 24 hours exceeds the free space." + "attachmentBillingHint": "Sliding Window Pricing®\nFees will only apply if the size of the file uploaded within 24 hours exceeds the free space.", + "postThumbnail": "Post Thumbnail" } diff --git a/assets/translations/zh-CN.json b/assets/translations/zh-CN.json index 0f389f7..1e8f810 100644 --- a/assets/translations/zh-CN.json +++ b/assets/translations/zh-CN.json @@ -668,5 +668,6 @@ }, "attachmentBillingUploaded": "已占用的字节数", "attachmentBillingDiscount": "免费的字节数", - "attachmentBillingHint": "滑动窗口计价®\n在24小时内上传的文件大小超出免费空间才会适用扣费。" + "attachmentBillingHint": "滑动窗口计价®\n在24小时内上传的文件大小超出免费空间才会适用扣费。", + "postThumbnail": "帖子缩略图" } diff --git a/assets/translations/zh-HK.json b/assets/translations/zh-HK.json index 88e49b1..1b1a433 100644 --- a/assets/translations/zh-HK.json +++ b/assets/translations/zh-HK.json @@ -668,5 +668,6 @@ }, "attachmentBillingUploaded": "已佔用的字節數", "attachmentBillingDiscount": "免費的字節數", - "attachmentBillingHint": "滑動窗口計價®\n在24小時內上傳的文件大小超出免費空間才會適用扣費。" + "attachmentBillingHint": "滑動窗口計價®\n在24小時內上傳的文件大小超出免費空間才會適用扣費。", + "postThumbnail": "帖子縮略圖" } diff --git a/assets/translations/zh-TW.json b/assets/translations/zh-TW.json index ff9c846..e94e6e3 100644 --- a/assets/translations/zh-TW.json +++ b/assets/translations/zh-TW.json @@ -668,5 +668,6 @@ }, "attachmentBillingUploaded": "已佔用的字節數", "attachmentBillingDiscount": "免費的字節數", - "attachmentBillingHint": "滑動窗口計價®\n在24小時內上傳的文件大小超出免費空間才會適用扣費。" + "attachmentBillingHint": "滑動窗口計價®\n在24小時內上傳的文件大小超出免費空間才會適用扣費。", + "postThumbnail": "帖子縮略圖" } diff --git a/lib/controllers/post_write_controller.dart b/lib/controllers/post_write_controller.dart index 5e04851..d55f25a 100644 --- a/lib/controllers/post_write_controller.dart +++ b/lib/controllers/post_write_controller.dart @@ -159,12 +159,13 @@ class PostWriteController extends ChangeNotifier { final TextEditingController rewardController = TextEditingController(); ContentInsertionConfiguration get contentInsertionConfiguration => ContentInsertionConfiguration( - onContentInserted: (KeyboardInsertedContent content) { - if (content.hasData) { - addAttachments([PostWriteMedia.fromBytes(content.data!, 'attachmentInsertedImage'.tr(), SnMediaType.image)]); - } - }, - ); + onContentInserted: (KeyboardInsertedContent content) { + if (content.hasData) { + addAttachments( + [PostWriteMedia.fromBytes(content.data!, 'attachmentInsertedImage'.tr(), SnMediaType.image)]); + } + }, + ); bool _temporarySaveActive = false; @@ -571,17 +572,8 @@ class PostWriteController extends ChangeNotifier { notifyListeners(); } - void setThumbnail(int? idx) { - if (idx == null) { - attachments.add(thumbnail!); - thumbnail = null; - } else { - if (thumbnail != null) { - attachments.add(thumbnail!); - } - thumbnail = attachments[idx]; - attachments.removeAt(idx); - } + void setThumbnail(SnAttachment? value) { + thumbnail = value == null ? null : PostWriteMedia(value); notifyListeners(); } diff --git a/lib/screens/post/post_editor.dart b/lib/screens/post/post_editor.dart index 603928b..08d5698 100644 --- a/lib/screens/post/post_editor.dart +++ b/lib/screens/post/post_editor.dart @@ -161,6 +161,20 @@ class _PostEditorScreenState extends State { } } + void _showThumbnailEditorDialog() async { + final attachment = await showDialog( + context: context, + builder: (context) => AttachmentInputDialog( + title: 'postThumbnail'.tr(), + pool: 'interactive', + mediaType: SnMediaType.image, + ), + ); + if (!context.mounted) return; + if (attachment == null) return; + _writeController.setThumbnail(attachment); + } + @override void dispose() { _writeController.dispose(); @@ -344,15 +358,11 @@ class _PostEditorScreenState extends State { left: 0, right: 0, child: PostMediaPendingList( - thumbnail: _writeController.thumbnail, attachments: _writeController.attachments, isBusy: _writeController.isBusy, onUpload: (int idx) async { await _writeController.uploadSingleAttachment(context, idx); }, - onPostSetThumbnail: (int? idx) { - _writeController.setThumbnail(idx); - }, onInsertLink: (int idx) async { _writeController.contentController.text += '\n![](solink://attachments/${_writeController.attachments[idx].attachment!.rid})'; @@ -453,6 +463,22 @@ class _PostEditorScreenState extends State { _showPollEditorDialog(); }, ), + if (_writeController.mode == 'articles') + IconButton( + icon: Icon(Symbols.image, color: Theme.of(context).colorScheme.primary), + style: ButtonStyle( + backgroundColor: _writeController.thumbnail == null + ? null + : WidgetStatePropertyAll(Theme.of(context).colorScheme.surfaceContainer), + ), + onPressed: () { + if (_writeController.thumbnail != null) { + _writeController.setThumbnail(null); + return; + } + _showThumbnailEditorDialog(); + }, + ), ], ), ), @@ -668,7 +694,24 @@ class _PostArticleEditor extends StatelessWidget { onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), contentInsertionConfiguration: controller.contentInsertionConfiguration, ).padding(horizontal: 16), - const Gap(4), + if (controller.thumbnail != null) + Container( + margin: const EdgeInsets.only(left: 12, right: 12, top: 8, bottom: 4), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Theme.of(context).dividerColor), + ), + child: ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(8)), + child: AspectRatio( + aspectRatio: 16 / 9, + child: AttachmentItem( + data: controller.thumbnail!.attachment!, + heroTag: "post-editor-thumbnail-preview", + ), + ), + ), + ), ]; if (ResponsiveBreakpoints.of(context).largerThan(MOBILE)) { diff --git a/lib/widgets/post/post_media_pending_list.dart b/lib/widgets/post/post_media_pending_list.dart index a60c039..7b5738e 100644 --- a/lib/widgets/post/post_media_pending_list.dart +++ b/lib/widgets/post/post_media_pending_list.dart @@ -30,25 +30,21 @@ import 'package:surface/widgets/universal_image.dart'; import '../attachment/pending_attachment_compress.dart'; class PostMediaPendingList extends StatelessWidget { - final PostWriteMedia? thumbnail; final List attachments; final bool isBusy; final Future Function(int idx, PostWriteMedia updatedMedia)? onUpdate; final Future Function(int idx)? onRemove; final Future Function(int idx)? onUpload; - final void Function(int? idx)? onPostSetThumbnail; final void Function(int idx)? onInsertLink; final void Function(bool state)? onUpdateBusy; const PostMediaPendingList({ super.key, - this.thumbnail, required this.attachments, required this.isBusy, this.onUpdate, this.onRemove, this.onUpload, - this.onPostSetThumbnail, this.onInsertLink, this.onUpdateBusy, }); @@ -116,7 +112,7 @@ class PostMediaPendingList extends StatelessWidget { } Future _deleteAttachment(BuildContext context, int idx) async { - final media = idx == -1 ? thumbnail! : attachments[idx]; + final media = attachments[idx]; if (media.attachment == null) return; try { @@ -212,22 +208,6 @@ class PostMediaPendingList extends StatelessWidget { onSelected: () { onUpload!(idx); }), - if (media.attachment != null && media.type == SnMediaType.image && onPostSetThumbnail != null && idx != -1) - MenuItem( - label: 'attachmentSetAsPostThumbnail'.tr(), - icon: Symbols.gallery_thumbnail, - onSelected: () { - onPostSetThumbnail!(idx); - }, - ) - else if (media.attachment != null && media.type == SnMediaType.image && onPostSetThumbnail != null) - MenuItem( - label: 'attachmentUnsetAsPostThumbnail'.tr(), - icon: Symbols.cancel, - onSelected: () { - onPostSetThumbnail!(null); - }, - ), if (media.attachment != null && onInsertLink != null) MenuItem( label: 'attachmentInsertLink'.tr(), @@ -291,35 +271,18 @@ class PostMediaPendingList extends StatelessWidget { Widget build(BuildContext context) { return Container( constraints: const BoxConstraints(maxHeight: 120), - child: Row( - children: [ - const Gap(16), - if (thumbnail != null) - ContextMenuArea( - contextMenu: _createContextMenu(context, -1, thumbnail!), - child: _PostMediaPendingItem(media: thumbnail!), - ), - if (thumbnail != null) - const VerticalDivider(width: 1, thickness: 1).padding( - horizontal: 12, - vertical: 16, - ), - Expanded( - child: ListView.separated( - scrollDirection: Axis.horizontal, - padding: const EdgeInsets.only(right: 8), - separatorBuilder: (context, index) => const Gap(8), - itemCount: attachments.length, - itemBuilder: (context, idx) { - final media = attachments[idx]; - return ContextMenuArea( - contextMenu: _createContextMenu(context, idx, media), - child: _PostMediaPendingItem(media: media), - ); - }, - ), - ), - ], + child: ListView.separated( + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.symmetric(horizontal: 8), + separatorBuilder: (context, index) => const Gap(8), + itemCount: attachments.length, + itemBuilder: (context, idx) { + final media = attachments[idx]; + return ContextMenuArea( + contextMenu: _createContextMenu(context, idx, media), + child: _PostMediaPendingItem(media: media), + ); + }, ), ); }