Add better error handling, send messages early and update when delivered
This commit is contained in:
parent
8c7adbc9d3
commit
55ecbc3590
9 changed files with 111 additions and 74 deletions
|
|
@ -9,6 +9,7 @@ import "package:flutter/foundation.dart";
|
|||
import "package:nexus/controllers/account_data_controller.dart";
|
||||
import "package:nexus/controllers/client_state_controller.dart";
|
||||
import "package:nexus/controllers/init_complete_controller.dart";
|
||||
import "package:nexus/controllers/new_events_controller.dart";
|
||||
import "package:nexus/controllers/rooms_controller.dart";
|
||||
import "package:nexus/controllers/space_edges_controller.dart";
|
||||
import "package:nexus/controllers/sync_status_controller.dart";
|
||||
|
|
@ -74,6 +75,13 @@ class ClientController extends AsyncNotifier<int> {
|
|||
case "init_complete":
|
||||
ref.watch(InitCompleteController.provider.notifier).complete();
|
||||
break;
|
||||
case "send_complete":
|
||||
final event = Event.fromJson(decodedMuksEvent["event"]);
|
||||
|
||||
ref
|
||||
.watch(NewEventsController.provider(event.roomId).notifier)
|
||||
.add(IList([event]));
|
||||
break;
|
||||
case "sync_complete":
|
||||
final syncData = SyncData.fromJson(decodedMuksEvent);
|
||||
final roomProvider = RoomsController.provider;
|
||||
|
|
@ -150,8 +158,8 @@ class ClientController extends AsyncNotifier<int> {
|
|||
Future<void> redactEvent(RedactEventRequest report) =>
|
||||
_sendCommand("redact_event", report.toJson());
|
||||
|
||||
Future<void> sendMessage(SendMessageRequest request) =>
|
||||
_sendCommand("send_message", request.toJson());
|
||||
Future<Event> sendMessage(SendMessageRequest request) async =>
|
||||
Event.fromJson(await _sendCommand("send_message", request.toJson()));
|
||||
|
||||
Future<String?> verify(String recoveryKey) async {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ class MessageController extends AsyncNotifier<Message?> {
|
|||
"big": event.localContent?.bigEmoji == true,
|
||||
"eventType": type,
|
||||
"pmp": event.content["com.beeper.per_message_profile"],
|
||||
"error": event.sendError,
|
||||
"editSource":
|
||||
event.localContent?.editSource ??
|
||||
newContent?["body"] ??
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ class RoomChatController extends AsyncNotifier<InMemoryChatController> {
|
|||
final client = ref.watch(ClientController.provider.notifier);
|
||||
var room = ref.read(RoomsController.provider)[roomId];
|
||||
if (room == null) return InMemoryChatController();
|
||||
|
||||
final state = await client.getRoomState(
|
||||
GetRoomStateRequest(roomId: roomId),
|
||||
);
|
||||
|
|
@ -78,7 +77,6 @@ class RoomChatController extends AsyncNotifier<InMemoryChatController> {
|
|||
|
||||
ref.onDispose(
|
||||
ref.listen(NewEventsController.provider(roomId), (_, next) async {
|
||||
final controller = await future;
|
||||
for (final event in next) {
|
||||
if (event.type == "m.room.redaction") {
|
||||
final controller = await future;
|
||||
|
|
@ -116,12 +114,8 @@ class RoomChatController extends AsyncNotifier<InMemoryChatController> {
|
|||
),
|
||||
);
|
||||
}
|
||||
if (message != null &&
|
||||
!controller.messages.any(
|
||||
(oldMessage) => oldMessage.id == message.id,
|
||||
) &&
|
||||
ref.mounted) {
|
||||
await controller.insertMessage(message);
|
||||
if (message != null && ref.mounted) {
|
||||
await insertMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -152,19 +146,11 @@ class RoomChatController extends AsyncNotifier<InMemoryChatController> {
|
|||
: controller.updateMessage(oldMessage, message);
|
||||
}
|
||||
|
||||
Future<void> deleteMessage(Message message, {String? reason}) async {
|
||||
final controller = await future;
|
||||
await controller.removeMessage(message);
|
||||
await ref
|
||||
Future<void> deleteMessage(Message message, {String? reason}) => ref
|
||||
.watch(ClientController.provider.notifier)
|
||||
.redactEvent(
|
||||
RedactEventRequest(
|
||||
eventId: message.id,
|
||||
roomId: roomId,
|
||||
reason: reason,
|
||||
),
|
||||
RedactEventRequest(eventId: message.id, roomId: roomId, reason: reason),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> loadOlder([InMemoryChatController? chatController]) async {
|
||||
final response = await ref
|
||||
|
|
@ -242,7 +228,8 @@ class RoomChatController extends AsyncNotifier<InMemoryChatController> {
|
|||
}
|
||||
|
||||
final client = ref.watch(ClientController.provider.notifier);
|
||||
client.sendMessage(
|
||||
final room = ref.read(RoomsController.provider)[roomId];
|
||||
final event = await client.sendMessage(
|
||||
SendMessageRequest(
|
||||
roomId: roomId,
|
||||
mentions: Mentions(
|
||||
|
|
@ -260,6 +247,15 @@ class RoomChatController extends AsyncNotifier<InMemoryChatController> {
|
|||
: Relation(eventId: relation.id, relationType: relationType),
|
||||
),
|
||||
);
|
||||
final message = room == null
|
||||
? null
|
||||
: await ref.watch(
|
||||
MessageController.provider(
|
||||
MessageConfig(room: room, event: event),
|
||||
).future,
|
||||
);
|
||||
|
||||
if (message != null) insertMessage(message);
|
||||
}
|
||||
|
||||
Future<chat.User> resolveUser(String id) async {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ part "message_config.g.dart";
|
|||
|
||||
@freezed
|
||||
abstract class MessageConfig with _$MessageConfig {
|
||||
const MessageConfig._();
|
||||
const factory MessageConfig({
|
||||
@Default(false) bool alwaysReturn,
|
||||
@Default(false) bool includeEdits,
|
||||
|
|
@ -14,15 +13,6 @@ abstract class MessageConfig with _$MessageConfig {
|
|||
required Event event,
|
||||
}) = _MessageConfig;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
other.runtimeType == runtimeType &&
|
||||
other is MessageConfig &&
|
||||
other.event.eventId == event.eventId;
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, event.eventId);
|
||||
|
||||
factory MessageConfig.fromJson(Map<String, Object?> json) =>
|
||||
_$MessageConfigFromJson(json);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import "package:nexus/widgets/chat_page/room_appbar.dart";
|
|||
import "package:nexus/widgets/chat_page/wrappers/text_message_wrapper.dart";
|
||||
import "package:nexus/widgets/chat_page/reply_widget.dart";
|
||||
import "package:nexus/widgets/form_text_input.dart";
|
||||
// import "package:dynamic_polls/dynamic_polls.dart";
|
||||
import "package:nexus/main.dart";
|
||||
|
||||
class RoomChat extends HookConsumerWidget {
|
||||
final bool isDesktop;
|
||||
|
|
@ -108,11 +108,13 @@ class RoomChat extends HookConsumerWidget {
|
|||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
notifier.deleteMessage(
|
||||
Navigator.of(context).pop();
|
||||
await notifier
|
||||
.deleteMessage(
|
||||
message,
|
||||
reason: deleteReasonController.text,
|
||||
);
|
||||
Navigator.of(context).pop();
|
||||
)
|
||||
.onError(showError);
|
||||
},
|
||||
child: Text("Delete"),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import "package:flutter/material.dart";
|
|||
import "package:flutter_chat_core/flutter_chat_core.dart";
|
||||
import "package:nexus/widgets/chat_page/lazy_loading/message_avatar.dart";
|
||||
import "package:nexus/widgets/chat_page/lazy_loading/message_displayname.dart";
|
||||
import "package:timeago/timeago.dart";
|
||||
|
||||
class MessageWrapper extends StatelessWidget {
|
||||
final Message message;
|
||||
|
|
@ -10,7 +11,10 @@ class MessageWrapper extends StatelessWidget {
|
|||
const MessageWrapper(this.message, this.child, this.groupStatus, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => ClipRRect(
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final error = message.metadata?["error"];
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
child: AnimatedContainer(
|
||||
padding: message.metadata?["flashing"] == true
|
||||
|
|
@ -33,13 +37,37 @@ class MessageWrapper extends StatelessWidget {
|
|||
spacing: 4,
|
||||
children: [
|
||||
if (groupStatus?.isFirst != false)
|
||||
MessageDisplayname(
|
||||
Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: MessageDisplayname(
|
||||
message,
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
style: theme.textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (message.deliveredAt != null &&
|
||||
groupStatus?.isFirst == true)
|
||||
Tooltip(
|
||||
message: message.deliveredAt!.toString(),
|
||||
child: Text(
|
||||
format(message.deliveredAt!),
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
child,
|
||||
if (error != null && error != "not sent")
|
||||
Text(
|
||||
error,
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
color: theme.colorScheme.error,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
@ -48,3 +76,4 @@ class MessageWrapper extends StatelessWidget {
|
|||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,9 @@ class TextMessageWrapper extends StatelessWidget {
|
|||
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: isSentByMe
|
||||
? colorScheme.primaryContainer
|
||||
? (message.id.startsWith("~")
|
||||
? colorScheme.onPrimary
|
||||
: colorScheme.primaryContainer)
|
||||
: colorScheme.surfaceContainer,
|
||||
),
|
||||
child: Column(
|
||||
|
|
|
|||
|
|
@ -1357,6 +1357,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.0+1"
|
||||
timeago:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: timeago
|
||||
sha256: b05159406a97e1cbb2b9ee4faa9fb096fe0e2dfcd8b08fcd2a00553450d3422e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.7.1"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ dependencies:
|
|||
hooks: ^1.0.0
|
||||
code_assets: ^1.0.0
|
||||
ffigen: ^20.1.1
|
||||
timeago: ^3.7.1
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: ^2.4.11
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue