dedupe replies
This commit is contained in:
parent
2a4525a78f
commit
1d03b09775
7 changed files with 86 additions and 41 deletions
|
|
@ -43,9 +43,11 @@ class RoomChatController extends AsyncNotifier<ChatController> {
|
||||||
return controller.updateMessage(message, newMessage);
|
return controller.updateMessage(message, newMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> send(String message) async {
|
Future<void> send(String message, {String? replyTo}) async =>
|
||||||
await room.sendTextEvent(message);
|
await room.sendTextEvent(
|
||||||
}
|
message,
|
||||||
|
inReplyTo: replyTo == null ? null : await room.getEventById(replyTo),
|
||||||
|
);
|
||||||
|
|
||||||
Future<chat.User> resolveUser(String id) async {
|
Future<chat.User> resolveUser(String id) async {
|
||||||
final user = await room.client.getUserProfile(id);
|
final user = await room.client.getUserProfile(id);
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import "package:matrix/matrix.dart";
|
||||||
import "package:nexus/models/full_room.dart";
|
import "package:nexus/models/full_room.dart";
|
||||||
import "package:nexus/widgets/error_dialog.dart";
|
import "package:nexus/widgets/error_dialog.dart";
|
||||||
import "package:nexus/widgets/loading.dart";
|
import "package:nexus/widgets/loading.dart";
|
||||||
|
import "package:html2md/html2md.dart";
|
||||||
|
|
||||||
extension BetterWhen<T> on AsyncValue<T> {
|
extension BetterWhen<T> on AsyncValue<T> {
|
||||||
Widget betterWhen({
|
Widget betterWhen({
|
||||||
|
|
@ -60,11 +61,16 @@ extension ToMessage on Event {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final formatted = convert(
|
||||||
|
formattedText.isEmpty ? body : formattedText,
|
||||||
|
ignore: replyId == null ? null : ["mx-reply"],
|
||||||
|
);
|
||||||
|
|
||||||
final asText = Message.text(
|
final asText = Message.text(
|
||||||
metadata: metadata,
|
metadata: metadata,
|
||||||
id: eventId,
|
id: eventId,
|
||||||
authorId: senderId,
|
authorId: senderId,
|
||||||
text: body,
|
text: formatted,
|
||||||
replyToMessageId: replyId,
|
replyToMessageId: replyId,
|
||||||
deliveredAt: originServerTs,
|
deliveredAt: originServerTs,
|
||||||
);
|
);
|
||||||
|
|
@ -77,6 +83,7 @@ extension ToMessage on Event {
|
||||||
metadata: metadata,
|
metadata: metadata,
|
||||||
id: eventId,
|
id: eventId,
|
||||||
authorId: senderId,
|
authorId: senderId,
|
||||||
|
text: formatted,
|
||||||
source: (await getAttachmentUri()).toString(),
|
source: (await getAttachmentUri()).toString(),
|
||||||
replyToMessageId: replyId,
|
replyToMessageId: replyId,
|
||||||
deliveredAt: originServerTs,
|
deliveredAt: originServerTs,
|
||||||
|
|
@ -85,7 +92,7 @@ extension ToMessage on Event {
|
||||||
metadata: metadata,
|
metadata: metadata,
|
||||||
id: eventId,
|
id: eventId,
|
||||||
authorId: senderId,
|
authorId: senderId,
|
||||||
text: body,
|
text: formatted,
|
||||||
replyToMessageId: replyId,
|
replyToMessageId: replyId,
|
||||||
source: (await getAttachmentUri()).toString(),
|
source: (await getAttachmentUri()).toString(),
|
||||||
deliveredAt: originServerTs,
|
deliveredAt: originServerTs,
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,7 @@ import "package:dynamic_system_colors/dynamic_system_colors.dart";
|
||||||
import "package:window_size/window_size.dart";
|
import "package:window_size/window_size.dart";
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
ScaledWidgetsFlutterBinding.ensureInitialized(
|
ScaledWidgetsFlutterBinding.ensureInitialized(scaleFactor: (size) => 1);
|
||||||
scaleFactor: (size) => size.width > 1080 ? 1.3 : 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
await windowManager.ensureInitialized();
|
await windowManager.ensureInitialized();
|
||||||
await windowManager.waitUntilReadyToShow(
|
await windowManager.waitUntilReadyToShow(
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import "package:flutter/foundation.dart";
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:flutter_chat_core/flutter_chat_core.dart";
|
import "package:flutter_chat_core/flutter_chat_core.dart";
|
||||||
import "package:flutter_chat_ui/flutter_chat_ui.dart";
|
import "package:flutter_chat_ui/flutter_chat_ui.dart";
|
||||||
|
import "package:flutter_hooks/flutter_hooks.dart";
|
||||||
import "package:flutter_link_previewer/flutter_link_previewer.dart";
|
import "package:flutter_link_previewer/flutter_link_previewer.dart";
|
||||||
import "package:flyer_chat_file_message/flyer_chat_file_message.dart";
|
import "package:flyer_chat_file_message/flyer_chat_file_message.dart";
|
||||||
import "package:flyer_chat_image_message/flyer_chat_image_message.dart";
|
import "package:flyer_chat_image_message/flyer_chat_image_message.dart";
|
||||||
|
|
@ -21,8 +22,23 @@ class RoomChat extends HookConsumerWidget {
|
||||||
final bool isDesktop;
|
final bool isDesktop;
|
||||||
const RoomChat({required this.isDesktop, super.key});
|
const RoomChat({required this.isDesktop, super.key});
|
||||||
|
|
||||||
|
void showContextMenu({
|
||||||
|
required BuildContext context,
|
||||||
|
required Offset globalPosition,
|
||||||
|
required VoidCallback onTap,
|
||||||
|
}) => showMenu(
|
||||||
|
context: context,
|
||||||
|
position: RelativeRect.fromRect(
|
||||||
|
Rect.fromPoints(globalPosition, globalPosition),
|
||||||
|
Offset.zero & (context.findRenderObject() as RenderBox).size,
|
||||||
|
),
|
||||||
|
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||||
|
items: [PopupMenuItem(onTap: onTap, child: Text("Reply"))],
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final replyToMessageId = useState<String?>(null);
|
||||||
final urlRegex = RegExp(r"https?://[^\s\]\(\)]+");
|
final urlRegex = RegExp(r"https?://[^\s\]\(\)]+");
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
return ref
|
return ref
|
||||||
|
|
@ -73,6 +89,28 @@ class RoomChat extends HookConsumerWidget {
|
||||||
onPrimary: theme.colorScheme.onPrimaryContainer,
|
onPrimary: theme.colorScheme.onPrimaryContainer,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
onMessageSecondaryTap:
|
||||||
|
(
|
||||||
|
context,
|
||||||
|
message, {
|
||||||
|
required details,
|
||||||
|
required index,
|
||||||
|
}) => showContextMenu(
|
||||||
|
context: context,
|
||||||
|
globalPosition: details.globalPosition,
|
||||||
|
onTap: () => replyToMessageId.value = message.id,
|
||||||
|
),
|
||||||
|
onMessageLongPress:
|
||||||
|
(
|
||||||
|
context,
|
||||||
|
message, {
|
||||||
|
required details,
|
||||||
|
required index,
|
||||||
|
}) => showContextMenu(
|
||||||
|
context: context,
|
||||||
|
globalPosition: details.globalPosition,
|
||||||
|
onTap: () => replyToMessageId.value = message.id,
|
||||||
|
),
|
||||||
builders: Builders(
|
builders: Builders(
|
||||||
composerBuilder: (_) => Composer(
|
composerBuilder: (_) => Composer(
|
||||||
sendIconColor: theme.colorScheme.primary,
|
sendIconColor: theme.colorScheme.primary,
|
||||||
|
|
@ -101,19 +139,8 @@ class RoomChat extends HookConsumerWidget {
|
||||||
index, {
|
index, {
|
||||||
required bool isSentByMe,
|
required bool isSentByMe,
|
||||||
MessageGroupStatus? groupStatus,
|
MessageGroupStatus? groupStatus,
|
||||||
}) => Column(
|
}) => FlyerChatTextMessage(
|
||||||
crossAxisAlignment: isSentByMe
|
topWidget: TopWidget(message, headers: headers),
|
||||||
? CrossAxisAlignment.end
|
|
||||||
: CrossAxisAlignment.start,
|
|
||||||
spacing: 8,
|
|
||||||
children: [
|
|
||||||
SizedBox(height: 8),
|
|
||||||
|
|
||||||
FlyerChatTextMessage(
|
|
||||||
topWidget: TopWidget(
|
|
||||||
message,
|
|
||||||
headers: headers,
|
|
||||||
),
|
|
||||||
message: message.copyWith(
|
message: message.copyWith(
|
||||||
text: message.text.replaceAllMapped(
|
text: message.text.replaceAllMapped(
|
||||||
urlRegex,
|
urlRegex,
|
||||||
|
|
@ -130,8 +157,6 @@ class RoomChat extends HookConsumerWidget {
|
||||||
sentLinksColor: Colors.blue,
|
sentLinksColor: Colors.blue,
|
||||||
receivedLinksColor: Colors.blue,
|
receivedLinksColor: Colors.blue,
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
linkPreviewBuilder: (_, message, isSentByMe) =>
|
linkPreviewBuilder: (_, message, isSentByMe) =>
|
||||||
LinkPreview(
|
LinkPreview(
|
||||||
text:
|
text:
|
||||||
|
|
@ -196,9 +221,12 @@ class RoomChat extends HookConsumerWidget {
|
||||||
index: index,
|
index: index,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onMessageSend: ref
|
onMessageSend: (message) {
|
||||||
|
ref
|
||||||
.watch(controllerProvider.notifier)
|
.watch(controllerProvider.notifier)
|
||||||
.send,
|
.send(message, replyTo: replyToMessageId.value);
|
||||||
|
replyToMessageId.value = null;
|
||||||
|
},
|
||||||
resolveUser: ref
|
resolveUser: ref
|
||||||
.watch(controllerProvider.notifier)
|
.watch(controllerProvider.notifier)
|
||||||
.resolveUser,
|
.resolveUser,
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,7 @@ class TopWidget extends ConsumerWidget {
|
||||||
replyText,
|
replyText,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: Theme.of(context).textTheme.labelMedium,
|
style: Theme.of(context).textTheme.labelMedium,
|
||||||
|
maxLines: 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
10
pubspec.lock
10
pubspec.lock
|
|
@ -491,7 +491,7 @@ packages:
|
||||||
description:
|
description:
|
||||||
path: "packages/flutter_chat_ui"
|
path: "packages/flutter_chat_ui"
|
||||||
ref: HEAD
|
ref: HEAD
|
||||||
resolved-ref: c1ef794e78e56308872ec377c91645a483204a02
|
resolved-ref: f6718923519db812762ff27eb402f70076d8676c
|
||||||
url: "https://github.com/Henry-Hiles/flutter_chat_ui"
|
url: "https://github.com/Henry-Hiles/flutter_chat_ui"
|
||||||
source: git
|
source: git
|
||||||
version: "2.9.1"
|
version: "2.9.1"
|
||||||
|
|
@ -694,6 +694,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.15.6"
|
version: "0.15.6"
|
||||||
|
html2md:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: html2md
|
||||||
|
sha256: "465cf8ffa1b510fe0e97941579bf5b22e2d575f2cecb500a9c0254efe33a8036"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.2"
|
||||||
html_unescape:
|
html_unescape:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ dependencies:
|
||||||
sqflite_common_ffi: ^2.3.6
|
sqflite_common_ffi: ^2.3.6
|
||||||
color_hash: ^1.0.1
|
color_hash: ^1.0.1
|
||||||
scaled_app: ^2.3.0
|
scaled_app: ^2.3.0
|
||||||
|
html2md: ^1.3.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: ^2.4.11
|
build_runner: ^2.4.11
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue