Skip to content

Commit

Permalink
Merge pull request #751 from micahmo/feature/username-community-mentions
Browse files Browse the repository at this point in the history
Add initial support for username/community mentions
  • Loading branch information
hjiangsu committed Oct 2, 2023
2 parents 330bf57 + b8757da commit af1eba9
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 69 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 17 additions & 0 deletions lib/community/pages/create_post_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -288,7 +289,23 @@ class _CreatePostPageState extends State<CreatePostPage> {
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)),
),
Expand Down
18 changes: 18 additions & 0 deletions lib/post/pages/create_comment_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -336,7 +338,23 @@ class _CreateCommentPageState extends State<CreateCommentPage> {
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(
Expand Down
142 changes: 78 additions & 64 deletions lib/shared/input_dialogs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<Iterable<PersonViewSafe>> 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)),
),
),
),
);
}

Expand Down Expand Up @@ -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<Iterable<CommunityView>> 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)),
),
),
),
);
}

Expand Down
6 changes: 3 additions & 3 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit af1eba9

Please sign in to comment.