diff --git a/lib/screens/articles/article_publish.dart b/lib/screens/articles/article_publish.dart index 9c1b3a9..1539a7d 100644 --- a/lib/screens/articles/article_publish.dart +++ b/lib/screens/articles/article_publish.dart @@ -12,6 +12,7 @@ import 'package:solian/widgets/attachments/attachment_publish.dart'; import 'package:solian/widgets/feed/feed_tags_field.dart'; import 'package:solian/widgets/prev_page.dart'; import 'package:textfield_tags/textfield_tags.dart'; +import 'package:badges/badges.dart' as badges; class ArticlePublishArguments { final Post? edit; @@ -44,6 +45,8 @@ class _ArticlePublishScreenState extends State { List _attachments = List.empty(); + bool _isDraft = false; + void showAttachments() { showModalBottomSheet( context: context, @@ -51,7 +54,9 @@ class _ArticlePublishScreenState extends State { builder: (context) => AttachmentPublishPopup( usage: 'i.attachment', current: _attachments, - onUpdate: (value) => _attachments = value, + onUpdate: (value) { + setState(() => _attachments = value); + }, ), ); } @@ -72,6 +77,7 @@ class _ArticlePublishScreenState extends State { 'tags': _tagsController.getTags?.map((x) => {'alias': x}).toList() ?? List.empty(), 'attachments': _attachments, + 'is_draft': _isDraft, if (widget.edit != null) 'alias': widget.edit!.alias, if (widget.realm != null) 'realm': widget.realm!.alias, }; @@ -95,6 +101,7 @@ class _ArticlePublishScreenState extends State { if (widget.edit != null) { _contentController.text = widget.edit!.content; _attachments = widget.edit!.attachments ?? List.empty(); + _isDraft = widget.edit!.isDraft ?? false; } } @@ -128,81 +135,102 @@ class _ArticlePublishScreenState extends State { actions: [ TextButton( onPressed: _isBusy ? null : () => applyPost(), - child: Text('postAction'.tr.toUpperCase()), + child: Text( + _isDraft + ? 'draftSave'.tr.toUpperCase() + : 'postAction'.tr.toUpperCase(), + ), ) ], ), - body: SafeArea( - top: false, - child: Stack( - children: [ - ListView( - children: [ - if (_isBusy) - const LinearProgressIndicator().animate().scaleX(), - if (widget.edit != null) - MaterialBanner( - leading: const Icon(Icons.edit), - leadingPadding: - const EdgeInsets.only(left: 10, right: 20), - dividerColor: Colors.transparent, - content: Text('postEditingNotify'.tr), - actions: notifyBannerActions, - ), - if (widget.realm != null) - MaterialBanner( - leading: const Icon(Icons.group), - leadingPadding: - const EdgeInsets.only(left: 10, right: 20), - dividerColor: Colors.transparent, - content: Text( - 'postInRealmNotify' - .trParams({'realm': '#${widget.realm!.alias}'}), - ), - actions: notifyBannerActions, - ), - const Divider(thickness: 0.3, height: 0.3) - .paddingOnly(bottom: 6), - Container( - padding: - const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - child: TextField( - maxLines: null, - autofocus: true, - autocorrect: true, - keyboardType: TextInputType.multiline, - controller: _titleController, - decoration: InputDecoration.collapsed( - hintText: 'articleTitlePlaceholder'.tr, - ), - onTapOutside: (_) => - FocusManager.instance.primaryFocus?.unfocus(), - ), + body: Stack( + children: [ + ListView( + children: [ + if (_isBusy) const LinearProgressIndicator().animate().scaleX(), + if (widget.edit != null) + MaterialBanner( + leading: const Icon(Icons.edit), + leadingPadding: const EdgeInsets.only(left: 10, right: 20), + dividerColor: Colors.transparent, + content: Text('postEditingNotify'.tr), + actions: notifyBannerActions, ), - const Divider(thickness: 0.3, height: 0.3) - .paddingSymmetric(vertical: 6), - Container( - padding: - const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - child: TextField( - maxLines: null, - autofocus: true, - autocorrect: true, - keyboardType: TextInputType.multiline, - controller: _contentController, - decoration: InputDecoration.collapsed( - hintText: 'articleContentPlaceholder'.tr, - ), - onTapOutside: (_) => - FocusManager.instance.primaryFocus?.unfocus(), + if (widget.realm != null) + MaterialBanner( + leading: const Icon(Icons.group), + leadingPadding: const EdgeInsets.only(left: 10, right: 20), + dividerColor: Colors.transparent, + content: Text( + 'postInRealmNotify' + .trParams({'realm': '#${widget.realm!.alias}'}), ), + actions: notifyBannerActions, ), - ], - ), - Positioned( - bottom: 0, - left: 0, - right: 0, + const Divider(thickness: 0.3, height: 0.3) + .paddingOnly(bottom: 6), + Container( + padding: + const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: TextField( + maxLines: null, + autofocus: true, + autocorrect: true, + controller: _titleController, + decoration: InputDecoration.collapsed( + hintText: 'articleTitlePlaceholder'.tr, + ), + onTapOutside: (_) => + FocusManager.instance.primaryFocus?.unfocus(), + ), + ), + const Divider(thickness: 0.3, height: 0.3) + .paddingOnly(bottom: 6), + Container( + padding: + const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: TextField( + minLines: 1, + maxLines: 3, + autofocus: true, + autocorrect: true, + keyboardType: TextInputType.multiline, + controller: _descriptionController, + decoration: InputDecoration.collapsed( + hintText: 'articleDescriptionPlaceholder'.tr, + ), + onTapOutside: (_) => + FocusManager.instance.primaryFocus?.unfocus(), + ), + ), + const Divider(thickness: 0.3, height: 0.3) + .paddingSymmetric(vertical: 6), + Container( + padding: + const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: TextField( + maxLines: null, + autofocus: true, + autocorrect: true, + keyboardType: TextInputType.multiline, + controller: _contentController, + decoration: InputDecoration.collapsed( + hintText: 'articleContentPlaceholder'.tr, + ), + onTapOutside: (_) => + FocusManager.instance.primaryFocus?.unfocus(), + ), + ), + const SizedBox(height: 120), + ], + ), + Positioned( + bottom: 0, + left: 0, + right: 0, + child: Material( + elevation: 8, + color: Theme.of(context).colorScheme.surface, child: Column( children: [ TagsField( @@ -214,23 +242,44 @@ class _ArticlePublishScreenState extends State { const Divider(thickness: 0.3, height: 0.3), SizedBox( height: 56, - child: Row( + child: ListView( + scrollDirection: Axis.horizontal, children: [ - TextButton( - style: TextButton.styleFrom( - shape: const CircleBorder(), + IconButton( + icon: _isDraft + ? const Icon(Icons.drive_file_rename_outline) + : const Icon(Icons.public), + color: _isDraft + ? Colors.grey.shade600 + : Colors.green.shade700, + onPressed: () { + setState(() => _isDraft = !_isDraft); + }, + ), + IconButton( + icon: badges.Badge( + badgeContent: Text( + _attachments.length.toString(), + style: const TextStyle(color: Colors.white), + ), + showBadge: _attachments.isNotEmpty, + position: badges.BadgePosition.topEnd( + top: -12, + end: -8, + ), + child: const Icon(Icons.camera_alt), ), - child: const Icon(Icons.camera_alt), + color: Theme.of(context).colorScheme.primary, onPressed: () => showAttachments(), - ) + ), ], - ), + ).paddingSymmetric(horizontal: 6, vertical: 8), ), ], - ), + ).paddingOnly(bottom: MediaQuery.of(context).padding.bottom), ), - ], - ), + ), + ], ), ), ); diff --git a/lib/screens/posts/post_publish.dart b/lib/screens/posts/post_publish.dart index b0bf191..4c603a0 100644 --- a/lib/screens/posts/post_publish.dart +++ b/lib/screens/posts/post_publish.dart @@ -60,7 +60,9 @@ class _PostPublishScreenState extends State { builder: (context) => AttachmentPublishPopup( usage: 'i.attachment', current: _attachments, - onUpdate: (value) => _attachments = value, + onUpdate: (value) { + setState(() => _attachments = value); + }, ), ); } @@ -261,14 +263,22 @@ class _PostPublishScreenState extends State { setState(() => _isDraft = !_isDraft); }, ), - badges.Badge( - badgeContent: Text(_attachments.length.toString()), - showBadge: _attachments.isNotEmpty, - child: IconButton( - icon: const Icon(Icons.camera_alt), - onPressed: () => showAttachments(), + IconButton( + icon: badges.Badge( + badgeContent: Text( + _attachments.length.toString(), + style: const TextStyle(color: Colors.white), + ), + showBadge: _attachments.isNotEmpty, + position: badges.BadgePosition.topEnd( + top: -12, + end: -8, + ), + child: const Icon(Icons.camera_alt), ), - ) + color: Theme.of(context).colorScheme.primary, + onPressed: () => showAttachments(), + ), ], ).paddingSymmetric(horizontal: 6, vertical: 8), ), diff --git a/lib/translations/en_us.dart b/lib/translations/en_us.dart index 6ff1ac2..2aedb28 100644 --- a/lib/translations/en_us.dart +++ b/lib/translations/en_us.dart @@ -91,6 +91,7 @@ const messagesEnglish = { 'postPublish': 'Post a post', 'articlePublish': 'Write an article', 'articleTitlePlaceholder': 'Title', + 'articleDescriptionPlaceholder': 'Description', 'articleContentPlaceholder': 'Content', 'postIdentityNotify': 'You will post this post as', 'postContentPlaceholder': 'What\'s happened?!', diff --git a/lib/widgets/posts/post_item.dart b/lib/widgets/posts/post_item.dart index 247237f..50f87c8 100644 --- a/lib/widgets/posts/post_item.dart +++ b/lib/widgets/posts/post_item.dart @@ -275,22 +275,25 @@ class _PostItemState extends State { attachmentsId: item.attachments ?? List.empty(), divided: true, ), - PostQuickAction( - isShowReply: widget.isShowReply, - isReactable: widget.isReactable, - item: widget.item, - onReact: (symbol, changes) { - setState(() { - item.reactionList[symbol] = - (item.reactionList[symbol] ?? 0) + changes; - }); - }, - ).paddingOnly( - top: hasAttachment ? 10 : 6, - left: hasAttachment ? 24 : 60, - right: 16, - bottom: 10, - ), + if (!widget.isShowReply && widget.isReactable) + PostQuickAction( + isShowReply: widget.isShowReply, + isReactable: widget.isReactable, + item: widget.item, + onReact: (symbol, changes) { + setState(() { + item.reactionList[symbol] = + (item.reactionList[symbol] ?? 0) + changes; + }); + }, + ).paddingOnly( + top: hasAttachment ? 10 : 6, + left: hasAttachment ? 24 : 60, + right: 16, + bottom: 10, + ) + else + const SizedBox(height: 10), ], ); } diff --git a/lib/widgets/posts/post_owned_list.dart b/lib/widgets/posts/post_owned_list.dart index d3fc26d..ca6dd53 100644 --- a/lib/widgets/posts/post_owned_list.dart +++ b/lib/widgets/posts/post_owned_list.dart @@ -1,9 +1,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:intl/intl.dart'; import 'package:solian/models/post.dart'; -import 'package:solian/widgets/feed/feed_content.dart'; -import 'package:solian/widgets/feed/feed_tags.dart'; +import 'package:solian/widgets/posts/post_item.dart'; class PostOwnedListEntry extends StatelessWidget { final Post item; @@ -15,61 +13,6 @@ class PostOwnedListEntry extends StatelessWidget { required this.onTap, }); - Widget buildFooter(BuildContext context) { - List labels = List.empty(growable: true); - if (item.createdAt == item.updatedAt) { - labels.add('postNewCreated'.trParams({ - 'date': DateFormat('yyyy/MM/dd HH:mm').format(item.updatedAt.toLocal()), - })); - } else { - labels.add('postEdited'.trParams({ - 'date': DateFormat('yyyy/MM/dd HH:mm').format(item.updatedAt.toLocal()), - })); - } - if (item.realm != null) { - labels.add('postInRealm'.trParams({ - 'realm': '#${item.realm!.alias}', - })); - } - - final color = Theme.of(context).colorScheme.onSurface.withOpacity(0.75); - - List widgets = List.from([ - Row( - children: [ - Text( - 'post'.tr, - textAlign: TextAlign.left, - style: TextStyle( - fontSize: 12, - color: color, - ), - ), - Icon(Icons.text_snippet, size: 14, color: color).paddingOnly(left: 4), - ], - ), - ], growable: true); - - if (item.tags?.isNotEmpty ?? false) { - widgets.add(FeedTagsList(tags: item.tags!)); - } - if (labels.isNotEmpty) { - widgets.add(Text( - labels.join(' ยท '), - textAlign: TextAlign.left, - style: TextStyle( - fontSize: 12, - color: color, - ), - )); - } - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: widgets, - ); - } - @override Widget build(BuildContext context) { return Card( @@ -78,12 +21,14 @@ class PostOwnedListEntry extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - FeedContent(content: item.content).paddingOnly( - left: 12, - right: 12, - top: 8, - ), - buildFooter(context).paddingOnly(left: 12, top: 6, bottom: 8), + PostItem( + key: Key('p${item.alias}'), + item: item, + isShowEmbed: false, + isClickable: false, + isShowReply: false, + isReactable: false, + ).paddingSymmetric(vertical: 8), ], ), onTap: () => onTap(),