Skip to content

Commit fb0d48c

Browse files
authored
Merge pull request #3169 from acterglobal/ben-other-mentions
Switch to SimplyMentions, ditch AppFlowy for Chat
2 parents 0d04250 + b1c00af commit fb0d48c

File tree

11 files changed

+370
-297
lines changed

11 files changed

+370
-297
lines changed

.changes/simply-mentions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Replace Chat Input Text field with a simplified editor that only support mentions, while we try to tackle all the problems the feature-rich editor is causing

app/lib/common/toolkit/html_editor/mentions/mention_menu.dart

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -148,53 +148,48 @@ class MentionMenu {
148148
// render based on mention type
149149
final Widget listWidget = switch (mentionType) {
150150
MentionType.user => UserMentionList(
151-
editorState: editorState,
152151
onDismiss: dismiss,
153152
onShow: () => show(context),
154153
roomId: roomId,
155154
onSelected: _select,
156155
),
157156
MentionType.room => RoomMentionList(
158-
editorState: editorState,
159157
onDismiss: dismiss,
160158
onShow: () => show(context),
161159
roomId: roomId,
162160
onSelected: _select,
163161
),
164162
};
165163
_menuEntry = OverlayEntry(
166-
builder:
167-
(context) => Positioned(
168-
top: max(0, bottom - maxHeight),
169-
height: maxHeight.toDouble(),
170-
left: isWide ? editorPosition.dx : 12,
171-
right: isWide ? editorPosition.dx : 12,
172-
child: Align(
173-
alignment: Alignment.bottomLeft,
174-
child: TapRegion(
175-
behavior: HitTestBehavior.opaque,
176-
onTapOutside: (event) => dismiss(),
177-
child: Material(
178-
elevation: 8,
179-
borderRadius: BorderRadius.circular(8),
180-
child: Container(
181-
constraints: BoxConstraints(
182-
maxHeight: maxHeight.toDouble(),
183-
),
184-
padding: const EdgeInsets.only(bottom: 12),
185-
decoration: BoxDecoration(
186-
color: Theme.of(context).colorScheme.surface,
187-
borderRadius: BorderRadius.only(
188-
topLeft: Radius.circular(8),
189-
topRight: Radius.circular(8),
190-
),
191-
),
192-
child: listWidget,
164+
builder: (context) => Positioned(
165+
top: max(0, bottom - maxHeight),
166+
height: maxHeight.toDouble(),
167+
left: isWide ? editorPosition.dx : 12,
168+
right: isWide ? editorPosition.dx : 12,
169+
child: Align(
170+
alignment: Alignment.bottomLeft,
171+
child: TapRegion(
172+
behavior: HitTestBehavior.opaque,
173+
onTapOutside: (event) => dismiss(),
174+
child: Material(
175+
elevation: 8,
176+
borderRadius: BorderRadius.circular(8),
177+
child: Container(
178+
constraints: BoxConstraints(maxHeight: maxHeight.toDouble()),
179+
padding: const EdgeInsets.only(bottom: 12),
180+
decoration: BoxDecoration(
181+
color: Theme.of(context).colorScheme.surface,
182+
borderRadius: BorderRadius.only(
183+
topLeft: Radius.circular(8),
184+
topRight: Radius.circular(8),
193185
),
194186
),
187+
child: listWidget,
195188
),
196189
),
197190
),
191+
),
192+
),
198193
);
199194

200195
Overlay.of(context).insert(_menuEntry!);

app/lib/common/toolkit/html_editor/mentions/widgets/mention_list.dart

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,16 @@ import 'package:acter/common/toolkit/html_editor/mentions/selected_mention_provi
55
import 'package:acter_avatar/acter_avatar.dart';
66
import 'package:acter/l10n/generated/l10n.dart';
77
import 'package:flutter/material.dart';
8-
import 'package:appflowy_editor/appflowy_editor.dart';
98
import 'package:flutter_riverpod/flutter_riverpod.dart';
109

1110
class UserMentionList extends ConsumerWidget {
12-
final EditorState editorState;
1311
final VoidCallback onDismiss;
1412
final VoidCallback onShow;
1513
final String roomId;
1614
final MentionSelectedFn onSelected;
1715

1816
const UserMentionList({
1917
super.key,
20-
required this.editorState,
2118
required this.onDismiss,
2219
required this.onShow,
2320
required this.roomId,
@@ -26,7 +23,6 @@ class UserMentionList extends ConsumerWidget {
2623
@override
2724
Widget build(BuildContext context, WidgetRef ref) => MentionList(
2825
roomId: roomId,
29-
editorState: editorState,
3026
onDismiss: onDismiss,
3127
onShow: onShow,
3228
// the actual provider
@@ -41,20 +37,18 @@ class UserMentionList extends ConsumerWidget {
4137
// the fields
4238
headerTitle: L10n.of(context).users,
4339
notFoundTitle: L10n.of(context).noUserFoundTitle,
44-
onSelected:
45-
(id, displayName) => onSelected(MentionType.user, id, displayName),
40+
onSelected: (id, displayName) =>
41+
onSelected(MentionType.user, id, displayName),
4642
);
4743
}
4844

4945
class RoomMentionList extends StatelessWidget {
50-
final EditorState editorState;
5146
final VoidCallback onDismiss;
5247
final VoidCallback onShow;
5348
final String roomId;
5449
final MentionSelectedFn onSelected;
5550
const RoomMentionList({
5651
super.key,
57-
required this.editorState,
5852
required this.onDismiss,
5953
required this.onShow,
6054
required this.roomId,
@@ -63,7 +57,6 @@ class RoomMentionList extends StatelessWidget {
6357
@override
6458
Widget build(BuildContext context) => MentionList(
6559
roomId: roomId,
66-
editorState: editorState,
6760
onDismiss: onDismiss,
6861
onShow: onShow,
6962
// the actual provider
@@ -76,16 +69,15 @@ class RoomMentionList extends StatelessWidget {
7669
headerTitle: L10n.of(context).chats,
7770
notFoundTitle: L10n.of(context).noChatsFound,
7871
selectedIndexProvider: selectedRoomMentionProvider(roomId),
79-
onSelected:
80-
(id, displayName) => onSelected(MentionType.room, id, displayName),
72+
onSelected: (id, displayName) =>
73+
onSelected(MentionType.room, id, displayName),
8174
);
8275
}
8376

8477
class MentionList extends ConsumerStatefulWidget {
8578
const MentionList({
8679
super.key,
8780
required this.roomId,
88-
required this.editorState,
8981
required this.mentionsProvider,
9082
required this.avatarBuilder,
9183
required this.headerTitle,
@@ -97,7 +89,6 @@ class MentionList extends ConsumerStatefulWidget {
9789
});
9890

9991
final String roomId;
100-
final EditorState editorState;
10192
final ProviderBase<Map<String, String>?> mentionsProvider;
10293
final AvatarOptions Function(String matchId, WidgetRef ref) avatarBuilder;
10394
final String headerTitle;
@@ -152,12 +143,8 @@ class MentionHandlerState extends ConsumerState<MentionList> {
152143
shrinkWrap: true,
153144
controller: _scrollController,
154145
itemCount: filteredSuggestions.length,
155-
separatorBuilder:
156-
(context, index) => Divider(
157-
indent: 70,
158-
color: theme.unselectedWidgetColor,
159-
height: 1,
160-
),
146+
separatorBuilder: (context, index) =>
147+
Divider(indent: 70, color: theme.unselectedWidgetColor, height: 1),
161148
itemBuilder: (context, index) {
162149
final mentionId = filteredSuggestions.keys.elementAt(index);
163150
final displayName = filteredSuggestions.values.elementAt(index);
@@ -167,9 +154,8 @@ class MentionHandlerState extends ConsumerState<MentionList> {
167154
displayName: displayName,
168155
avatarOptions: options(mentionId, ref),
169156
selected: index == ref.watch(widget.selectedIndexProvider),
170-
onTap:
171-
(String id, {String? displayName}) =>
172-
widget.onSelected(id, displayName),
157+
onTap: (String id, {String? displayName}) =>
158+
widget.onSelected(id, displayName),
173159
);
174160
},
175161
),

app/lib/features/chat_ng/actions/send_message_action.dart

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import 'package:acter/common/providers/chat_providers.dart';
21
import 'package:acter/common/utils/utils.dart';
3-
import 'package:acter/common/toolkit/html_editor/html_editor.dart';
42
import 'package:acter/features/chat/providers/chat_providers.dart';
53
import 'package:acter/features/chat_ng/providers/chat_room_messages_provider.dart';
4+
import 'package:acter/features/chat_ng/widgets/chat_editor/utils.dart';
65
import 'package:acter/features/home/providers/client_providers.dart';
76
import 'package:acter_flutter_sdk/acter_flutter_sdk_ffi.dart' show MsgDraft;
8-
import 'package:appflowy_editor/appflowy_editor.dart';
97
import 'package:flutter/material.dart';
108
import 'package:flutter_easyloading/flutter_easyloading.dart';
119
import 'package:flutter_riverpod/flutter_riverpod.dart';
@@ -15,7 +13,7 @@ import 'package:logging/logging.dart';
1513

1614
// send chat message action
1715
Future<void> sendMessageAction({
18-
required EditorState textEditorState,
16+
required MarkedUpEditContent content,
1917
required String roomId,
2018
required BuildContext context,
2119
required WidgetRef ref,
@@ -27,9 +25,9 @@ Future<void> sendMessageAction({
2725
}
2826

2927
final lang = L10n.of(context);
30-
final body = textEditorState.intoMarkdown();
31-
final html = textEditorState.intoHtml();
32-
final mentions = textEditorState.extractMentions();
28+
final body = content.plainText;
29+
final html = content.htmlText;
30+
final mentions = content.userMentions;
3331

3432
if (!hasValidEditorContent(plainText: body, html: html)) {
3533
return;
@@ -72,26 +70,13 @@ Future<void> sendMessageAction({
7270
}
7371

7472
ref.read(chatInputProvider.notifier).messageSent();
75-
textEditorState.clear();
76-
77-
// also clear composed state
78-
final convo = await ref.read(chatProvider(roomId).future);
79-
final notifier = ref.read(chatEditorStateProvider.notifier);
80-
notifier.unsetActions();
81-
if (convo != null) {
82-
await convo.saveMsgDraft(
83-
textEditorState.intoMarkdown(),
84-
null,
85-
'new',
86-
null,
87-
);
88-
}
8973
} catch (e, s) {
9074
log.severe('Sending chat message failed', e, s);
9175
EasyLoading.showError(
9276
lang.failedToSend(e),
9377
duration: const Duration(seconds: 3),
9478
);
9579
ref.read(chatInputProvider.notifier).sendingFailed();
80+
rethrow;
9681
}
9782
}

app/lib/features/chat_ng/pages/chat_room.dart

Lines changed: 35 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:acter/features/chat_ng/widgets/chat_editor/chat_editor_view.dart
44
import 'package:acter/features/chat_ng/widgets/chat_messages.dart';
55
import 'package:acter/features/chat_ng/widgets/chat_room/app_bar_widget.dart';
66
import 'package:acter/features/settings/providers/app_settings_provider.dart';
7+
import 'package:acter_trigger_auto_complete/acter_trigger_autocomplete.dart';
78
import 'package:flutter/material.dart';
89
import 'package:flutter_riverpod/flutter_riverpod.dart';
910
import 'package:go_router/go_router.dart';
@@ -17,48 +18,46 @@ class ChatRoomNgPage extends ConsumerWidget {
1718

1819
@override
1920
Widget build(BuildContext context, WidgetRef ref) {
20-
return Scaffold(
21-
appBar: ChatRoomAppBarWidget(
22-
roomId: roomId,
23-
onProfileTap:
24-
() => context.pushNamed(
25-
Routes.chatProfile.name,
26-
pathParameters: {'roomId': roomId},
27-
),
28-
),
29-
body: OrientationBuilder(
30-
builder:
31-
(context, orientation) => Scaffold(
32-
resizeToAvoidBottomInset: orientation == Orientation.portrait,
33-
body: Column(
34-
children: [
35-
Expanded(
36-
child: Stack(
37-
children: [
38-
Positioned.fill(
39-
child: Opacity(
40-
opacity: 0.07,
41-
child: Container(
42-
decoration: BoxDecoration(
43-
image: DecorationImage(
44-
image: AssetImage(
45-
'assets/images/chat_bg.png',
46-
),
47-
repeat: ImageRepeat.repeat,
48-
fit: BoxFit.none,
49-
),
21+
return Portal(
22+
child: Scaffold(
23+
appBar: ChatRoomAppBarWidget(
24+
roomId: roomId,
25+
onProfileTap: () => context.pushNamed(
26+
Routes.chatProfile.name,
27+
pathParameters: {'roomId': roomId},
28+
),
29+
),
30+
body: OrientationBuilder(
31+
builder: (context, orientation) => Scaffold(
32+
resizeToAvoidBottomInset: orientation == Orientation.portrait,
33+
body: Column(
34+
children: [
35+
Expanded(
36+
child: Stack(
37+
children: [
38+
Positioned.fill(
39+
child: Opacity(
40+
opacity: 0.07,
41+
child: Container(
42+
decoration: BoxDecoration(
43+
image: DecorationImage(
44+
image: AssetImage('assets/images/chat_bg.png'),
45+
repeat: ImageRepeat.repeat,
46+
fit: BoxFit.none,
5047
),
5148
),
5249
),
5350
),
54-
Positioned.fill(child: ChatMessages(roomId: roomId)),
55-
],
56-
),
51+
),
52+
Positioned.fill(child: ChatMessages(roomId: roomId)),
53+
],
5754
),
58-
chatInput(context, ref),
59-
],
60-
),
55+
),
56+
chatInput(context, ref),
57+
],
6158
),
59+
),
60+
),
6261
),
6362
);
6463
}

0 commit comments

Comments
 (0)