Skip to content

Commit

Permalink
feat(post): Support edit and save draft
Browse files Browse the repository at this point in the history
* Recognize editing draft.
* Save draft as draft (without publishing).
  • Loading branch information
realth000 committed Sep 7, 2024
1 parent 7b98a89 commit b0ffe62
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 21 deletions.
1 change: 1 addition & 0 deletions lib/features/post/bloc/post_edit_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ final class PostEditBloc extends Bloc<PostEditEvent, PostEditState>
threadType: event.threadType?.typeID,
threadTitle: event.threadTitle,
data: event.data,
save: event.save,
options: Map.fromEntries(
event.options
.where((e) => !e.disabled && e.checked)
Expand Down
6 changes: 6 additions & 0 deletions lib/features/post/bloc/post_edit_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ final class PostEditCompleteEditRequested extends PostEditEvent
required this.threadTitle,
required this.data,
required this.options,
required this.save,
}) : super();

/// Form hash.
Expand Down Expand Up @@ -81,6 +82,11 @@ final class PostEditCompleteEditRequested extends PostEditEvent

/// Additional options provided by server.
final List<PostEditContentOption> options;

/// Save post as draft or publish as new thread.
///
/// Only set to "1" when editing thread in draft state.
final String save;
}

/// Fetch required info for publishing, including form hash, post time and more.
Expand Down
12 changes: 10 additions & 2 deletions lib/features/post/models/post_edit_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@ enum PostEditType {
newThread,

/// Edit an existing post.
editPost;
editPost,

/// Editing a thread that still in draft state (not published yet).
///
/// This type is similar to [newThread] and [editPost], only on editing the
/// first floor post, fetch info like [editPost] but have save-as-draft
/// action.
editDraft;

/// Check whether the edit type is editing something.
bool get isEditingPost => this == editPost;

/// Check whether the edit type is writing new thread.
bool get isDraftingNewThread => this == PostEditType.newThread;
bool get isEditingDraft =>
this == PostEditType.newThread || this == PostEditType.editDraft;
}
3 changes: 2 additions & 1 deletion lib/features/post/repository/post_edit_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ final class PostEditRepository with LoggerMixin {
required String? threadTitle,
required String data,
required Map<String, String> options,
required String save,
}) =>
AsyncVoidEither(() async {
final body = <String, String>{
Expand All @@ -72,7 +73,7 @@ final class PostEditRepository with LoggerMixin {
'subject': threadTitle ?? '',
'message': data,
'editsubmit': 'true',
'save': '',
'save': save,
};
if (threadType != null) {
body['typeid'] = threadType;
Expand Down
41 changes: 24 additions & 17 deletions lib/features/post/view/post_edit_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,6 @@ class PostEditPage extends StatefulWidget {
/// Post id of the post.
final String? pid;

static String _formatDataUrl({
required String fid,
required String tid,
required String pid,
}) {
return '$baseUrl/forum.php?mod=post&action=edit&fid=$fid&tid=$tid&pid=$pid';
}

@override
State<PostEditPage> createState() => _PostEditPageState();
}
Expand Down Expand Up @@ -184,12 +176,20 @@ class _PostEditPageState extends State<PostEditPage> with LoggerMixin {
/// * Editing thread draft.
_UploadMethod uploadMethod = _UploadMethod.notYet;

static String _formatDataUrl({
required String fid,
required String tid,
required String pid,
}) {
return '$baseUrl/forum.php?mod=post&action=edit&fid=$fid&tid=$tid&pid=$pid';
}

Future<void> _onFinish(
BuildContext context,
PostEditState state, {
bool saveDraft = false,
}) async {
if (widget.editType.isDraftingNewThread) {
if (widget.editType.isEditingDraft) {
final tr = context.t.postEditPage.threadPublish;
final ret = await showQuestionDialog(
context: context,
Expand Down Expand Up @@ -230,7 +230,9 @@ class _PostEditPageState extends State<PostEditPage> with LoggerMixin {
}

final event = switch (widget.editType) {
PostEditType.editPost => PostEditCompleteEditRequested(
PostEditType.editPost ||
PostEditType.editDraft =>
PostEditCompleteEditRequested(
formHash: state.content!.formHash,
postTime: state.content!.postTime,
delattachop: state.content?.delattachop ?? '0',
Expand All @@ -245,6 +247,7 @@ class _PostEditPageState extends State<PostEditPage> with LoggerMixin {
threadTitle: threadTitleController.text,
data: bbcodeController.toBBCode(),
options: additionalOptionsMap?.values.toList() ?? [],
save: saveDraft ? '1' : '',
),
PostEditType.newThread => ThreadPubPostThread(
ThreadPublishInfo(
Expand Down Expand Up @@ -441,7 +444,7 @@ class _PostEditPageState extends State<PostEditPage> with LoggerMixin {
: null,
),
const Spacer(),
if (widget.editType.isDraftingNewThread) ...[
if (widget.editType.isEditingDraft) ...[
FilledButton.tonal(
onPressed: state.status == PostEditStatus.uploading
? null
Expand Down Expand Up @@ -491,8 +494,10 @@ class _PostEditPageState extends State<PostEditPage> with LoggerMixin {
);

final event = switch (widget.editType) {
PostEditType.editPost => PostEditLoadDataRequested(
PostEditPage._formatDataUrl(
PostEditType.editPost ||
PostEditType.editDraft =>
PostEditLoadDataRequested(
_formatDataUrl(
fid: widget.fid,
tid: widget.tid!,
pid: widget.pid!,
Expand All @@ -518,10 +523,10 @@ class _PostEditPageState extends State<PostEditPage> with LoggerMixin {
if (state.status == PostEditStatus.failedToLoad) {
return buildRetryButton(context, () {
switch (widget.editType) {
case PostEditType.editPost:
case PostEditType.editPost || PostEditType.editDraft:
context.read<PostEditBloc>().add(
PostEditLoadDataRequested(
PostEditPage._formatDataUrl(
_formatDataUrl(
fid: widget.fid,
// Not null when editing post
tid: widget.tid!,
Expand Down Expand Up @@ -585,7 +590,7 @@ class _PostEditPageState extends State<PostEditPage> with LoggerMixin {
);
context.pop();
return;
} else if (widget.editType.isDraftingNewThread) {
} else if (widget.editType.isEditingDraft) {
// Writing new post.
//
// Ask for a redirect to just published thread page.
Expand Down Expand Up @@ -658,7 +663,9 @@ class _PostEditPageState extends State<PostEditPage> with LoggerMixin {
Widget build(BuildContext context) {
final title = switch (widget.editType) {
PostEditType.newThread => context.t.postEditPage.newThreadTitle,
PostEditType.editPost => context.t.postEditPage.editPostTitle,
PostEditType.editPost ||
PostEditType.editDraft =>
context.t.postEditPage.editPostTitle,
};
return PopScope(
canPop: false,
Expand Down
10 changes: 10 additions & 0 deletions lib/shared/models/post.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class Post with PostMappable {
required this.lastEditTime,
required this.shareLink,
required this.page,
required this.isDraft,
this.locked = const [],
this.rate,
this.packetUrl,
Expand Down Expand Up @@ -102,6 +103,12 @@ class Post with PostMappable {
/// Current page number.
final int page;

/// Flag indicating whether the post is in draft state.
///
/// Draft post only can be a first floor, equivalent to editing a thread that
/// not published yet.
final bool isDraft;

/// Build [Post] from [element] that has attribute id "post_$postID".
static Post? fromPostNode(uh.Element element, int page) {
final trRootNode = element.querySelector('table > tbody > tr');
Expand Down Expand Up @@ -281,6 +288,8 @@ class Post with PostMappable {
talker.error('post $postID: user profile node not found');
}

final isDraft = element.querySelector('a.psave') != null;

return Post(
postID: postID,
postFloor: postFloor,
Expand All @@ -298,6 +307,7 @@ class Post with PostMappable {
userBriefProfile: userBriefProfile,
shareLink: shareLink,
page: page,
isDraft: isDraft,
);
}

Expand Down
17 changes: 16 additions & 1 deletion lib/widgets/card/post_card/post_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:go_router/go_router.dart';
import 'package:tsdm_client/constants/layout.dart';
import 'package:tsdm_client/extensions/build_context.dart';
import 'package:tsdm_client/extensions/date_time.dart';
import 'package:tsdm_client/features/post/models/models.dart';
import 'package:tsdm_client/features/thread/bloc/thread_bloc.dart';
import 'package:tsdm_client/i18n/strings.g.dart';
import 'package:tsdm_client/routes/screen_paths.dart';
Expand Down Expand Up @@ -325,7 +326,21 @@ class _PostCardState extends State<PostCard>
// not-null author uid.
context.read<ThreadBloc>().add(ThreadViewAllAuthorsRequested());
case _PostCardActions.edit:
await context.dispatchAsUrl(widget.post.editUrl!);
final url = Uri.parse(widget.post.editUrl!);
final editType = widget.post.isDraft
? PostEditType.editDraft.index
: PostEditType.editPost.index;
await context.pushNamed(
ScreenPaths.editPost,
pathParameters: {
'editType': '$editType',
'fid': '${url.queryParameters["fid"]}',
},
queryParameters: {
'tid': '${url.queryParameters["tid"]}',
'pid': '${url.queryParameters["pid"]}',
},
);
case _PostCardActions.share:
await copyToClipboard(context, widget.post.shareLink!);
}
Expand Down

0 comments on commit b0ffe62

Please sign in to comment.