don't pass room around, use many watches
This commit is contained in:
parent
e0ba99d9b9
commit
60be7aaf72
15 changed files with 207 additions and 231 deletions
|
|
@ -1,31 +1,31 @@
|
||||||
import "dart:async";
|
import "dart:async";
|
||||||
import "package:collection/collection.dart";
|
import "package:collection/collection.dart";
|
||||||
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||||
|
import "package:flutter_chat_core/flutter_chat_core.dart";
|
||||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
import "package:nexus/controllers/client_state_controller.dart";
|
import "package:nexus/controllers/client_state_controller.dart";
|
||||||
import "package:nexus/controllers/members_controller.dart";
|
import "package:nexus/controllers/members_controller.dart";
|
||||||
import "package:nexus/models/configs/author_config.dart";
|
|
||||||
import "package:nexus/models/membership.dart";
|
import "package:nexus/models/membership.dart";
|
||||||
|
|
||||||
class AuthorController extends AsyncNotifier<Membership> {
|
class AuthorController extends AsyncNotifier<Membership> {
|
||||||
final AuthorConfig config;
|
final Message message;
|
||||||
AuthorController(this.config);
|
AuthorController(this.message);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Membership> build() async {
|
Future<Membership> build() async {
|
||||||
final member = await ref.watch(
|
final member = await ref.watch(
|
||||||
MembersController.provider(config.room).selectAsync(
|
MembersController.provider.selectAsync(
|
||||||
(value) => value.firstWhereOrNull(
|
(value) => value.firstWhereOrNull(
|
||||||
(membership) => membership.userId == config.message.authorId,
|
(membership) => membership.userId == message.authorId,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final pmp = config.message.metadata?["pmp"] == null
|
final pmp = message.metadata?["pmp"] == null
|
||||||
? null
|
? null
|
||||||
: Membership.fromContent(
|
: Membership.fromContent(
|
||||||
IMap(config.message.metadata?["pmp"]),
|
IMap(message.metadata?["pmp"]),
|
||||||
config.message.authorId,
|
message.authorId,
|
||||||
ref.watch(
|
ref.watch(
|
||||||
ClientStateController.provider.select(
|
ClientStateController.provider.select(
|
||||||
(value) => value?.homeserverUrl,
|
(value) => value?.homeserverUrl,
|
||||||
|
|
@ -39,12 +39,13 @@ class AuthorController extends AsyncNotifier<Membership> {
|
||||||
displayName:
|
displayName:
|
||||||
pmp?.displayName ??
|
pmp?.displayName ??
|
||||||
member?.displayName ??
|
member?.displayName ??
|
||||||
config.message.authorId.substring(1).split(":").first,
|
message.authorId.substring(1).split(":").first,
|
||||||
userId: config.message.authorId,
|
userId: message.authorId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static final provider = AsyncNotifierProvider.family<AuthorController, Membership, AuthorConfig>(
|
static final provider =
|
||||||
|
AsyncNotifierProvider.family<AuthorController, Membership, Message>(
|
||||||
AuthorController.new,
|
AuthorController.new,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,28 @@ import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
import "package:nexus/controllers/client_controller.dart";
|
import "package:nexus/controllers/client_controller.dart";
|
||||||
import "package:nexus/controllers/client_state_controller.dart";
|
import "package:nexus/controllers/client_state_controller.dart";
|
||||||
|
import "package:nexus/controllers/selected_room_controller.dart";
|
||||||
import "package:nexus/models/membership.dart";
|
import "package:nexus/models/membership.dart";
|
||||||
import "package:nexus/models/requests/get_room_state_request.dart";
|
import "package:nexus/models/requests/get_room_state_request.dart";
|
||||||
import "package:nexus/models/room.dart";
|
|
||||||
|
|
||||||
class MembersController extends AsyncNotifier<IList<Membership>> {
|
class MembersController extends AsyncNotifier<IList<Membership>> {
|
||||||
final Room room;
|
|
||||||
MembersController(this.room);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<IList<Membership>> build() async {
|
Future<IList<Membership>> build() async {
|
||||||
if (room.metadata == null) return const IList.empty();
|
final data = ref.watch(
|
||||||
|
SelectedRoomController.provider.select(
|
||||||
|
(value) => value?.metadata == null
|
||||||
|
? null
|
||||||
|
: (value!.metadata!.id, value.metadata!.hasMemberList),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (data == null) return const IList.empty();
|
||||||
|
|
||||||
final state = await ref
|
final state = await ref
|
||||||
.watch(ClientController.provider.notifier)
|
.watch(ClientController.provider.notifier)
|
||||||
.getRoomState(
|
.getRoomState(
|
||||||
GetRoomStateRequest(
|
GetRoomStateRequest(
|
||||||
roomId: room.metadata!.id,
|
roomId: data.$1,
|
||||||
fetchMembers: room.metadata!.hasMemberList == false,
|
fetchMembers: data.$2 == false,
|
||||||
includeMembers: true,
|
includeMembers: true,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -42,7 +46,7 @@ class MembersController extends AsyncNotifier<IList<Membership>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
static final provider =
|
static final provider =
|
||||||
AsyncNotifierProvider.family<MembersController, IList<Membership>, Room>(
|
AsyncNotifierProvider<MembersController, IList<Membership>>(
|
||||||
MembersController.new,
|
MembersController.new,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -223,13 +223,13 @@ class RoomChatController extends AsyncNotifier<InMemoryChatController> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> send(
|
Future<void> send(
|
||||||
String message, {
|
String text, {
|
||||||
bool shouldMention = true,
|
bool shouldMention = true,
|
||||||
required Iterable<Tag> tags,
|
required IList<Tag> tags,
|
||||||
required RelationType relationType,
|
required RelationType relationType,
|
||||||
Message? relation,
|
Message? relation,
|
||||||
}) async {
|
}) async {
|
||||||
var taggedMessage = message;
|
var taggedMessage = text;
|
||||||
|
|
||||||
for (final tag in tags) {
|
for (final tag in tags) {
|
||||||
final escaped = RegExp.escape(tag.id);
|
final escaped = RegExp.escape(tag.id);
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
import "package:flutter_chat_core/flutter_chat_core.dart";
|
|
||||||
import "package:freezed_annotation/freezed_annotation.dart";
|
|
||||||
import "package:nexus/models/room.dart";
|
|
||||||
part "author_config.freezed.dart";
|
|
||||||
part "author_config.g.dart";
|
|
||||||
|
|
||||||
@freezed
|
|
||||||
abstract class AuthorConfig with _$AuthorConfig {
|
|
||||||
const factory AuthorConfig({required Message message, required Room room}) =
|
|
||||||
_AuthorConfig;
|
|
||||||
|
|
||||||
factory AuthorConfig.fromJson(Map<String, Object?> json) =>
|
|
||||||
_$AuthorConfigFromJson(json);
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
|
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:flutter/services.dart";
|
import "package:flutter/services.dart";
|
||||||
import "package:flutter_chat_core/flutter_chat_core.dart";
|
import "package:flutter_chat_core/flutter_chat_core.dart";
|
||||||
import "package:flutter_hooks/flutter_hooks.dart";
|
import "package:flutter_hooks/flutter_hooks.dart";
|
||||||
import "package:fluttertagger/fluttertagger.dart";
|
import "package:fluttertagger/fluttertagger.dart";
|
||||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:nexus/controllers/room_chat_controller.dart";
|
|
||||||
import "package:nexus/models/relation_type.dart";
|
import "package:nexus/models/relation_type.dart";
|
||||||
import "package:nexus/models/room.dart";
|
|
||||||
import "package:nexus/widgets/chat_page/composer/mention_overlay.dart";
|
import "package:nexus/widgets/chat_page/composer/mention_overlay.dart";
|
||||||
import "package:nexus/widgets/chat_page/composer/relation_preview.dart";
|
import "package:nexus/widgets/chat_page/composer/relation_preview.dart";
|
||||||
|
|
||||||
|
|
@ -14,12 +13,17 @@ class ChatBox extends HookConsumerWidget {
|
||||||
final Message? relatedMessage;
|
final Message? relatedMessage;
|
||||||
final RelationType relationType;
|
final RelationType relationType;
|
||||||
final VoidCallback onDismiss;
|
final VoidCallback onDismiss;
|
||||||
final Room room;
|
final Future<void> Function(
|
||||||
|
String text, {
|
||||||
|
required bool shouldMention,
|
||||||
|
required IList<Tag> tags,
|
||||||
|
})
|
||||||
|
onSend;
|
||||||
const ChatBox({
|
const ChatBox({
|
||||||
required this.relatedMessage,
|
required this.relatedMessage,
|
||||||
required this.relationType,
|
required this.relationType,
|
||||||
required this.onDismiss,
|
required this.onDismiss,
|
||||||
required this.room,
|
required this.onSend,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -38,16 +42,12 @@ class ChatBox extends HookConsumerWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
void send() {
|
void send() {
|
||||||
if (controller.value.text.trim().isEmpty || room.metadata == null) return;
|
onSend(
|
||||||
ref
|
|
||||||
.watch(RoomChatController.provider(room.metadata!.id).notifier)
|
|
||||||
.send(
|
|
||||||
controller.value.formattedText,
|
controller.value.formattedText,
|
||||||
shouldMention: shouldMention.value,
|
shouldMention: shouldMention.value,
|
||||||
relation: relatedMessage,
|
tags: controller.value.tags.toIList(),
|
||||||
relationType: relationType,
|
|
||||||
tags: controller.value.tags,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
onDismiss();
|
onDismiss();
|
||||||
controller.value.text = "";
|
controller.value.text = "";
|
||||||
}
|
}
|
||||||
|
|
@ -81,7 +81,6 @@ class ChatBox extends HookConsumerWidget {
|
||||||
children: [
|
children: [
|
||||||
RelationPreview(
|
RelationPreview(
|
||||||
relatedMessage,
|
relatedMessage,
|
||||||
room: room,
|
|
||||||
shouldMention: shouldMention.value,
|
shouldMention: shouldMention.value,
|
||||||
toggleShouldMention: () =>
|
toggleShouldMention: () =>
|
||||||
shouldMention.value = !shouldMention.value,
|
shouldMention.value = !shouldMention.value,
|
||||||
|
|
@ -123,7 +122,6 @@ class ChatBox extends HookConsumerWidget {
|
||||||
child: FlutterTagger(
|
child: FlutterTagger(
|
||||||
triggerStrategy: TriggerStrategy.eager,
|
triggerStrategy: TriggerStrategy.eager,
|
||||||
overlay: MentionOverlay(
|
overlay: MentionOverlay(
|
||||||
room,
|
|
||||||
query: query.value,
|
query: query.value,
|
||||||
triggerCharacter: triggerCharacter.value,
|
triggerCharacter: triggerCharacter.value,
|
||||||
addTag: ({required id, required name}) {
|
addTag: ({required id, required name}) {
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,14 @@ import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:nexus/controllers/members_controller.dart";
|
import "package:nexus/controllers/members_controller.dart";
|
||||||
import "package:nexus/controllers/rooms_controller.dart";
|
import "package:nexus/controllers/rooms_controller.dart";
|
||||||
import "package:nexus/helpers/extensions/better_when.dart";
|
import "package:nexus/helpers/extensions/better_when.dart";
|
||||||
import "package:nexus/models/room.dart";
|
|
||||||
import "package:nexus/widgets/avatar_or_hash.dart";
|
import "package:nexus/widgets/avatar_or_hash.dart";
|
||||||
import "package:nexus/widgets/loading.dart";
|
import "package:nexus/widgets/loading.dart";
|
||||||
|
|
||||||
class MentionOverlay extends ConsumerWidget {
|
class MentionOverlay extends ConsumerWidget {
|
||||||
final String? triggerCharacter;
|
final String? triggerCharacter;
|
||||||
final String query;
|
final String query;
|
||||||
final Room room;
|
|
||||||
final void Function({required String id, required String name}) addTag;
|
final void Function({required String id, required String name}) addTag;
|
||||||
const MentionOverlay(
|
const MentionOverlay({
|
||||||
this.room, {
|
|
||||||
required this.query,
|
required this.query,
|
||||||
required this.addTag,
|
required this.addTag,
|
||||||
required this.triggerCharacter,
|
required this.triggerCharacter,
|
||||||
|
|
@ -34,7 +31,7 @@ class MentionOverlay extends ConsumerWidget {
|
||||||
child: switch (triggerCharacter) {
|
child: switch (triggerCharacter) {
|
||||||
"@" =>
|
"@" =>
|
||||||
ref
|
ref
|
||||||
.watch(MembersController.provider(room))
|
.watch(MembersController.provider)
|
||||||
.betterWhen(
|
.betterWhen(
|
||||||
data: (members) => ListView(
|
data: (members) => ListView(
|
||||||
children:
|
children:
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ 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:hooks_riverpod/hooks_riverpod.dart";
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:nexus/models/relation_type.dart";
|
import "package:nexus/models/relation_type.dart";
|
||||||
import "package:nexus/models/room.dart";
|
|
||||||
import "package:nexus/widgets/chat_page/lazy_loading/message_avatar.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:nexus/widgets/chat_page/lazy_loading/message_displayname.dart";
|
||||||
|
|
||||||
|
|
@ -12,11 +11,9 @@ class RelationPreview extends ConsumerWidget {
|
||||||
final VoidCallback onDismiss;
|
final VoidCallback onDismiss;
|
||||||
final bool shouldMention;
|
final bool shouldMention;
|
||||||
final VoidCallback toggleShouldMention;
|
final VoidCallback toggleShouldMention;
|
||||||
final Room room;
|
|
||||||
|
|
||||||
const RelationPreview(
|
const RelationPreview(
|
||||||
this.relatedMessage, {
|
this.relatedMessage, {
|
||||||
required this.room,
|
|
||||||
required this.relationType,
|
required this.relationType,
|
||||||
required this.onDismiss,
|
required this.onDismiss,
|
||||||
required this.shouldMention,
|
required this.shouldMention,
|
||||||
|
|
@ -41,10 +38,9 @@ class RelationPreview extends ConsumerWidget {
|
||||||
"Editing message:",
|
"Editing message:",
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
MessageAvatar(relatedMessage!, room),
|
MessageAvatar(relatedMessage!),
|
||||||
MessageDisplayname(
|
MessageDisplayname(
|
||||||
relatedMessage!,
|
relatedMessage!,
|
||||||
room,
|
|
||||||
style: theme.textTheme.labelMedium?.copyWith(
|
style: theme.textTheme.labelMedium?.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -3,21 +3,16 @@ import "package:flutter_chat_core/flutter_chat_core.dart";
|
||||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
import "package:nexus/controllers/author_controller.dart";
|
import "package:nexus/controllers/author_controller.dart";
|
||||||
import "package:nexus/helpers/extensions/better_when.dart";
|
import "package:nexus/helpers/extensions/better_when.dart";
|
||||||
import "package:nexus/models/configs/author_config.dart";
|
|
||||||
import "package:nexus/models/room.dart";
|
|
||||||
import "package:nexus/widgets/avatar_or_hash.dart";
|
import "package:nexus/widgets/avatar_or_hash.dart";
|
||||||
|
|
||||||
class MessageAvatar extends ConsumerWidget {
|
class MessageAvatar extends ConsumerWidget {
|
||||||
final Message message;
|
final Message message;
|
||||||
final Room room;
|
|
||||||
final double height;
|
final double height;
|
||||||
const MessageAvatar(this.message, this.room, {this.height = 16, super.key});
|
const MessageAvatar(this.message, {this.height = 16, super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) => ref
|
Widget build(BuildContext context, WidgetRef ref) => ref
|
||||||
.watch(
|
.watch(AuthorController.provider(message))
|
||||||
AuthorController.provider(AuthorConfig(room: room, message: message)),
|
|
||||||
)
|
|
||||||
.betterWhen(
|
.betterWhen(
|
||||||
data: (membership) => AvatarOrHash(
|
data: (membership) => AvatarOrHash(
|
||||||
membership.avatarUrl,
|
membership.avatarUrl,
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,15 @@ import "package:flutter_chat_core/flutter_chat_core.dart";
|
||||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
import "package:nexus/controllers/author_controller.dart";
|
import "package:nexus/controllers/author_controller.dart";
|
||||||
import "package:nexus/helpers/extensions/better_when.dart";
|
import "package:nexus/helpers/extensions/better_when.dart";
|
||||||
import "package:nexus/models/configs/author_config.dart";
|
|
||||||
import "package:nexus/models/room.dart";
|
|
||||||
|
|
||||||
class MessageDisplayname extends ConsumerWidget {
|
class MessageDisplayname extends ConsumerWidget {
|
||||||
final Message message;
|
final Message message;
|
||||||
final Room room;
|
|
||||||
final TextStyle? style;
|
final TextStyle? style;
|
||||||
const MessageDisplayname(this.message, this.room, {this.style, super.key});
|
const MessageDisplayname(this.message, {this.style, super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) => ref
|
Widget build(BuildContext context, WidgetRef ref) => ref
|
||||||
.watch(
|
.watch(AuthorController.provider(message))
|
||||||
AuthorController.provider(AuthorConfig(room: room, message: message)),
|
|
||||||
)
|
|
||||||
.betterWhen(
|
.betterWhen(
|
||||||
data: (membership) => Text(
|
data: (membership) => Text(
|
||||||
"${membership.displayName} ${message.metadata?["pmp"] == null ? "" : "(via ${message.authorId})"}",
|
"${membership.displayName} ${message.metadata?["pmp"] == null ? "" : "(via ${message.authorId})"}",
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,14 @@ import "package:flutter/material.dart";
|
||||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:nexus/controllers/members_controller.dart";
|
import "package:nexus/controllers/members_controller.dart";
|
||||||
import "package:nexus/helpers/extensions/better_when.dart";
|
import "package:nexus/helpers/extensions/better_when.dart";
|
||||||
import "package:nexus/models/room.dart";
|
|
||||||
import "package:nexus/widgets/avatar_or_hash.dart";
|
import "package:nexus/widgets/avatar_or_hash.dart";
|
||||||
|
|
||||||
class MemberList extends ConsumerWidget {
|
class MemberList extends ConsumerWidget {
|
||||||
final Room room;
|
const MemberList({super.key});
|
||||||
const MemberList(this.room, {super.key});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final membersProvider = ref.watch(MembersController.provider(room));
|
final membersProvider = ref.watch(MembersController.provider);
|
||||||
return Drawer(
|
return Drawer(
|
||||||
shape: Border(),
|
shape: Border(),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@ import "package:flutter_chat_core/flutter_chat_core.dart";
|
||||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
import "package:nexus/controllers/event_controller.dart";
|
import "package:nexus/controllers/event_controller.dart";
|
||||||
import "package:nexus/controllers/message_controller.dart";
|
import "package:nexus/controllers/message_controller.dart";
|
||||||
|
import "package:nexus/controllers/selected_room_controller.dart";
|
||||||
import "package:nexus/helpers/extensions/better_when.dart";
|
import "package:nexus/helpers/extensions/better_when.dart";
|
||||||
import "package:nexus/models/configs/message_config.dart";
|
import "package:nexus/models/configs/message_config.dart";
|
||||||
import "package:nexus/models/requests/get_event_request.dart";
|
import "package:nexus/models/requests/get_event_request.dart";
|
||||||
import "package:nexus/models/room.dart";
|
|
||||||
import "package:nexus/widgets/chat_page/html/quoted.dart";
|
import "package:nexus/widgets/chat_page/html/quoted.dart";
|
||||||
import "package:nexus/widgets/chat_page/lazy_loading/message_avatar.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:nexus/widgets/chat_page/lazy_loading/message_displayname.dart";
|
||||||
|
|
@ -16,12 +16,10 @@ typedef OnTapReply = void Function(Message message)?;
|
||||||
class ReplyWidget extends ConsumerWidget {
|
class ReplyWidget extends ConsumerWidget {
|
||||||
final Message message;
|
final Message message;
|
||||||
final bool alwaysShow;
|
final bool alwaysShow;
|
||||||
final Room room;
|
|
||||||
final MessageGroupStatus? groupStatus;
|
final MessageGroupStatus? groupStatus;
|
||||||
final OnTapReply onTapReply;
|
final OnTapReply onTapReply;
|
||||||
const ReplyWidget(
|
const ReplyWidget(
|
||||||
this.message, {
|
this.message, {
|
||||||
required this.room,
|
|
||||||
required this.groupStatus,
|
required this.groupStatus,
|
||||||
this.onTapReply,
|
this.onTapReply,
|
||||||
this.alwaysShow = false,
|
this.alwaysShow = false,
|
||||||
|
|
@ -29,8 +27,9 @@ class ReplyWidget extends ConsumerWidget {
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) =>
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
message.replyToMessageId == null
|
final room = ref.watch(SelectedRoomController.provider);
|
||||||
|
return message.replyToMessageId == null || room == null
|
||||||
? SizedBox.shrink()
|
? SizedBox.shrink()
|
||||||
: Padding(
|
: Padding(
|
||||||
padding: EdgeInsets.only(bottom: 12),
|
padding: EdgeInsets.only(bottom: 12),
|
||||||
|
|
@ -67,11 +66,10 @@ class ReplyWidget extends ConsumerWidget {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
spacing: 8,
|
spacing: 8,
|
||||||
children: [
|
children: [
|
||||||
MessageAvatar(replyMessage, room),
|
MessageAvatar(replyMessage),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: MessageDisplayname(
|
child: MessageDisplayname(
|
||||||
replyMessage,
|
replyMessage,
|
||||||
room,
|
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.labelMedium
|
.labelMedium
|
||||||
|
|
@ -99,3 +97,4 @@ class ReplyWidget extends ConsumerWidget {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,17 @@
|
||||||
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:nexus/models/room.dart";
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
|
import "package:nexus/controllers/selected_room_controller.dart";
|
||||||
import "package:nexus/widgets/appbar.dart";
|
import "package:nexus/widgets/appbar.dart";
|
||||||
import "package:nexus/widgets/avatar_or_hash.dart";
|
import "package:nexus/widgets/avatar_or_hash.dart";
|
||||||
import "package:nexus/widgets/chat_page/expandable_image.dart";
|
import "package:nexus/widgets/chat_page/expandable_image.dart";
|
||||||
import "package:nexus/widgets/chat_page/room_menu.dart";
|
import "package:nexus/widgets/chat_page/room_menu.dart";
|
||||||
|
|
||||||
class RoomAppbar extends StatelessWidget implements PreferredSizeWidget {
|
class RoomAppbar extends ConsumerWidget implements PreferredSizeWidget {
|
||||||
final bool isDesktop;
|
final bool isDesktop;
|
||||||
final Room room;
|
|
||||||
final void Function(BuildContext context) onOpenMemberList;
|
final void Function(BuildContext context) onOpenMemberList;
|
||||||
final void Function(BuildContext context) onOpenDrawer;
|
final void Function(BuildContext context) onOpenDrawer;
|
||||||
const RoomAppbar(
|
const RoomAppbar({
|
||||||
this.room, {
|
|
||||||
required this.isDesktop,
|
required this.isDesktop,
|
||||||
required this.onOpenMemberList,
|
required this.onOpenMemberList,
|
||||||
required this.onOpenDrawer,
|
required this.onOpenDrawer,
|
||||||
|
|
@ -23,7 +22,9 @@ class RoomAppbar extends StatelessWidget implements PreferredSizeWidget {
|
||||||
Size get preferredSize => AppBar().preferredSize;
|
Size get preferredSize => AppBar().preferredSize;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Appbar(
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final room = ref.watch(SelectedRoomController.provider)!;
|
||||||
|
return Appbar(
|
||||||
leading: isDesktop
|
leading: isDesktop
|
||||||
? ExpandableImage(
|
? ExpandableImage(
|
||||||
room.metadata?.avatar?.toString(),
|
room.metadata?.avatar?.toString(),
|
||||||
|
|
@ -70,3 +71,4 @@ class RoomAppbar extends StatelessWidget implements PreferredSizeWidget {
|
||||||
].toIList(),
|
].toIList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,16 +35,18 @@ class RoomChat extends HookConsumerWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final client = ref.watch(ClientController.provider.notifier);
|
final client = ref.watch(ClientController.provider.notifier);
|
||||||
final replyToMessage = useState<Message?>(null);
|
final relatedMessage = useState<Message?>(null);
|
||||||
final memberListOpened = useState<bool>(showMembersByDefault);
|
final memberListOpened = useState<bool>(showMembersByDefault);
|
||||||
final relationType = useState(RelationType.reply);
|
final relationType = useState(RelationType.reply);
|
||||||
final room = ref.watch(SelectedRoomController.provider);
|
|
||||||
final userId = ref.watch(ClientStateController.provider)?.userId;
|
final userId = ref.watch(ClientStateController.provider)?.userId;
|
||||||
|
final roomId = ref.watch(
|
||||||
|
SelectedRoomController.provider.select((value) => value?.metadata?.id),
|
||||||
|
);
|
||||||
|
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final danger = theme.colorScheme.error;
|
final danger = theme.colorScheme.error;
|
||||||
|
|
||||||
if (room == null || userId == null || room.metadata?.id == null) {
|
if (roomId == null || userId == null) {
|
||||||
return Center(
|
return Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
"Nothing to see here...",
|
"Nothing to see here...",
|
||||||
|
|
@ -53,7 +55,7 @@ class RoomChat extends HookConsumerWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final controllerProvider = RoomChatController.provider(room.metadata!.id);
|
final controllerProvider = RoomChatController.provider(roomId);
|
||||||
final notifier = ref.watch(controllerProvider.notifier);
|
final notifier = ref.watch(controllerProvider.notifier);
|
||||||
|
|
||||||
List<PopupMenuEntry> getMessageOptions(Message message) {
|
List<PopupMenuEntry> getMessageOptions(Message message) {
|
||||||
|
|
@ -61,7 +63,7 @@ class RoomChat extends HookConsumerWidget {
|
||||||
return [
|
return [
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
replyToMessage.value = message;
|
relatedMessage.value = message;
|
||||||
relationType.value = RelationType.reply;
|
relationType.value = RelationType.reply;
|
||||||
},
|
},
|
||||||
child: ListTile(leading: Icon(Icons.reply), title: Text("Reply")),
|
child: ListTile(leading: Icon(Icons.reply), title: Text("Reply")),
|
||||||
|
|
@ -69,7 +71,7 @@ class RoomChat extends HookConsumerWidget {
|
||||||
if (message is TextMessage && isSentByMe)
|
if (message is TextMessage && isSentByMe)
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
replyToMessage.value = message;
|
relatedMessage.value = message;
|
||||||
relationType.value = RelationType.edit;
|
relationType.value = RelationType.edit;
|
||||||
},
|
},
|
||||||
child: ListTile(leading: Icon(Icons.edit), title: Text("Edit")),
|
child: ListTile(leading: Icon(Icons.edit), title: Text("Edit")),
|
||||||
|
|
@ -153,10 +155,9 @@ class RoomChat extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (room.metadata == null) return;
|
|
||||||
client.reportEvent(
|
client.reportEvent(
|
||||||
ReportRequest(
|
ReportRequest(
|
||||||
roomId: room.metadata!.id,
|
roomId: roomId,
|
||||||
eventId: message.id,
|
eventId: message.id,
|
||||||
reason: reasonController.text.isEmpty
|
reason: reasonController.text.isEmpty
|
||||||
? null
|
? null
|
||||||
|
|
@ -189,7 +190,6 @@ class RoomChat extends HookConsumerWidget {
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: RoomAppbar(
|
appBar: RoomAppbar(
|
||||||
room,
|
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
onOpenDrawer: (_) => Scaffold.of(context).openDrawer(),
|
onOpenDrawer: (_) => Scaffold.of(context).openDrawer(),
|
||||||
onOpenMemberList: (thisContext) {
|
onOpenMemberList: (thisContext) {
|
||||||
|
|
@ -237,18 +237,41 @@ class RoomChat extends HookConsumerWidget {
|
||||||
chatAnimatedListBuilder: (_, itemBuilder) =>
|
chatAnimatedListBuilder: (_, itemBuilder) =>
|
||||||
ChatAnimatedList(
|
ChatAnimatedList(
|
||||||
itemBuilder: itemBuilder,
|
itemBuilder: itemBuilder,
|
||||||
onEndReached: room.hasMore
|
onEndReached:
|
||||||
|
ref.watch(
|
||||||
|
SelectedRoomController.provider.select(
|
||||||
|
(room) => room?.hasMore == true,
|
||||||
|
),
|
||||||
|
)
|
||||||
? notifier.loadOlder
|
? notifier.loadOlder
|
||||||
: null,
|
: null,
|
||||||
onStartReached: () => client.markRead(room),
|
onStartReached: () async {
|
||||||
|
final room = ref.watch(
|
||||||
|
SelectedRoomController.provider,
|
||||||
|
);
|
||||||
|
return room == null
|
||||||
|
? null
|
||||||
|
: await client.markRead(room);
|
||||||
|
},
|
||||||
bottomPadding: 72,
|
bottomPadding: 72,
|
||||||
),
|
),
|
||||||
|
|
||||||
composerBuilder: (_) => ChatBox(
|
composerBuilder: (_) => ChatBox(
|
||||||
|
onSend:
|
||||||
|
(
|
||||||
|
text, {
|
||||||
|
required shouldMention,
|
||||||
|
required tags,
|
||||||
|
}) => notifier.send(
|
||||||
|
text,
|
||||||
|
tags: tags,
|
||||||
relationType: relationType.value,
|
relationType: relationType.value,
|
||||||
relatedMessage: replyToMessage.value,
|
shouldMention: shouldMention,
|
||||||
onDismiss: () => replyToMessage.value = null,
|
relation: relatedMessage.value,
|
||||||
room: room,
|
),
|
||||||
|
relationType: relationType.value,
|
||||||
|
relatedMessage: relatedMessage.value,
|
||||||
|
onDismiss: () => relatedMessage.value = null,
|
||||||
),
|
),
|
||||||
|
|
||||||
textMessageBuilder:
|
textMessageBuilder:
|
||||||
|
|
@ -259,7 +282,6 @@ class RoomChat extends HookConsumerWidget {
|
||||||
required bool isSentByMe,
|
required bool isSentByMe,
|
||||||
MessageGroupStatus? groupStatus,
|
MessageGroupStatus? groupStatus,
|
||||||
}) => TextMessageWrapper(
|
}) => TextMessageWrapper(
|
||||||
room: room,
|
|
||||||
message,
|
message,
|
||||||
content: message.text,
|
content: message.text,
|
||||||
groupStatus: groupStatus,
|
groupStatus: groupStatus,
|
||||||
|
|
@ -277,7 +299,6 @@ class RoomChat extends HookConsumerWidget {
|
||||||
MessageGroupStatus? groupStatus,
|
MessageGroupStatus? groupStatus,
|
||||||
}) => TextMessageWrapper(
|
}) => TextMessageWrapper(
|
||||||
message,
|
message,
|
||||||
room: room,
|
|
||||||
content: message.text,
|
content: message.text,
|
||||||
groupStatus: groupStatus,
|
groupStatus: groupStatus,
|
||||||
onTapReply: notifier.scrollToMessage,
|
onTapReply: notifier.scrollToMessage,
|
||||||
|
|
@ -309,7 +330,6 @@ class RoomChat extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
child: FlyerChatFileMessage(
|
child: FlyerChatFileMessage(
|
||||||
topWidget: ReplyWidget(
|
topWidget: ReplyWidget(
|
||||||
room: room,
|
|
||||||
message,
|
message,
|
||||||
onTapReply: notifier.scrollToMessage,
|
onTapReply: notifier.scrollToMessage,
|
||||||
groupStatus: groupStatus,
|
groupStatus: groupStatus,
|
||||||
|
|
@ -319,7 +339,6 @@ class RoomChat extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
groupStatus,
|
groupStatus,
|
||||||
room,
|
|
||||||
),
|
),
|
||||||
|
|
||||||
systemMessageBuilder:
|
systemMessageBuilder:
|
||||||
|
|
@ -358,11 +377,11 @@ class RoomChat extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
|
|
||||||
if (memberListOpened.value == true && showMembersByDefault)
|
if (memberListOpened.value == true && showMembersByDefault)
|
||||||
MemberList(room),
|
MemberList(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
endDrawer: showMembersByDefault ? null : MemberList(room),
|
endDrawer: showMembersByDefault ? null : MemberList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,13 @@
|
||||||
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:nexus/models/room.dart";
|
|
||||||
import "package:nexus/widgets/chat_page/lazy_loading/message_avatar.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:nexus/widgets/chat_page/lazy_loading/message_displayname.dart";
|
||||||
|
|
||||||
class MessageWrapper extends StatelessWidget {
|
class MessageWrapper extends StatelessWidget {
|
||||||
final Message message;
|
final Message message;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
final Room room;
|
|
||||||
final MessageGroupStatus? groupStatus;
|
final MessageGroupStatus? groupStatus;
|
||||||
const MessageWrapper(
|
const MessageWrapper(this.message, this.child, this.groupStatus, {super.key});
|
||||||
this.message,
|
|
||||||
this.child,
|
|
||||||
this.groupStatus,
|
|
||||||
this.room, {
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => ClipRRect(
|
Widget build(BuildContext context) => ClipRRect(
|
||||||
|
|
@ -33,7 +25,7 @@ class MessageWrapper extends StatelessWidget {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
groupStatus?.isFirst != false
|
groupStatus?.isFirst != false
|
||||||
? MessageAvatar(message, room, height: 40)
|
? MessageAvatar(message, height: 40)
|
||||||
: SizedBox(width: 40),
|
: SizedBox(width: 40),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|
@ -43,7 +35,6 @@ class MessageWrapper extends StatelessWidget {
|
||||||
if (groupStatus?.isFirst != false)
|
if (groupStatus?.isFirst != false)
|
||||||
MessageDisplayname(
|
MessageDisplayname(
|
||||||
message,
|
message,
|
||||||
room,
|
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
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_link_previewer/flutter_link_previewer.dart";
|
import "package:flutter_link_previewer/flutter_link_previewer.dart";
|
||||||
import "package:nexus/models/room.dart";
|
|
||||||
import "package:nexus/widgets/chat_page/html/html.dart";
|
import "package:nexus/widgets/chat_page/html/html.dart";
|
||||||
import "package:nexus/widgets/chat_page/wrappers/message_wrapper.dart";
|
import "package:nexus/widgets/chat_page/wrappers/message_wrapper.dart";
|
||||||
import "package:nexus/widgets/chat_page/reply_widget.dart";
|
import "package:nexus/widgets/chat_page/reply_widget.dart";
|
||||||
|
|
@ -9,7 +8,6 @@ import "package:nexus/widgets/chat_page/reply_widget.dart";
|
||||||
class TextMessageWrapper extends StatelessWidget {
|
class TextMessageWrapper extends StatelessWidget {
|
||||||
final Message message;
|
final Message message;
|
||||||
final String? content;
|
final String? content;
|
||||||
final Room room;
|
|
||||||
final MessageGroupStatus? groupStatus;
|
final MessageGroupStatus? groupStatus;
|
||||||
final Future<void> Function(Message oldMessage, Message newMessage)
|
final Future<void> Function(Message oldMessage, Message newMessage)
|
||||||
updateMessage;
|
updateMessage;
|
||||||
|
|
@ -21,7 +19,6 @@ class TextMessageWrapper extends StatelessWidget {
|
||||||
this.message, {
|
this.message, {
|
||||||
this.content,
|
this.content,
|
||||||
this.onTapReply,
|
this.onTapReply,
|
||||||
required this.room,
|
|
||||||
required this.updateMessage,
|
required this.updateMessage,
|
||||||
required this.groupStatus,
|
required this.groupStatus,
|
||||||
required this.isSentByMe,
|
required this.isSentByMe,
|
||||||
|
|
@ -51,7 +48,6 @@ class TextMessageWrapper extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
ReplyWidget(
|
ReplyWidget(
|
||||||
message,
|
message,
|
||||||
room: room,
|
|
||||||
groupStatus: groupStatus,
|
groupStatus: groupStatus,
|
||||||
onTapReply: onTapReply,
|
onTapReply: onTapReply,
|
||||||
),
|
),
|
||||||
|
|
@ -109,7 +105,6 @@ class TextMessageWrapper extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
groupStatus,
|
groupStatus,
|
||||||
room,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue