Skip to content

Commit

Permalink
fix: change query for mfm keyboard
Browse files Browse the repository at this point in the history
  • Loading branch information
poppingmoon committed Dec 9, 2024
1 parent f059c18 commit 1440400
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 21 deletions.
5 changes: 3 additions & 2 deletions lib/view/dialog/user_select_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import '../../model/account.dart';
import '../../provider/api/i_notifier_provider.dart';
import '../../provider/api/search_users_by_username_provider.dart';
import '../../provider/recently_used_users_notifier_provider.dart';
import '../../util/punycode.dart';
import '../widget/error_message.dart';
import '../widget/user_preview.dart';
import '../widget/user_sheet.dart';
Expand Down Expand Up @@ -51,8 +52,8 @@ class UserSelectDialog extends HookConsumerWidget {
? ref.watch(
searchUsersByUsernameProvider(
account,
username.value,
host.value,
username.value.isNotEmpty ? username.value : null,
host.value.isNotEmpty ? toAscii(host.value) : null,
),
)
: null;
Expand Down
38 changes: 24 additions & 14 deletions lib/view/widget/mfm_keyboard.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import '../../provider/recently_used_users_notifier_provider.dart';
import '../../provider/search_custom_emojis_provider.dart';
import '../../provider/search_unicode_emojis_provider.dart';
import '../../util/pick_date_time.dart';
import '../../util/punycode.dart';
import '../dialog/user_select_dialog.dart';
import 'emoji_picker.dart';
import 'emoji_widget.dart';
Expand Down Expand Up @@ -250,7 +251,8 @@ class MfmEmojiKeyboard extends HookConsumerWidget {
final selectionIndex = max(0, controller.selection.start);
final textBeforeSelection =
controller.text.substring(0, selectionIndex);
final match = RegExp(r':?(\S*)$').firstMatch(textBeforeSelection);
final match = RegExp(r':(\S*)$').firstMatch(textBeforeSelection) ??
RegExp(r'(\S*)$').firstMatch(textBeforeSelection);
query.value = match?[1] ?? '';
final tagIndex = selectionIndex - (match?[0]?.length ?? 0) + 1;
isAfterCloseTag.value =
Expand Down Expand Up @@ -413,9 +415,9 @@ class MfmFnKeyboard extends HookConsumerWidget {
final selectionIndex = max(0, controller.selection.start);
final textBeforeSelection =
controller.text.substring(0, selectionIndex);
query.value =
RegExp(r'(\$\[)?(\S*)$').firstMatch(textBeforeSelection)?[2] ??
'';
final match = RegExp(r'\$\[(\S*)$').firstMatch(textBeforeSelection) ??
RegExp(r'(\S*)$').firstMatch(textBeforeSelection);
query.value = match?[1] ?? '';
periodIndex.value = query.value.indexOf('.');
}

Expand Down Expand Up @@ -583,17 +585,23 @@ class MfmMentionKeyboard extends HookConsumerWidget {
final selectionIndex = max(0, controller.selection.start);
final textBeforeSelection =
controller.text.substring(0, selectionIndex);
query.value =
RegExp(r'@?(\S*)$').firstMatch(textBeforeSelection)?[1] ?? '';
if (query.value case final query when query.isNotEmpty) {
final acct = query.split('@');
final match = RegExp(r'(@([a-zA-Z0-9_.-]+))?@([^@\s]*)$')
.firstMatch(textBeforeSelection);
query.value = match?[0]?.substring(1) ?? '';
final first = match?[2];
final second = match?[3];
final username = first ?? second;
final host = first != null && second != null ? toAscii(second) : null;
if (username != null) {
users.value = await ref.read(
searchUsersByUsernameProvider(
account,
acct.first,
acct.elementAtOrNull(1),
username,
host,
).future,
);
} else {
users.value = [];
}
}

Expand All @@ -617,8 +625,9 @@ class MfmMentionKeyboard extends HookConsumerWidget {
account: account,
username: user.username,
host: user.host ?? account.host,
onTap: () => controller.insert(
'${user.acct.substring(query.value.length + 1)} ',
onTap: () => controller.replace(
query.value.length + 1,
'${user.acct} ',
),
),
),
Expand Down Expand Up @@ -653,8 +662,9 @@ class MfmHashtagKeyboard extends HookConsumerWidget {
final selectionIndex = max(0, controller.selection.start);
final textBeforeSelection =
controller.text.substring(0, selectionIndex);
query.value =
RegExp(r'#?(\S*)$').firstMatch(textBeforeSelection)?[1] ?? '';
final match = RegExp(r'#(\S*)$').firstMatch(textBeforeSelection) ??
RegExp(r'(\S*)$').firstMatch(textBeforeSelection);
query.value = match?[1] ?? '';
if (query.value case final query when query.isNotEmpty) {
hashtags.value =
await ref.read(searchHashtagsProvider(account, query).future);
Expand Down
78 changes: 73 additions & 5 deletions test/view/widget/mfm_keyboard_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,10 @@ Future<ProviderContainer> setupWidget(

void main() {
group('getLastTag', () {
final controller = TextEditingController();
final widget =
MfmKeyboard(account: Account.dummy(), controller: controller);

test('emoji', () {
final controller = TextEditingController();
final widget =
MfmKeyboard(account: Account.dummy(), controller: controller);
controller.text = ':';
controller.selection = const TextSelection.collapsed(offset: 0);
expect(widget.getLastTag(), equals((null, -1)));
Expand All @@ -58,6 +57,9 @@ void main() {
});

test('mfmFn', () {
final controller = TextEditingController();
final widget =
MfmKeyboard(account: Account.dummy(), controller: controller);
controller.text = r'$[';
controller.selection = const TextSelection.collapsed(offset: 0);
expect(widget.getLastTag(), equals((null, -1)));
Expand All @@ -74,6 +76,9 @@ void main() {
});

test('mention', () {
final controller = TextEditingController();
final widget =
MfmKeyboard(account: Account.dummy(), controller: controller);
controller.text = '@';
controller.selection = const TextSelection.collapsed(offset: 0);
expect(widget.getLastTag(), equals((null, -1)));
Expand All @@ -87,6 +92,9 @@ void main() {
});

test('hashtag', () {
final controller = TextEditingController();
final widget =
MfmKeyboard(account: Account.dummy(), controller: controller);
controller.text = '#';
controller.selection = const TextSelection.collapsed(offset: 0);
expect(widget.getLastTag(), equals((null, -1)));
Expand All @@ -100,6 +108,9 @@ void main() {
});

test('mixed', () {
final controller = TextEditingController();
final widget =
MfmKeyboard(account: Account.dummy(), controller: controller);
controller.text = r':emoji: #hashtag $[tada a] @user';
controller.selection = const TextSelection.collapsed(offset: 0);
expect(widget.getLastTag(), equals((null, -1)));
Expand Down Expand Up @@ -166,6 +177,26 @@ void main() {
expect(controller.text, '❤️');
});

testWidgets(
'should show an emoji keyboard if an open tag is between characters',
(tester) async {
const account = Account(host: 'misskey.tld', username: 'testuser');
final controller = TextEditingController(text: 'a:b');
controller.selection = const TextSelection.collapsed(offset: 2);
final container = await setupWidget(
tester,
account: account,
controller: controller,
);
await container
.read(accountSettingsNotifierProvider(account).notifier)
.setRecentlyUsedEmojis(['❤️']);
await tester.pumpAndSettle();
await tester.tap(find.byKey(const ValueKey('❤️')));
expect(controller.text, 'a❤️b');
},
);

testWidgets('should not show an emoji keyboard after a close tag',
(tester) async {
const account = Account(host: 'misskey.tld', username: 'testuser');
Expand Down Expand Up @@ -252,6 +283,23 @@ void main() {
expect(controller.text, r'$[spin.speed=1.5s,x');
});

testWidgets(
'should show an MFM fn keyboard if an open tag is between characters',
(tester) async {
const account = Account(host: 'misskey.tld', username: 'testuser');
final controller = TextEditingController(text: r'a$[b');
controller.selection = const TextSelection.collapsed(offset: 3);
await setupWidget(
tester,
account: account,
controller: controller,
);
await tester.pumpAndSettle();
await tester.tap(find.text('tada'));
expect(controller.text, r'a$[tada b');
},
);

testWidgets('should not show an MFM fn keyboard after a close tag',
(tester) async {
const account = Account(host: 'misskey.tld', username: 'testuser');
Expand Down Expand Up @@ -349,7 +397,27 @@ void main() {
expect(controller.text, '@[email protected] ');
});

testWidgets('should not show an mention keyboard after a space',
testWidgets(
'should show a mention keyboard if an open tag is between characters',
(tester) async {
const account = Account(host: 'misskey.tld', username: 'testuser');
final controller = TextEditingController(text: 'a:b');
controller.selection = const TextSelection.collapsed(offset: 2);
final container = await setupWidget(
tester,
account: account,
controller: controller,
);
await container
.read(accountSettingsNotifierProvider(account).notifier)
.setRecentlyUsedEmojis(['❤️']);
await tester.pumpAndSettle();
await tester.tap(find.byKey(const ValueKey('❤️')));
expect(controller.text, 'a❤️b');
},
);

testWidgets('should not show a mention keyboard after a space',
(tester) async {
const account = Account(host: 'misskey.tld', username: 'testuser');
final controller = TextEditingController();
Expand Down

0 comments on commit 1440400

Please sign in to comment.