From 957396898668266a9668445bbd431c00d491a50c Mon Sep 17 00:00:00 2001 From: poppingmoon <63451158+poppingmoon@users.noreply.github.com> Date: Wed, 30 Oct 2024 08:27:02 +0900 Subject: [PATCH] feat: add post form menu (#460) * feat: add post form menu * feat: add reset button to post form menu * feat: add swap cw button to post form menu --- lib/i18n/aria/aria.i18n.yaml | 2 + lib/i18n/strings.g.dart | 2 +- lib/i18n/strings_en_US.g.dart | 2 + lib/provider/post_notifier_provider.dart | 16 ++- lib/provider/post_notifier_provider.g.dart | 2 +- lib/view/widget/post_form.dart | 146 +++++++++++++++------ 6 files changed, 124 insertions(+), 46 deletions(-) diff --git a/lib/i18n/aria/aria.i18n.yaml b/lib/i18n/aria/aria.i18n.yaml index 18fb51cde..79205bc68 100644 --- a/lib/i18n/aria/aria.i18n.yaml +++ b/lib/i18n/aria/aria.i18n.yaml @@ -107,6 +107,7 @@ recentlyUsedEmojis: "Recently used emojis" renoteConfirm: "Are you sure you want to renote this note?" renoteToChannel: "Renote to a channel" renotedBy(rich): "Renoted by {user}" +reset: "Reset" rotate: "Rotate" scale: "Scale" selectIcon: "Select an icon" @@ -139,6 +140,7 @@ showTranslateButtonInNoteFooter: "Add \"Translate\" to note action menu" sinceDate: "Since" stackTrace: "Stack trace" streamingChannel: "Streaming channel" +swapCw: "Swap comments with the body" tabName: "Tab name" tabType: "Tab type" tabs: "Tabs" diff --git a/lib/i18n/strings.g.dart b/lib/i18n/strings.g.dart index 8f0e90a13..4633341a8 100644 --- a/lib/i18n/strings.g.dart +++ b/lib/i18n/strings.g.dart @@ -4,7 +4,7 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 31 -/// Strings: 54622 (1762 per locale) +/// Strings: 54624 (1762 per locale) // coverage:ignore-file // ignore_for_file: type=lint, unused_import diff --git a/lib/i18n/strings_en_US.g.dart b/lib/i18n/strings_en_US.g.dart index ee5f9b3d4..461d113db 100644 --- a/lib/i18n/strings_en_US.g.dart +++ b/lib/i18n/strings_en_US.g.dart @@ -190,6 +190,7 @@ class TranslationsAriaEnUs { const TextSpan(text: 'Renoted by '), user, ]); + String get reset => 'Reset'; String get rotate => 'Rotate'; String get scale => 'Scale'; String get selectIcon => 'Select an icon'; @@ -228,6 +229,7 @@ class TranslationsAriaEnUs { String get sinceDate => 'Since'; String get stackTrace => 'Stack trace'; String get streamingChannel => 'Streaming channel'; + String get swapCw => 'Swap comments with the body'; String get tabName => 'Tab name'; String get tabType => 'Tab type'; String get tabs => 'Tabs'; diff --git a/lib/provider/post_notifier_provider.dart b/lib/provider/post_notifier_provider.dart index 59171798f..d17e73c2f 100644 --- a/lib/provider/post_notifier_provider.dart +++ b/lib/provider/post_notifier_provider.dart @@ -282,8 +282,12 @@ class PostNotifier extends _$PostNotifier { } void setCw(String? cw) { - if ((cw == null || cw.isEmpty) && state.cw != null) { - state = state.copyWith(cw: null); + if (cw == null || cw.isEmpty) { + if (state.cw != null) { + state = state.copyWith(cw: null); + } else { + return; + } } else if (cw != state.cw) { state = state.copyWith(cw: cw); } else { @@ -468,8 +472,12 @@ class PostNotifier extends _$PostNotifier { } void setText(String? text) { - if ((text == null || text.isEmpty) && state.text != null) { - state = state.copyWith(text: null); + if (text == null || text.isEmpty) { + if (state.text != null) { + state = state.copyWith(text: null); + } else { + return; + } } else if (text != state.text) { state = state.copyWith(text: text); } else { diff --git a/lib/provider/post_notifier_provider.g.dart b/lib/provider/post_notifier_provider.g.dart index 25b9fdb5e..56c09215d 100644 --- a/lib/provider/post_notifier_provider.g.dart +++ b/lib/provider/post_notifier_provider.g.dart @@ -6,7 +6,7 @@ part of 'post_notifier_provider.dart'; // RiverpodGenerator // ************************************************************************** -String _$postNotifierHash() => r'fc224bbd9a943ee7a09a4c5a6bcee70bf4e72895'; +String _$postNotifierHash() => r'd8beee3b314a1ae828444dde84d3fff777bacc52'; /// Copied from Dart SDK class _SystemHash { diff --git a/lib/view/widget/post_form.dart b/lib/view/widget/post_form.dart index 5dd83408c..711642f25 100644 --- a/lib/view/widget/post_form.dart +++ b/lib/view/widget/post_form.dart @@ -32,6 +32,7 @@ import '../../provider/post_notifier_provider.dart'; import '../../provider/timeline_tab_settings_provider.dart'; import '../../util/extract_mentions.dart'; import '../../util/future_with_dialog.dart'; +import '../dialog/confirmation_dialog.dart'; import '../dialog/post_confirmation_dialog.dart'; import '../dialog/user_select_dialog.dart'; import '../page/channel/channels_page.dart'; @@ -271,6 +272,16 @@ class PostForm extends HookConsumerWidget { final focusNode = this.focusNode ?? useFocusNode(); final isCwFocused = useState(false); final isFocused = useState(false); + ref.listen( + postNotifierProvider(account.value, noteId: noteId) + .select((request) => request.cw), + (_, cw) { + final s = cw ?? ''; + if (s != cwController.text) { + cwController.text = s; + } + }, + ); ref.listen( postNotifierProvider(account.value, noteId: noteId) .select((request) => request.text), @@ -462,50 +473,105 @@ class PostForm extends HookConsumerWidget { ? const Icon(Icons.rocket_outlined) : const Icon(Icons.rocket), ), - IconButton( - onPressed: noteId == null - ? () async { - final result = await showModalBottomSheet< - (ReactionAcceptance?,)>( - context: context, - builder: (context) => ListView( - shrinkWrap: true, - children: [ - ListTile( - title: Text( - t.misskey.reactionAcceptance, - ), - ), - const Divider(height: 0.0), - ...[ - null, - ...ReactionAcceptance.values, - ].map( - (acceptance) => ListTile( - leading: ReactionAcceptanceIcon( - acceptance: acceptance, + PopupMenuButton( + itemBuilder: (context) => [ + PopupMenuItem( + onTap: noteId == null + ? () async { + final result = await showModalBottomSheet< + (ReactionAcceptance?,)>( + context: context, + builder: (context) => ListView( + shrinkWrap: true, + children: [ + ListTile( + title: Text( + t.misskey.reactionAcceptance, + ), ), - title: ReactionAcceptanceWidget( - acceptance: acceptance, + const Divider(height: 0.0), + ...[ + null, + ...ReactionAcceptance.values, + ].map( + (acceptance) => ListTile( + leading: ReactionAcceptanceIcon( + acceptance: acceptance, + ), + title: ReactionAcceptanceWidget( + acceptance: acceptance, + ), + onTap: () => + context.pop((acceptance,)), + ), ), - onTap: () => context.pop((acceptance,)), - ), + ], ), - ], - ), - ); - if (result != null) { - ref - .read( - postNotifierProvider(account.value) - .notifier, - ) - .setReactionAcceptance(result.$1); - } + ); + if (result != null) { + ref + .read( + postNotifierProvider(account.value) + .notifier, + ) + .setReactionAcceptance(result.$1); + } + } + : null, + child: ListTile( + leading: ReactionAcceptanceIcon( + acceptance: request.reactionAcceptance, + ), + title: Text(t.misskey.reactionAcceptance), + ), + ), + PopupMenuItem( + onTap: () { + final text = request.text; + ref + .read( + postNotifierProvider(account.value).notifier, + ) + .setText(request.cw); + ref + .read( + postNotifierProvider(account.value).notifier, + ) + .setCw(text?.replaceAll('\n', ' ')); + useCw.value = true; + }, + enabled: request.text != null || request.cw != null, + child: ListTile( + leading: const Icon(Icons.swap_vert), + title: Text(t.aria.swapCw), + ), + ), + PopupMenuItem( + onTap: () async { + final confirmed = await confirm( + context, + message: t.misskey.resetAreYouSure, + ); + if (!context.mounted) return; + if (confirmed) { + ref + .read( + postNotifierProvider(account.value).notifier, + ) + .reset(); } - : null, - icon: ReactionAcceptanceIcon( - acceptance: request.reactionAcceptance, + }, + child: ListTile( + leading: const Icon(Icons.delete), + title: Text(t.aria.reset), + iconColor: colors.error, + textColor: colors.error, + ), + ), + ], + child: const Padding( + padding: EdgeInsets.all(8.0), + child: Icon(Icons.more_horiz), ), ), if (showPostButton) ...[