✨ Post tags
This commit is contained in:
parent
0361f031db
commit
4deff5a920
@ -103,30 +103,32 @@ class PostComposeScreen extends HookConsumerWidget {
|
|||||||
originalPost: originalPost,
|
originalPost: originalPost,
|
||||||
forwardedPost: effectiveForwardedPost,
|
forwardedPost: effectiveForwardedPost,
|
||||||
repliedPost: effectiveRepliedPost,
|
repliedPost: effectiveRepliedPost,
|
||||||
|
postType: 0, // Regular post type
|
||||||
),
|
),
|
||||||
[originalPost, effectiveForwardedPost, effectiveRepliedPost],
|
[originalPost, effectiveForwardedPost, effectiveRepliedPost],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add a listener to the entire state to trigger rebuilds
|
// Add a listener to the entire state to trigger rebuilds
|
||||||
final stateNotifier = useMemoized(
|
final stateNotifier = useMemoized(
|
||||||
() => Listenable.merge([
|
() => Listenable.merge([
|
||||||
state.titleController,
|
state.titleController,
|
||||||
state.descriptionController,
|
state.descriptionController,
|
||||||
state.contentController,
|
state.contentController,
|
||||||
state.visibility,
|
state.visibility,
|
||||||
state.attachments,
|
state.attachments,
|
||||||
state.attachmentProgress,
|
state.attachmentProgress,
|
||||||
state.currentPublisher,
|
state.currentPublisher,
|
||||||
state.submitting,
|
state.submitting,
|
||||||
]),
|
]),
|
||||||
[state]);
|
[state],
|
||||||
|
);
|
||||||
useListenable(stateNotifier);
|
useListenable(stateNotifier);
|
||||||
|
|
||||||
// Start auto-save when component mounts
|
// Start auto-save when component mounts
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
if (originalPost == null) {
|
if (originalPost == null) {
|
||||||
// Only auto-save for new posts, not edits
|
// Only auto-save for new posts, not edits
|
||||||
state.startAutoSave(ref, postType: 0);
|
state.startAutoSave(ref);
|
||||||
}
|
}
|
||||||
return () => state.stopAutoSave();
|
return () => state.stopAutoSave();
|
||||||
}, [state]);
|
}, [state]);
|
||||||
@ -165,13 +167,18 @@ class PostComposeScreen extends HookConsumerWidget {
|
|||||||
final drafts = ref.read(composeStorageNotifierProvider);
|
final drafts = ref.read(composeStorageNotifierProvider);
|
||||||
if (drafts.isNotEmpty) {
|
if (drafts.isNotEmpty) {
|
||||||
final mostRecentDraft = drafts.values.reduce(
|
final mostRecentDraft = drafts.values.reduce(
|
||||||
(a, b) => (a.updatedAt ?? DateTime(0)).isAfter(b.updatedAt ?? DateTime(0)) ? a : b,
|
(a, b) =>
|
||||||
|
(a.updatedAt ?? DateTime(0)).isAfter(b.updatedAt ?? DateTime(0))
|
||||||
|
? a
|
||||||
|
: b,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Only load if the draft has meaningful content
|
// Only load if the draft has meaningful content
|
||||||
if (mostRecentDraft.content?.isNotEmpty == true || mostRecentDraft.title?.isNotEmpty == true) {
|
if (mostRecentDraft.content?.isNotEmpty == true ||
|
||||||
|
mostRecentDraft.title?.isNotEmpty == true) {
|
||||||
state.titleController.text = mostRecentDraft.title ?? '';
|
state.titleController.text = mostRecentDraft.title ?? '';
|
||||||
state.descriptionController.text = mostRecentDraft.description ?? '';
|
state.descriptionController.text =
|
||||||
|
mostRecentDraft.description ?? '';
|
||||||
state.contentController.text = mostRecentDraft.content ?? '';
|
state.contentController.text = mostRecentDraft.content ?? '';
|
||||||
state.visibility.value = mostRecentDraft.visibility;
|
state.visibility.value = mostRecentDraft.visibility;
|
||||||
}
|
}
|
||||||
@ -298,7 +305,8 @@ class PostComposeScreen extends HookConsumerWidget {
|
|||||||
state.titleController.text = draft.title ?? '';
|
state.titleController.text = draft.title ?? '';
|
||||||
state.descriptionController.text =
|
state.descriptionController.text =
|
||||||
draft.description ?? '';
|
draft.description ?? '';
|
||||||
state.contentController.text = draft.content ?? '';
|
state.contentController.text =
|
||||||
|
draft.content ?? '';
|
||||||
state.visibility.value = draft.visibility;
|
state.visibility.value = draft.visibility;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -322,14 +330,13 @@ class PostComposeScreen extends HookConsumerWidget {
|
|||||||
state.submitting.value
|
state.submitting.value
|
||||||
? null
|
? null
|
||||||
: () => ComposeLogic.performAction(
|
: () => ComposeLogic.performAction(
|
||||||
ref,
|
ref,
|
||||||
state,
|
state,
|
||||||
context,
|
context,
|
||||||
originalPost: originalPost,
|
originalPost: originalPost,
|
||||||
repliedPost: repliedPost,
|
repliedPost: repliedPost,
|
||||||
forwardedPost: forwardedPost,
|
forwardedPost: forwardedPost,
|
||||||
postType: 0, // Regular post type
|
),
|
||||||
),
|
|
||||||
icon:
|
icon:
|
||||||
state.submitting.value
|
state.submitting.value
|
||||||
? SizedBox(
|
? SizedBox(
|
||||||
@ -341,9 +348,7 @@ class PostComposeScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
).center()
|
).center()
|
||||||
: Icon(
|
: Icon(
|
||||||
originalPost != null
|
originalPost != null ? Symbols.edit : Symbols.upload,
|
||||||
? Symbols.edit
|
|
||||||
: Symbols.upload,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
@ -405,7 +410,6 @@ class PostComposeScreen extends HookConsumerWidget {
|
|||||||
originalPost: originalPost,
|
originalPost: originalPost,
|
||||||
repliedPost: repliedPost,
|
repliedPost: repliedPost,
|
||||||
forwardedPost: forwardedPost,
|
forwardedPost: forwardedPost,
|
||||||
postType: 0, // Regular post type
|
|
||||||
),
|
),
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: state.contentController,
|
controller: state.contentController,
|
||||||
|
@ -60,7 +60,10 @@ class ArticleComposeScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
final publishers = ref.watch(publishersManagedProvider);
|
final publishers = ref.watch(publishersManagedProvider);
|
||||||
final state = useMemoized(
|
final state = useMemoized(
|
||||||
() => ComposeLogic.createState(originalPost: originalPost),
|
() => ComposeLogic.createState(
|
||||||
|
originalPost: originalPost,
|
||||||
|
postType: 1, // Article type
|
||||||
|
),
|
||||||
[originalPost],
|
[originalPost],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -70,7 +73,7 @@ class ArticleComposeScreen extends HookConsumerWidget {
|
|||||||
if (originalPost == null) {
|
if (originalPost == null) {
|
||||||
// Only auto-save for new articles, not edits
|
// Only auto-save for new articles, not edits
|
||||||
autoSaveTimer = Timer.periodic(const Duration(seconds: 3), (_) {
|
autoSaveTimer = Timer.periodic(const Duration(seconds: 3), (_) {
|
||||||
ComposeLogic.saveDraftWithoutUpload(ref, state, postType: 1);
|
ComposeLogic.saveDraftWithoutUpload(ref, state);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return () {
|
return () {
|
||||||
@ -78,7 +81,7 @@ class ArticleComposeScreen extends HookConsumerWidget {
|
|||||||
state.stopAutoSave();
|
state.stopAutoSave();
|
||||||
// Save final draft before disposing
|
// Save final draft before disposing
|
||||||
if (originalPost == null) {
|
if (originalPost == null) {
|
||||||
ComposeLogic.saveDraftWithoutUpload(ref, state, postType: 1);
|
ComposeLogic.saveDraftWithoutUpload(ref, state);
|
||||||
}
|
}
|
||||||
ComposeLogic.dispose(state);
|
ComposeLogic.dispose(state);
|
||||||
autoSaveTimer?.cancel();
|
autoSaveTimer?.cancel();
|
||||||
@ -362,7 +365,7 @@ class ArticleComposeScreen extends HookConsumerWidget {
|
|||||||
return PopScope(
|
return PopScope(
|
||||||
onPopInvoked: (_) {
|
onPopInvoked: (_) {
|
||||||
if (originalPost == null) {
|
if (originalPost == null) {
|
||||||
ComposeLogic.saveDraftWithoutUpload(ref, state, postType: 1);
|
ComposeLogic.saveDraftWithoutUpload(ref, state);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: AppScaffold(
|
child: AppScaffold(
|
||||||
@ -410,7 +413,7 @@ class ArticleComposeScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Symbols.save),
|
icon: const Icon(Symbols.save),
|
||||||
onPressed: () => ComposeLogic.saveDraft(ref, state, postType: 1),
|
onPressed: () => ComposeLogic.saveDraft(ref, state),
|
||||||
tooltip: 'saveDraft'.tr(),
|
tooltip: 'saveDraft'.tr(),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
@ -437,7 +440,6 @@ class ArticleComposeScreen extends HookConsumerWidget {
|
|||||||
state,
|
state,
|
||||||
context,
|
context,
|
||||||
originalPost: originalPost,
|
originalPost: originalPost,
|
||||||
postType: 1, // Article type
|
|
||||||
),
|
),
|
||||||
icon:
|
icon:
|
||||||
submitting
|
submitting
|
||||||
@ -530,18 +532,17 @@ class ArticleComposeScreen extends HookConsumerWidget {
|
|||||||
if (isPaste && isModifierPressed) {
|
if (isPaste && isModifierPressed) {
|
||||||
ComposeLogic.handlePaste(state);
|
ComposeLogic.handlePaste(state);
|
||||||
} else if (isSave && isModifierPressed) {
|
} else if (isSave && isModifierPressed) {
|
||||||
ComposeLogic.saveDraft(ref, state, postType: 1);
|
ComposeLogic.saveDraft(ref, state);
|
||||||
|
ComposeLogic.saveDraft(ref, state);
|
||||||
} else if (isSubmit && isModifierPressed && !state.submitting.value) {
|
} else if (isSubmit && isModifierPressed && !state.submitting.value) {
|
||||||
ComposeLogic.performAction(
|
ComposeLogic.performAction(
|
||||||
ref,
|
ref,
|
||||||
state,
|
state,
|
||||||
context,
|
context,
|
||||||
originalPost: originalPost,
|
originalPost: originalPost,
|
||||||
postType: 1, // Article type
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper method to save article draft
|
// Helper method to save article draft
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ class ChipTagInputField extends StatelessWidget {
|
|||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
label: Text(labelText).tr(),
|
label: Text(labelText).tr(),
|
||||||
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
|
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
|
||||||
|
contentPadding: const EdgeInsets.all(16),
|
||||||
hintText: inputFieldValues.tags.isNotEmpty ? '' : hintText.tr(),
|
hintText: inputFieldValues.tags.isNotEmpty ? '' : hintText.tr(),
|
||||||
errorText: inputFieldValues.error,
|
errorText: inputFieldValues.error,
|
||||||
prefixIconConstraints: BoxConstraints(
|
prefixIconConstraints: BoxConstraints(
|
||||||
@ -51,9 +52,7 @@ class ChipTagInputField extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
color: Theme.of(context).colorScheme.primary,
|
color: Theme.of(context).colorScheme.primary,
|
||||||
),
|
),
|
||||||
margin: const EdgeInsets.symmetric(
|
margin: const EdgeInsets.only(left: 5),
|
||||||
horizontal: 5.0,
|
|
||||||
),
|
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 10.0,
|
horizontal: 10.0,
|
||||||
vertical: 5.0,
|
vertical: 5.0,
|
||||||
@ -72,11 +71,8 @@ class ChipTagInputField extends StatelessWidget {
|
|||||||
).colorScheme.onPrimary,
|
).colorScheme.onPrimary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () {
|
|
||||||
//print("$tag selected");
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4.0),
|
const Gap(4),
|
||||||
InkWell(
|
InkWell(
|
||||||
child: const Icon(
|
child: const Icon(
|
||||||
Icons.cancel,
|
Icons.cancel,
|
||||||
|
@ -27,9 +27,10 @@ class ComposeState {
|
|||||||
final ValueNotifier<Map<int, double>> attachmentProgress;
|
final ValueNotifier<Map<int, double>> attachmentProgress;
|
||||||
final ValueNotifier<SnPublisher?> currentPublisher;
|
final ValueNotifier<SnPublisher?> currentPublisher;
|
||||||
final ValueNotifier<bool> submitting;
|
final ValueNotifier<bool> submitting;
|
||||||
final StringTagController tagsController;
|
StringTagController tagsController;
|
||||||
final StringTagController categoriesController;
|
StringTagController categoriesController;
|
||||||
final String draftId;
|
final String draftId;
|
||||||
|
int postType;
|
||||||
Timer? _autoSaveTimer;
|
Timer? _autoSaveTimer;
|
||||||
|
|
||||||
ComposeState({
|
ComposeState({
|
||||||
@ -44,12 +45,13 @@ class ComposeState {
|
|||||||
required this.tagsController,
|
required this.tagsController,
|
||||||
required this.categoriesController,
|
required this.categoriesController,
|
||||||
required this.draftId,
|
required this.draftId,
|
||||||
|
this.postType = 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
void startAutoSave(WidgetRef ref, {int postType = 0}) {
|
void startAutoSave(WidgetRef ref) {
|
||||||
_autoSaveTimer?.cancel();
|
_autoSaveTimer?.cancel();
|
||||||
_autoSaveTimer = Timer.periodic(const Duration(seconds: 3), (_) {
|
_autoSaveTimer = Timer.periodic(const Duration(seconds: 3), (_) {
|
||||||
ComposeLogic.saveDraftWithoutUpload(ref, this, postType: postType);
|
ComposeLogic.saveDraftWithoutUpload(ref, this);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,6 +67,7 @@ class ComposeLogic {
|
|||||||
SnPost? forwardedPost,
|
SnPost? forwardedPost,
|
||||||
SnPost? repliedPost,
|
SnPost? repliedPost,
|
||||||
String? draftId,
|
String? draftId,
|
||||||
|
int postType = 0,
|
||||||
}) {
|
}) {
|
||||||
final id = draftId ?? DateTime.now().millisecondsSinceEpoch.toString();
|
final id = draftId ?? DateTime.now().millisecondsSinceEpoch.toString();
|
||||||
final tagsController = StringTagController();
|
final tagsController = StringTagController();
|
||||||
@ -110,10 +113,11 @@ class ComposeLogic {
|
|||||||
tagsController: tagsController,
|
tagsController: tagsController,
|
||||||
categoriesController: categoriesController,
|
categoriesController: categoriesController,
|
||||||
draftId: id,
|
draftId: id,
|
||||||
|
postType: postType,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ComposeState createStateFromDraft(SnPost draft) {
|
static ComposeState createStateFromDraft(SnPost draft, {int postType = 0}) {
|
||||||
final tagsController = StringTagController();
|
final tagsController = StringTagController();
|
||||||
final categoriesController = StringTagController();
|
final categoriesController = StringTagController();
|
||||||
for (var x in draft.tags) {
|
for (var x in draft.tags) {
|
||||||
@ -136,14 +140,11 @@ class ComposeLogic {
|
|||||||
tagsController: tagsController,
|
tagsController: tagsController,
|
||||||
categoriesController: categoriesController,
|
categoriesController: categoriesController,
|
||||||
draftId: draft.id,
|
draftId: draft.id,
|
||||||
|
postType: postType,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> saveDraft(
|
static Future<void> saveDraft(WidgetRef ref, ComposeState state) async {
|
||||||
WidgetRef ref,
|
|
||||||
ComposeState state, {
|
|
||||||
int postType = 0,
|
|
||||||
}) async {
|
|
||||||
final hasContent =
|
final hasContent =
|
||||||
state.titleController.text.trim().isNotEmpty ||
|
state.titleController.text.trim().isNotEmpty ||
|
||||||
state.descriptionController.text.trim().isNotEmpty ||
|
state.descriptionController.text.trim().isNotEmpty ||
|
||||||
@ -175,7 +176,7 @@ class ComposeLogic {
|
|||||||
baseUrl: baseUrl,
|
baseUrl: baseUrl,
|
||||||
filename:
|
filename:
|
||||||
attachment.data.name ??
|
attachment.data.name ??
|
||||||
(postType == 1 ? 'Article media' : 'Post media'),
|
(state.postType == 1 ? 'Article media' : 'Post media'),
|
||||||
mimetype:
|
mimetype:
|
||||||
attachment.data.mimeType ??
|
attachment.data.mimeType ??
|
||||||
ComposeLogic.getMimeTypeFromFileType(attachment.type),
|
ComposeLogic.getMimeTypeFromFileType(attachment.type),
|
||||||
@ -202,7 +203,7 @@ class ComposeLogic {
|
|||||||
publishedAt: DateTime.now(),
|
publishedAt: DateTime.now(),
|
||||||
visibility: state.visibility.value,
|
visibility: state.visibility.value,
|
||||||
content: state.contentController.text,
|
content: state.contentController.text,
|
||||||
type: postType,
|
type: state.postType,
|
||||||
meta: null,
|
meta: null,
|
||||||
viewsUnique: 0,
|
viewsUnique: 0,
|
||||||
viewsTotal: 0,
|
viewsTotal: 0,
|
||||||
@ -252,9 +253,8 @@ class ComposeLogic {
|
|||||||
|
|
||||||
static Future<void> saveDraftWithoutUpload(
|
static Future<void> saveDraftWithoutUpload(
|
||||||
WidgetRef ref,
|
WidgetRef ref,
|
||||||
ComposeState state, {
|
ComposeState state,
|
||||||
int postType = 0,
|
) async {
|
||||||
}) async {
|
|
||||||
final hasContent =
|
final hasContent =
|
||||||
state.titleController.text.trim().isNotEmpty ||
|
state.titleController.text.trim().isNotEmpty ||
|
||||||
state.descriptionController.text.trim().isNotEmpty ||
|
state.descriptionController.text.trim().isNotEmpty ||
|
||||||
@ -279,7 +279,7 @@ class ComposeLogic {
|
|||||||
publishedAt: DateTime.now(),
|
publishedAt: DateTime.now(),
|
||||||
visibility: state.visibility.value,
|
visibility: state.visibility.value,
|
||||||
content: state.contentController.text,
|
content: state.contentController.text,
|
||||||
type: postType,
|
type: state.postType,
|
||||||
meta: null,
|
meta: null,
|
||||||
viewsUnique: 0,
|
viewsUnique: 0,
|
||||||
viewsTotal: 0,
|
viewsTotal: 0,
|
||||||
@ -333,54 +333,7 @@ class ComposeLogic {
|
|||||||
BuildContext context,
|
BuildContext context,
|
||||||
) async {
|
) async {
|
||||||
try {
|
try {
|
||||||
final draft = SnPost(
|
await saveDraft(ref, state);
|
||||||
id: state.draftId,
|
|
||||||
title: state.titleController.text,
|
|
||||||
description: state.descriptionController.text,
|
|
||||||
language: null,
|
|
||||||
editedAt: null,
|
|
||||||
publishedAt: DateTime.now(),
|
|
||||||
visibility: state.visibility.value,
|
|
||||||
content: state.contentController.text,
|
|
||||||
type: 0,
|
|
||||||
meta: null,
|
|
||||||
viewsUnique: 0,
|
|
||||||
viewsTotal: 0,
|
|
||||||
upvotes: 0,
|
|
||||||
downvotes: 0,
|
|
||||||
repliesCount: 0,
|
|
||||||
threadedPostId: null,
|
|
||||||
threadedPost: null,
|
|
||||||
repliedPostId: null,
|
|
||||||
repliedPost: null,
|
|
||||||
forwardedPostId: null,
|
|
||||||
forwardedPost: null,
|
|
||||||
attachments: [], // TODO: Handle attachments
|
|
||||||
publisher: SnPublisher(
|
|
||||||
id: '',
|
|
||||||
type: 0,
|
|
||||||
name: '',
|
|
||||||
nick: '',
|
|
||||||
picture: null,
|
|
||||||
background: null,
|
|
||||||
account: null,
|
|
||||||
accountId: null,
|
|
||||||
createdAt: DateTime.now(),
|
|
||||||
updatedAt: DateTime.now(),
|
|
||||||
deletedAt: null,
|
|
||||||
realmId: null,
|
|
||||||
verification: null,
|
|
||||||
),
|
|
||||||
reactions: [],
|
|
||||||
tags: [],
|
|
||||||
categories: [],
|
|
||||||
collections: [],
|
|
||||||
createdAt: DateTime.now(),
|
|
||||||
updatedAt: DateTime.now(),
|
|
||||||
deletedAt: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
await ref.read(composeStorageNotifierProvider.notifier).saveDraft(draft);
|
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
showSnackBar('draftSaved'.tr());
|
showSnackBar('draftSaved'.tr());
|
||||||
@ -535,7 +488,6 @@ class ComposeLogic {
|
|||||||
SnPost? originalPost,
|
SnPost? originalPost,
|
||||||
SnPost? repliedPost,
|
SnPost? repliedPost,
|
||||||
SnPost? forwardedPost,
|
SnPost? forwardedPost,
|
||||||
int? postType, // 0 for regular post, 1 for article
|
|
||||||
}) async {
|
}) async {
|
||||||
if (state.submitting.value) return;
|
if (state.submitting.value) return;
|
||||||
|
|
||||||
@ -581,7 +533,7 @@ class ComposeLogic {
|
|||||||
.where((e) => e.isOnCloud)
|
.where((e) => e.isOnCloud)
|
||||||
.map((e) => e.data.id)
|
.map((e) => e.data.id)
|
||||||
.toList(),
|
.toList(),
|
||||||
if (postType != null) 'type': postType,
|
'type': state.postType,
|
||||||
if (repliedPost != null) 'replied_post_id': repliedPost.id,
|
if (repliedPost != null) 'replied_post_id': repliedPost.id,
|
||||||
if (forwardedPost != null) 'forwarded_post_id': forwardedPost.id,
|
if (forwardedPost != null) 'forwarded_post_id': forwardedPost.id,
|
||||||
'tags': state.tagsController.getTags,
|
'tags': state.tagsController.getTags,
|
||||||
@ -599,7 +551,7 @@ class ComposeLogic {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Delete draft after successful submission
|
// Delete draft after successful submission
|
||||||
if (postType == 1) {
|
if (state.postType == 1) {
|
||||||
// Delete article draft
|
// Delete article draft
|
||||||
await ref
|
await ref
|
||||||
.read(composeStorageNotifierProvider.notifier)
|
.read(composeStorageNotifierProvider.notifier)
|
||||||
@ -642,7 +594,6 @@ class ComposeLogic {
|
|||||||
SnPost? originalPost,
|
SnPost? originalPost,
|
||||||
SnPost? repliedPost,
|
SnPost? repliedPost,
|
||||||
SnPost? forwardedPost,
|
SnPost? forwardedPost,
|
||||||
int? postType,
|
|
||||||
}) {
|
}) {
|
||||||
if (event is! RawKeyDownEvent) return;
|
if (event is! RawKeyDownEvent) return;
|
||||||
|
|
||||||
@ -663,7 +614,6 @@ class ComposeLogic {
|
|||||||
originalPost: originalPost,
|
originalPost: originalPost,
|
||||||
repliedPost: repliedPost,
|
repliedPost: repliedPost,
|
||||||
forwardedPost: forwardedPost,
|
forwardedPost: forwardedPost,
|
||||||
postType: postType,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -242,6 +242,47 @@ class PostItem extends HookConsumerWidget {
|
|||||||
? EdgeInsets.only(bottom: 8)
|
? EdgeInsets.only(bottom: 8)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
|
// Render tags and categories if they exist
|
||||||
|
if (item.tags.isNotEmpty || item.categories.isNotEmpty)
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if (item.tags.isNotEmpty)
|
||||||
|
Wrap(
|
||||||
|
children: [
|
||||||
|
for (final tag in item.tags)
|
||||||
|
InkWell(
|
||||||
|
child: Row(
|
||||||
|
spacing: 4,
|
||||||
|
children: [
|
||||||
|
const Icon(Symbols.label, size: 13),
|
||||||
|
Text(tag.name ?? '#${tag.slug}')
|
||||||
|
.fontSize(13)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (item.categories.isNotEmpty)
|
||||||
|
Wrap(
|
||||||
|
children: [
|
||||||
|
for (final category in item.categories)
|
||||||
|
InkWell(
|
||||||
|
child: Row(
|
||||||
|
spacing: 4,
|
||||||
|
children: [
|
||||||
|
const Icon(Symbols.category, size: 13),
|
||||||
|
Text(category.name ?? '#${category.slug}')
|
||||||
|
.fontSize(13)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
// Show truncation hint if post is truncated
|
// Show truncation hint if post is truncated
|
||||||
if (item.isTruncated && !isFullPost)
|
if (item.isTruncated && !isFullPost)
|
||||||
_PostTruncateHint().padding(
|
_PostTruncateHint().padding(
|
||||||
|
@ -2301,10 +2301,11 @@ packages:
|
|||||||
textfield_tags:
|
textfield_tags:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: textfield_tags
|
path: "."
|
||||||
sha256: d1f2204114157a1296bb97c20d7f8c8c7fd036212812afb2e19de7bb34acc55b
|
ref: "fixes/allow-controller-re-registration"
|
||||||
url: "https://pub.dev"
|
resolved-ref: "7574e79649e34df1c3cc0c49b2f0cc2b92de6a7b"
|
||||||
source: hosted
|
url: "https://github.com/lionelmennig/textfield_tags.git"
|
||||||
|
source: git
|
||||||
version: "3.0.1"
|
version: "3.0.1"
|
||||||
timezone:
|
timezone:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
|
@ -122,7 +122,10 @@ dependencies:
|
|||||||
share_plus: ^11.0.0
|
share_plus: ^11.0.0
|
||||||
receive_sharing_intent: ^1.8.1
|
receive_sharing_intent: ^1.8.1
|
||||||
top_snackbar_flutter: ^3.3.0
|
top_snackbar_flutter: ^3.3.0
|
||||||
textfield_tags: ^3.0.1
|
textfield_tags:
|
||||||
|
git:
|
||||||
|
url: https://github.com/lionelmennig/textfield_tags.git
|
||||||
|
ref: fixes/allow-controller-re-registration
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user