diff --git a/CHANGELOG.md b/CHANGELOG.md index fa1519911..3aa3809a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ - Highlight the currently selected page in the navigation drawer - contribution from @micahmo - Newly created comments get inserted into comment list correctly without losing your scroll position. If comment is top level, the list scrolls to your comment. The comment also gets highlighted - contribution from @ajsosa - Add new actions to the post and comment bottom sheets - contribution from @micahmo +- Added buttons to quickly insert user or community mention in post or comment - contribution from @micahmo ### Changed - Prioritize and label the default accent color - contribution from @micahmo diff --git a/lib/community/pages/create_post_page.dart b/lib/community/pages/create_post_page.dart index 2614cbf34..9a387be52 100644 --- a/lib/community/pages/create_post_page.dart +++ b/lib/community/pages/create_post_page.dart @@ -12,6 +12,7 @@ import 'package:thunder/core/enums/view_mode.dart'; import 'package:thunder/feed/feed.dart'; import 'package:thunder/shared/common_markdown_body.dart'; import 'package:thunder/shared/community_icon.dart'; +import 'package:thunder/shared/input_dialogs.dart'; import 'package:thunder/shared/link_preview_card.dart'; import 'package:thunder/user/widgets/user_indicator.dart'; import 'package:thunder/shared/snackbar.dart'; @@ -288,7 +289,23 @@ class _CreatePostPageState extends State { MarkdownType.list, MarkdownType.separator, MarkdownType.code, + MarkdownType.username, + MarkdownType.community, ], + customTapActions: { + MarkdownType.username: () { + showUserInputDialog(context, title: AppLocalizations.of(context)!.username, onUserSelected: (person) { + _bodyTextController.text = _bodyTextController.text.replaceRange(_bodyTextController.selection.end, _bodyTextController.selection.end, + '[@${person.person.name}@${fetchInstanceNameFromUrl(person.person.actorId)}](${person.person.actorId})'); + }); + }, + MarkdownType.community: () { + showCommunityInputDialog(context, title: AppLocalizations.of(context)!.community, onCommunitySelected: (community) { + _bodyTextController.text = _bodyTextController.text.replaceRange(_bodyTextController.selection.end, _bodyTextController.selection.end, + '[@${community.community.title}@${fetchInstanceNameFromUrl(community.community.actorId)}](${community.community.actorId})'); + }); + }, + }, imageIsLoading: imageUploading, customImageButtonAction: () => uploadImage(context, imageBloc)), ), diff --git a/lib/post/pages/create_comment_page.dart b/lib/post/pages/create_comment_page.dart index cb5b1bd2a..4de88db41 100644 --- a/lib/post/pages/create_comment_page.dart +++ b/lib/post/pages/create_comment_page.dart @@ -14,11 +14,13 @@ import 'package:thunder/core/models/post_view_media.dart'; import 'package:thunder/inbox/bloc/inbox_bloc.dart'; import 'package:thunder/post/bloc/post_bloc.dart'; import 'package:thunder/shared/common_markdown_body.dart'; +import 'package:thunder/shared/input_dialogs.dart'; import 'package:thunder/shared/media_view.dart'; import 'package:thunder/shared/snackbar.dart'; import 'package:thunder/thunder/bloc/thunder_bloc.dart'; import 'package:thunder/user/widgets/user_indicator.dart'; import 'package:thunder/utils/image.dart'; +import 'package:thunder/utils/instance.dart'; class CreateCommentPage extends StatefulWidget { final PostViewMedia? postView; @@ -336,7 +338,23 @@ class _CreateCommentPageState extends State { MarkdownType.list, MarkdownType.separator, MarkdownType.code, + MarkdownType.username, + MarkdownType.community, ], + customTapActions: { + MarkdownType.username: () { + showUserInputDialog(context, title: AppLocalizations.of(context)!.username, onUserSelected: (person) { + _bodyTextController.text = _bodyTextController.text.replaceRange(_bodyTextController.selection.end, _bodyTextController.selection.end, + '[@${person.person.name}@${fetchInstanceNameFromUrl(person.person.actorId)}](${person.person.actorId})'); + }); + }, + MarkdownType.community: () { + showCommunityInputDialog(context, title: AppLocalizations.of(context)!.community, onCommunitySelected: (community) { + _bodyTextController.text = _bodyTextController.text.replaceRange(_bodyTextController.selection.end, _bodyTextController.selection.end, + '[@${community.community.title}@${fetchInstanceNameFromUrl(community.community.actorId)}](${community.community.actorId})'); + }); + }, + }, imageIsLoading: imageUploading, customImageButtonAction: () => uploadImage(context, imageBloc))), Padding( diff --git a/lib/shared/input_dialogs.dart b/lib/shared/input_dialogs.dart index 30480f854..b3c6aa649 100644 --- a/lib/shared/input_dialogs.dart +++ b/lib/shared/input_dialogs.dart @@ -45,39 +45,46 @@ void showUserInputDialog(BuildContext context, {required String title, required title: title, inputLabel: AppLocalizations.of(context)!.username, onSubmitted: onSubmitted, - getSuggestions: (query) async { - if (query.isNotEmpty != true) { - return const Iterable.empty(); - } - Account? account = await fetchActiveProfileAccount(); - final SearchResults searchReults = await LemmyClient.instance.lemmyApiV3.run(Search( - q: query, - auth: account?.jwt, - type: SearchType.users, - limit: 10, - )); - return searchReults.users; - }, - suggestionBuilder: (payload) { - return Tooltip( - message: '${payload.person.name}@${fetchInstanceNameFromUrl(payload.person.actorId)}', - preferBelow: false, - child: ListTile( - leading: UserAvatar(person: payload.person), - title: Text( - payload.person.displayName ?? payload.person.name, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - subtitle: TextScroll( - '${payload.person.name}@${fetchInstanceNameFromUrl(payload.person.actorId)}', - delayBefore: const Duration(seconds: 2), - pauseBetween: const Duration(seconds: 3), - velocity: const Velocity(pixelsPerSecond: Offset(50, 0)), - ), + getSuggestions: getUserSuggestions, + suggestionBuilder: (payload) => buildUserSuggestionWidget(payload), + ); +} + +Future> getUserSuggestions(String query) async { + if (query.isNotEmpty != true) { + return const Iterable.empty(); + } + Account? account = await fetchActiveProfileAccount(); + final SearchResults searchReults = await LemmyClient.instance.lemmyApiV3.run(Search( + q: query, + auth: account?.jwt, + type: SearchType.users, + limit: 10, + )); + return searchReults.users; +} + +Widget buildUserSuggestionWidget(PersonViewSafe payload, {void Function(PersonViewSafe)? onSelected}) { + return Tooltip( + message: '${payload.person.name}@${fetchInstanceNameFromUrl(payload.person.actorId)}', + preferBelow: false, + child: InkWell( + onTap: onSelected == null ? null : () => onSelected(payload), + child: ListTile( + leading: UserAvatar(person: payload.person), + title: Text( + payload.person.displayName ?? payload.person.name, + maxLines: 1, + overflow: TextOverflow.ellipsis, ), - ); - }, + subtitle: TextScroll( + '${payload.person.name}@${fetchInstanceNameFromUrl(payload.person.actorId)}', + delayBefore: const Duration(seconds: 2), + pauseBetween: const Duration(seconds: 3), + velocity: const Velocity(pixelsPerSecond: Offset(50, 0)), + ), + ), + ), ); } @@ -116,39 +123,46 @@ void showCommunityInputDialog(BuildContext context, {required String title, requ title: title, inputLabel: AppLocalizations.of(context)!.community, onSubmitted: onSubmitted, - getSuggestions: (query) async { - if (query.isNotEmpty != true) { - return const Iterable.empty(); - } - Account? account = await fetchActiveProfileAccount(); - final SearchResults searchReults = await LemmyClient.instance.lemmyApiV3.run(Search( - q: query, - auth: account?.jwt, - type: SearchType.communities, - limit: 10, - )); - return searchReults.communities; - }, - suggestionBuilder: (payload) { - return Tooltip( - message: '${payload.community.name}@${fetchInstanceNameFromUrl(payload.community.actorId)}', - preferBelow: false, - child: ListTile( - leading: CommunityIcon(community: payload.community), - title: Text( - payload.community.title, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - subtitle: TextScroll( - '${payload.community.name}@${fetchInstanceNameFromUrl(payload.community.actorId)}', - delayBefore: const Duration(seconds: 2), - pauseBetween: const Duration(seconds: 3), - velocity: const Velocity(pixelsPerSecond: Offset(50, 0)), - ), + getSuggestions: getCommunitySuggestions, + suggestionBuilder: buildCommunitySuggestionWidget, + ); +} + +Future> getCommunitySuggestions(String query) async { + if (query.isNotEmpty != true) { + return const Iterable.empty(); + } + Account? account = await fetchActiveProfileAccount(); + final SearchResults searchReults = await LemmyClient.instance.lemmyApiV3.run(Search( + q: query, + auth: account?.jwt, + type: SearchType.communities, + limit: 10, + )); + return searchReults.communities; +} + +Widget buildCommunitySuggestionWidget(payload, {void Function(CommunityView)? onSelected}) { + return Tooltip( + message: '${payload.community.name}@${fetchInstanceNameFromUrl(payload.community.actorId)}', + preferBelow: false, + child: InkWell( + onTap: onSelected == null ? null : () => onSelected(payload), + child: ListTile( + leading: CommunityIcon(community: payload.community), + title: Text( + payload.community.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, ), - ); - }, + subtitle: TextScroll( + '${payload.community.name}@${fetchInstanceNameFromUrl(payload.community.actorId)}', + delayBefore: const Duration(seconds: 2), + pauseBetween: const Duration(seconds: 3), + velocity: const Velocity(pixelsPerSecond: Offset(50, 0)), + ), + ), + ), ); } diff --git a/pubspec.lock b/pubspec.lock index da63d7815..8e7dae8e8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -748,9 +748,9 @@ packages: dependency: "direct main" description: path: "." - ref: "3ded84267bb951a1d9312a308313d47ea714d210" - resolved-ref: "3ded84267bb951a1d9312a308313d47ea714d210" - url: "https://github.com/hjiangsu/markdown-editable-textinput.git" + ref: "017c8614c59b7081f54a7af70cc9586888d53b56" + resolved-ref: "017c8614c59b7081f54a7af70cc9586888d53b56" + url: "https://github.com/thunder-app/markdown-editor.git" source: git version: "2.2.1" matcher: diff --git a/pubspec.yaml b/pubspec.yaml index f687b1074..839260a6c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,8 +20,8 @@ dependencies: path: ^1.8.3 markdown_editable_textinput: git: - url: https://github.com/hjiangsu/markdown-editable-textinput.git - ref: 3ded84267bb951a1d9312a308313d47ea714d210 + url: https://github.com/thunder-app/markdown-editor.git + ref: 017c8614c59b7081f54a7af70cc9586888d53b56 extended_image: git: url: https://github.com/hjiangsu/extended_image.git