Skip to content

Commit

Permalink
TW-1469: Fix the cursor automatically focus when changing reply a mes…
Browse files Browse the repository at this point in the history
…sage
  • Loading branch information
nqhhdev authored and hoangdat committed Mar 1, 2024
1 parent 6ac4dde commit 495782e
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 54 deletions.
118 changes: 72 additions & 46 deletions lib/pages/chat/chat.dart
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ class ChatController extends State<Chat>

final Set<String> unfolded = {};

Event? replyEvent;
final replyEventNotifier = ValueNotifier<Event?>(null);

Event? editEvent;

Expand Down Expand Up @@ -504,7 +504,7 @@ class ChatController extends State<Chat>
// ignore: unawaited_futures
room!.sendTextEvent(
sendController.text.trim(),
inReplyTo: replyEvent,
inReplyTo: replyEventNotifier.value,
editEventId: editEvent?.eventId,
parseCommands: parseCommands,
);
Expand All @@ -514,8 +514,8 @@ class ChatController extends State<Chat>
);
setReadMarker();
inputText.value = pendingText;
_updateReplyEvent();
setState(() {
replyEvent = null;
editEvent = null;
pendingText = '';
});
Expand Down Expand Up @@ -614,9 +614,7 @@ class ChatController extends State<Chat>
// );
// return null;
// });
setState(() {
replyEvent = null;
});
_updateReplyEvent();
}

void onEmojiAction() {
Expand All @@ -625,7 +623,7 @@ class ChatController extends State<Chat>
if (PlatformInfos.isMobile) {
hideKeyboardChatScreen();
} else {
inputFocus.requestFocus();
_requestInputFocus();
}
}

Expand All @@ -646,9 +644,7 @@ class ChatController extends State<Chat>
await event.copyTextEvent(context, timeline!);

showEmojiPickerNotifier.value = false;
setState(() {
selectedEvents.clear();
});
_clearSelectEvent();
}

void reportEventAction() async {
Expand Down Expand Up @@ -694,9 +690,7 @@ class ChatController extends State<Chat>
);
if (result.error != null) return;
showEmojiPickerNotifier.value = false;
setState(() {
selectedEvents.clear();
});
_clearSelectEvent();
TwakeSnackBar.show(context, L10n.of(context)!.contentHasBeenReported);
}

Expand Down Expand Up @@ -734,9 +728,7 @@ class ChatController extends State<Chat>
);
}
showEmojiPickerNotifier.value = false;
setState(() {
selectedEvents.clear();
});
_clearSelectEvent();
}

List<Client?> get currentRoomBundle {
Expand Down Expand Up @@ -780,7 +772,7 @@ class ChatController extends State<Chat>
"forwardEventsAction():: shareContentList: ${Matrix.of(context).shareContentList}",
);
}
setState(() => selectedEvents.clear());
_clearSelectEvent();
context.go(
'/rooms/forward',
extra: ForwardArgument(
Expand All @@ -800,15 +792,17 @@ class ChatController extends State<Chat>
for (final e in allEditEvents) {
e.sendAgain();
}
setState(() => selectedEvents.clear());
_clearSelectEvent();
}

void replyAction({Event? replyTo}) {
setState(() {
replyEvent = replyTo ?? selectedEvents.first;
selectedEvents.clear();
});
inputFocus.requestFocus();
void replyAction({
Event? replyTo,
}) {
_updateReplyEvent(
event: replyTo ?? selectedEvents.first,
);
_clearSelectEvent();
_requestInputFocus();
}

Future<void> scrollToEventIdAndHighlight(String eventId) async {
Expand Down Expand Up @@ -997,7 +991,7 @@ class ChatController extends State<Chat>
);

if (PlatformInfos.isWeb) {
inputFocus.requestFocus();
_requestInputFocus();
}
break;
}
Expand All @@ -1010,8 +1004,8 @@ class ChatController extends State<Chat>
}

void sendEmojiAction(String? emoji) async {
final events = List<Event>.from(selectedEvents);
setState(() => selectedEvents.clear());
final events = selectedEvents;
_clearSelectEvent();
for (final event in events) {
await room!.sendReaction(
event.eventId,
Expand All @@ -1023,9 +1017,7 @@ class ChatController extends State<Chat>
void clearSelectedEvents() {
showEmojiPickerNotifier.value = false;

setState(() {
selectedEvents.clear();
});
_clearSelectEvent();
}

void clearSingleSelectedEvent() {
Expand All @@ -1046,15 +1038,16 @@ class ChatController extends State<Chat>
setState(() {
pendingText = sendController.text;
editEvent = selectedEvents.first;
inputText.value = sendController.text =
editEvent!.getDisplayEvent(timeline!).calcLocalizedBodyFallback(
MatrixLocals(L10n.of(context)!),
withSenderNamePrefix: false,
hideReply: true,
);
selectedEvents.clear();
});
inputFocus.requestFocus();
inputText.value = sendController.text =
editEvent!.getDisplayEvent(timeline!).calcLocalizedBodyFallback(
MatrixLocals(L10n.of(context)!),
withSenderNamePrefix: false,
hideReply: true,
);
_clearSelectEvent();

_requestInputFocus();
}

void goToNewRoomAction() async {
Expand Down Expand Up @@ -1091,13 +1084,9 @@ class ChatController extends State<Chat>
void onSelectMessage(Event event) {
if (!event.redacted) {
if (selectedEvents.contains(event)) {
setState(
() => selectedEvents.remove(event),
);
_removeSelectEvent(event);
} else {
setState(
() => selectedEvents.add(event),
);
_addSelectEvent([event]);
}
selectedEvents.sort(
(a, b) => a.originServerTs.compareTo(b.originServerTs),
Expand Down Expand Up @@ -1275,7 +1264,7 @@ class ChatController extends State<Chat>
inputText.value = sendController.text = pendingText;
pendingText = '';
}
replyEvent = null;
_updateReplyEvent();
editEvent = null;
});

Expand Down Expand Up @@ -1472,7 +1461,7 @@ class ChatController extends State<Chat>

void onKeyboardAction() {
showEmojiPickerNotifier.toggle();
inputFocus.requestFocus();
_requestInputFocus();
}

void onPushDetails() async {
Expand Down Expand Up @@ -1680,6 +1669,42 @@ class ChatController extends State<Chat>
}
}

void _requestInputFocus() {
if (!inputFocus.hasPrimaryFocus) {
inputFocus.requestFocus();
}
}

void _updateReplyEvent({Event? event}) {
try {
replyEventNotifier.value = event;
} on FlutterError catch (e) {
Logs().e(
'Chat::_updateReplyEvent():: FlutterError: $e',
e.stackTrace,
);
}
}

void _addSelectEvent(List<Event> events) {
setState(() {
selectedEvents.addAll(events);
});
}

void _removeSelectEvent(Event events) {
setState(() {
selectedEvents.remove(events);
});
}

void _clearSelectEvent() {
if (selectedEvents.isEmpty) return;
setState(() {
selectedEvents.clear();
});
}

@override
void initState() {
_initializePinnedEvents();
Expand Down Expand Up @@ -1733,6 +1758,7 @@ class ChatController extends State<Chat>
suggestionsController.dispose();
stickyTimestampNotifier.dispose();
openingChatViewStateNotifier.dispose();
replyEventNotifier.dispose();
super.dispose();
}

Expand Down
9 changes: 7 additions & 2 deletions lib/pages/chat/chat_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ class ChatView extends StatelessWidget with MessageContentMixin {
builder: (context, showScrollDownButton, _) {
if (showScrollDownButton &&
controller.selectedEvents.isEmpty &&
controller.replyEvent == null) {
controller.replyEventNotifier.value == null) {
return Padding(
padding: const EdgeInsets.only(bottom: 56.0),
child: FloatingActionButton(
Expand Down Expand Up @@ -224,7 +224,12 @@ class ChatView extends StatelessWidget with MessageContentMixin {
return ChatInvitationBody(controller);
}

return ChatViewBody(controller);
return ValueListenableBuilder(
valueListenable: controller.replyEventNotifier,
builder: (context, _, __) {
return ChatViewBody(controller);
},
);
}

Widget _buildBackButton(BuildContext context) => Padding(
Expand Down
2 changes: 1 addition & 1 deletion lib/pages/chat/events/reply_content.dart
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ class ReplyContent extends StatelessWidget {
);
},
),
replyBody,
Expanded(child: replyBody),
],
),
),
Expand Down
2 changes: 1 addition & 1 deletion lib/pages/chat/reactions_picker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class ReactionsPicker extends StatelessWidget {
Widget build(BuildContext context) {
if (controller.showEmojiPickerNotifier.value) return Container();
final display = controller.editEvent == null &&
controller.replyEvent == null &&
controller.replyEventNotifier.value == null &&
controller.room!.canSendDefaultMessages &&
controller.selectedEvents.isNotEmpty;
return AnimatedContainer(
Expand Down
10 changes: 6 additions & 4 deletions lib/pages/chat/reply_display.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ class ReplyDisplay extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: controller.editEvent != null || controller.replyEvent != null
padding: controller.editEvent != null ||
controller.replyEventNotifier.value != null
? ReplyDisplayStyle.replyDisplayPadding
: EdgeInsets.zero,
child: AnimatedContainer(
duration: TwakeThemes.animationDuration,
curve: TwakeThemes.animationCurve,
height: controller.editEvent != null || controller.replyEvent != null
height: controller.editEvent != null ||
controller.replyEventNotifier.value != null
? ReplyDisplayStyle.replyContainerHeight
: 0,
clipBehavior: Clip.hardEdge,
Expand All @@ -30,9 +32,9 @@ class ReplyDisplay extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: controller.replyEvent != null
child: controller.replyEventNotifier.value != null
? ReplyContent(
controller.replyEvent!,
controller.replyEventNotifier.value!,
timeline: controller.timeline!,
)
: _EditContent(
Expand Down

0 comments on commit 495782e

Please sign in to comment.