♻️ Refactored the post compose sheet

This commit is contained in:
2025-10-28 01:10:18 +08:00
parent 5f4cdf7937
commit a7990f83db
9 changed files with 501 additions and 109 deletions

View File

@@ -7,8 +7,13 @@ import 'package:island/models/post.dart';
import 'package:island/screens/posts/compose.dart';
import 'package:island/services/compose_storage_db.dart';
import 'package:island/services/event_bus.dart';
import 'package:island/services/responsive.dart';
import 'package:island/widgets/content/sheet.dart';
import 'package:island/widgets/post/compose_card.dart';
import 'package:island/widgets/post/compose_settings_sheet.dart';
import 'package:island/widgets/post/compose_shared.dart';
import 'package:island/widgets/post/compose_state_utils.dart';
import 'package:island/widgets/post/compose_submit_utils.dart';
import 'package:material_symbols_icons/symbols.dart';
/// A dialog that wraps PostComposeCard for easy use in dialogs.
/// This provides a convenient way to show the compose interface in a modal dialog.
@@ -29,16 +34,15 @@ class PostComposeDialog extends HookConsumerWidget {
SnPost? originalPost,
PostComposeInitialState? initialState,
}) {
return showDialog<bool>(
return showModalBottomSheet<bool>(
context: context,
isScrollControlled: true,
useRootNavigator: true,
builder:
(context) => Padding(
padding: EdgeInsets.all(16),
child: PostComposeDialog(
originalPost: originalPost,
initialState: initialState,
),
(context) => PostComposeDialog(
originalPost: originalPost,
initialState: initialState,
isBottomSheet: true,
),
);
}
@@ -48,7 +52,41 @@ class PostComposeDialog extends HookConsumerWidget {
final drafts = ref.watch(composeStorageNotifierProvider);
final restoredInitialState = useState<PostComposeInitialState?>(null);
final prompted = useState(false);
final isWide = isWideScreen(context);
final repliedPost = initialState?.replyingTo ?? originalPost?.repliedPost;
final forwardedPost =
initialState?.forwardingTo ?? originalPost?.forwardedPost;
// Create compose state
final state = useMemoized(
() => ComposeLogic.createState(
originalPost: originalPost,
forwardedPost: forwardedPost,
repliedPost: repliedPost,
postType: 0,
),
[originalPost, forwardedPost, repliedPost],
);
// Add a listener to the entire state to trigger rebuilds
final stateNotifier = useMemoized(
() => Listenable.merge([
state.titleController,
state.descriptionController,
state.contentController,
state.visibility,
state.attachments,
state.attachmentProgress,
state.currentPublisher,
state.submitting,
]),
[state],
);
useListenable(stateNotifier);
// Use shared state management utilities
ComposeStateUtils.usePublisherInitialization(ref, state);
ComposeStateUtils.useInitialStateLoader(state, initialState);
useEffect(() {
if (!prompted.value &&
@@ -64,24 +102,69 @@ class PostComposeDialog extends HookConsumerWidget {
return null;
}, [drafts, prompted.value]);
return Dialog(
insetPadding: isWide ? const EdgeInsets.all(16) : EdgeInsets.zero,
child: ConstrainedBox(
constraints:
isWide
? const BoxConstraints(maxWidth: 600)
: const BoxConstraints.expand(),
child: PostComposeCard(
originalPost: originalPost,
initialState: restoredInitialState.value ?? initialState,
onCancel: () => Navigator.of(context).pop(),
onSubmit: () {
// Fire event to notify listeners that a post was created
eventBus.fire(PostCreatedEvent());
Navigator.of(context).pop(true);
},
isDialog: true,
),
// Helper methods for actions
void showSettingsSheet() {
showModalBottomSheet(
context: context,
isScrollControlled: true,
useRootNavigator: true,
builder: (context) => ComposeSettingsSheet(state: state),
);
}
Future<void> performSubmit() async {
await ComposeSubmitUtils.performSubmit(
ref,
state,
context,
originalPost: originalPost,
repliedPost: repliedPost,
forwardedPost: forwardedPost,
onSuccess: () {
// Fire event to notify listeners that a post was created
eventBus.fire(PostCreatedEvent());
Navigator.of(context).pop(true);
},
);
}
final actions = [
IconButton(
icon: const Icon(Symbols.settings),
onPressed: showSettingsSheet,
tooltip: 'postSettings'.tr(),
),
IconButton(
onPressed:
(state.submitting.value || state.currentPublisher.value == null)
? null
: performSubmit,
icon:
state.submitting.value
? SizedBox(
width: 24,
height: 24,
child: const CircularProgressIndicator(strokeWidth: 2),
)
: Icon(originalPost != null ? Symbols.edit : Symbols.upload),
tooltip: originalPost != null ? 'postUpdate'.tr() : 'postPublish'.tr(),
),
];
return SheetScaffold(
titleText: 'postCompose'.tr(),
actions: actions,
child: PostComposeCard(
originalPost: originalPost,
initialState: restoredInitialState.value ?? initialState,
onCancel: () => Navigator.of(context).pop(),
onSubmit: () {
// Fire event to notify listeners that a post was created
eventBus.fire(PostCreatedEvent());
Navigator.of(context).pop(true);
},
isContained: true,
showHeader: false,
),
);
}