✨ Articles writing
This commit is contained in:
parent
fa600d6c69
commit
065cda27e9
@ -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<ArticlePublishScreen> {
|
||||
|
||||
List<int> _attachments = List.empty();
|
||||
|
||||
bool _isDraft = false;
|
||||
|
||||
void showAttachments() {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
@ -51,7 +54,9 @@ class _ArticlePublishScreenState extends State<ArticlePublishScreen> {
|
||||
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<ArticlePublishScreen> {
|
||||
'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<ArticlePublishScreen> {
|
||||
if (widget.edit != null) {
|
||||
_contentController.text = widget.edit!.content;
|
||||
_attachments = widget.edit!.attachments ?? List.empty();
|
||||
_isDraft = widget.edit!.isDraft ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,23 +135,23 @@ class _ArticlePublishScreenState extends State<ArticlePublishScreen> {
|
||||
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(
|
||||
body: Stack(
|
||||
children: [
|
||||
ListView(
|
||||
children: [
|
||||
if (_isBusy)
|
||||
const LinearProgressIndicator().animate().scaleX(),
|
||||
if (_isBusy) const LinearProgressIndicator().animate().scaleX(),
|
||||
if (widget.edit != null)
|
||||
MaterialBanner(
|
||||
leading: const Icon(Icons.edit),
|
||||
leadingPadding:
|
||||
const EdgeInsets.only(left: 10, right: 20),
|
||||
leadingPadding: const EdgeInsets.only(left: 10, right: 20),
|
||||
dividerColor: Colors.transparent,
|
||||
content: Text('postEditingNotify'.tr),
|
||||
actions: notifyBannerActions,
|
||||
@ -152,8 +159,7 @@ class _ArticlePublishScreenState extends State<ArticlePublishScreen> {
|
||||
if (widget.realm != null)
|
||||
MaterialBanner(
|
||||
leading: const Icon(Icons.group),
|
||||
leadingPadding:
|
||||
const EdgeInsets.only(left: 10, right: 20),
|
||||
leadingPadding: const EdgeInsets.only(left: 10, right: 20),
|
||||
dividerColor: Colors.transparent,
|
||||
content: Text(
|
||||
'postInRealmNotify'
|
||||
@ -170,7 +176,6 @@ class _ArticlePublishScreenState extends State<ArticlePublishScreen> {
|
||||
maxLines: null,
|
||||
autofocus: true,
|
||||
autocorrect: true,
|
||||
keyboardType: TextInputType.multiline,
|
||||
controller: _titleController,
|
||||
decoration: InputDecoration.collapsed(
|
||||
hintText: 'articleTitlePlaceholder'.tr,
|
||||
@ -179,6 +184,25 @@ class _ArticlePublishScreenState extends State<ArticlePublishScreen> {
|
||||
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(
|
||||
@ -197,12 +221,16 @@ class _ArticlePublishScreenState extends State<ArticlePublishScreen> {
|
||||
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,25 +242,46 @@ class _ArticlePublishScreenState extends State<ArticlePublishScreen> {
|
||||
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),
|
||||
),
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
onPressed: () => showAttachments(),
|
||||
)
|
||||
),
|
||||
],
|
||||
).paddingSymmetric(horizontal: 6, vertical: 8),
|
||||
),
|
||||
],
|
||||
).paddingOnly(bottom: MediaQuery.of(context).padding.bottom),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,9 @@ class _PostPublishScreenState extends State<PostPublishScreen> {
|
||||
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<PostPublishScreen> {
|
||||
setState(() => _isDraft = !_isDraft);
|
||||
},
|
||||
),
|
||||
badges.Badge(
|
||||
badgeContent: Text(_attachments.length.toString()),
|
||||
IconButton(
|
||||
icon: badges.Badge(
|
||||
badgeContent: Text(
|
||||
_attachments.length.toString(),
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
showBadge: _attachments.isNotEmpty,
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.camera_alt),
|
||||
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),
|
||||
),
|
||||
|
@ -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?!',
|
||||
|
@ -275,6 +275,7 @@ class _PostItemState extends State<PostItem> {
|
||||
attachmentsId: item.attachments ?? List.empty(),
|
||||
divided: true,
|
||||
),
|
||||
if (!widget.isShowReply && widget.isReactable)
|
||||
PostQuickAction(
|
||||
isShowReply: widget.isShowReply,
|
||||
isReactable: widget.isReactable,
|
||||
@ -290,7 +291,9 @@ class _PostItemState extends State<PostItem> {
|
||||
left: hasAttachment ? 24 : 60,
|
||||
right: 16,
|
||||
bottom: 10,
|
||||
),
|
||||
)
|
||||
else
|
||||
const SizedBox(height: 10),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
@ -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<String> 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<Widget> 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(),
|
||||
|
Loading…
Reference in New Issue
Block a user