Gomuks SDK Rewrite #2
21 changed files with 236 additions and 121 deletions
wip thing
commit
92eedc92ab
|
|
@ -12,12 +12,15 @@ import "package:nexus/controllers/top_level_spaces_controller.dart";
|
||||||
import "package:nexus/helpers/extensions/gomuks_buffer.dart";
|
import "package:nexus/helpers/extensions/gomuks_buffer.dart";
|
||||||
import "package:nexus/models/client_state.dart";
|
import "package:nexus/models/client_state.dart";
|
||||||
import "package:nexus/models/event.dart";
|
import "package:nexus/models/event.dart";
|
||||||
import "package:nexus/models/get_event_request.dart";
|
import "package:nexus/models/paginate.dart";
|
||||||
import "package:nexus/models/get_related_events_request.dart";
|
import "package:nexus/models/requests/get_event_request.dart";
|
||||||
import "package:nexus/models/login_request.dart";
|
import "package:nexus/models/requests/get_related_events_request.dart";
|
||||||
|
import "package:nexus/models/requests/login_request.dart";
|
||||||
import "package:nexus/models/profile.dart";
|
import "package:nexus/models/profile.dart";
|
||||||
import "package:nexus/models/redact_event_request.dart";
|
import "package:nexus/models/requests/paginate_request.dart";
|
||||||
import "package:nexus/models/report_request.dart";
|
import "package:nexus/models/requests/redact_event_request.dart";
|
||||||
|
import "package:nexus/models/requests/report_request.dart";
|
||||||
|
import "package:nexus/models/requests/send_message_request.dart";
|
||||||
import "package:nexus/models/room.dart";
|
import "package:nexus/models/room.dart";
|
||||||
import "package:nexus/models/sync_data.dart";
|
import "package:nexus/models/sync_data.dart";
|
||||||
import "package:nexus/models/sync_status.dart";
|
import "package:nexus/models/sync_status.dart";
|
||||||
|
|
@ -98,7 +101,10 @@ class ClientController extends AsyncNotifier<int> {
|
||||||
throw Exception("GomuksStart returned error code $errorCode");
|
throw Exception("GomuksStart returned error code $errorCode");
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> sendCommand(String command, Map<String, dynamic> data) async {
|
Future<dynamic> _sendCommand(
|
||||||
|
String command,
|
||||||
|
Map<String, dynamic> data,
|
||||||
|
) async {
|
||||||
final bufferPointer = data.toGomuksBufferPtr();
|
final bufferPointer = data.toGomuksBufferPtr();
|
||||||
final handle = await future;
|
final handle = await future;
|
||||||
final response = await Isolate.run(
|
final response = await Isolate.run(
|
||||||
|
|
@ -115,11 +121,14 @@ class ClientController extends AsyncNotifier<int> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> redactEvent(RedactEventRequest report) =>
|
Future<void> redactEvent(RedactEventRequest report) =>
|
||||||
sendCommand("redact_event", report.toJson());
|
_sendCommand("redact_event", report.toJson());
|
||||||
|
|
||||||
|
Future<void> sendMessage(SendMessageRequest request) =>
|
||||||
|
_sendCommand("send_message", request.toJson());
|
||||||
|
|
||||||
Future<bool> verify(String recoveryKey) async {
|
Future<bool> verify(String recoveryKey) async {
|
||||||
try {
|
try {
|
||||||
await sendCommand("verify", {"recovery_key": recoveryKey});
|
await _sendCommand("verify", {"recovery_key": recoveryKey});
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -128,35 +137,38 @@ class ClientController extends AsyncNotifier<int> {
|
||||||
|
|
||||||
Future<void> leaveRoom(Room room) async {
|
Future<void> leaveRoom(Room room) async {
|
||||||
if (room.metadata == null) return;
|
if (room.metadata == null) return;
|
||||||
await sendCommand("leave_room", {"room_id": room.metadata!.id});
|
await _sendCommand("leave_room", {"room_id": room.metadata!.id});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<IList<Event>?> getRelatedEvents(
|
Future<IList<Event>?> getRelatedEvents(
|
||||||
GetRelatedEventsRequest request,
|
GetRelatedEventsRequest request,
|
||||||
) async {
|
) async {
|
||||||
final response =
|
final response =
|
||||||
(await sendCommand("get_related_events", request.toJson())) as List?;
|
(await _sendCommand("get_related_events", request.toJson())) as List?;
|
||||||
return response?.map((event) => Event.fromJson(event)).toIList();
|
return response?.map((event) => Event.fromJson(event)).toIList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Event?> getEvent(GetEventRequest request) async {
|
Future<Event?> getEvent(GetEventRequest request) async {
|
||||||
final json = await sendCommand("get_event", request.toJson());
|
final json = await _sendCommand("get_event", request.toJson());
|
||||||
|
|
||||||
return json == null ? null : Event.fromJson(json);
|
return json == null ? null : Event.fromJson(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Paginate> paginate(PaginateRequest request) async =>
|
||||||
|
Paginate.fromJson(await _sendCommand("paginate", request.toJson()));
|
||||||
|
|
||||||
Future<Profile?> getProfile(String userId) async {
|
Future<Profile?> getProfile(String userId) async {
|
||||||
final json = await sendCommand("get_profile", {"user_id": userId});
|
final json = await _sendCommand("get_profile", {"user_id": userId});
|
||||||
|
|
||||||
return json == null ? null : Profile.fromJson(json);
|
return json == null ? null : Profile.fromJson(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> reportEvent(ReportRequest report) =>
|
Future<void> reportEvent(ReportRequest report) =>
|
||||||
sendCommand("report_event", report.toJson());
|
_sendCommand("report_event", report.toJson());
|
||||||
|
|
||||||
Future<void> markRead(Room room) async {
|
Future<void> markRead(Room room) async {
|
||||||
if (room.events.isEmpty || room.metadata == null) return;
|
if (room.events.isEmpty || room.metadata == null) return;
|
||||||
await sendCommand("mark_read", {
|
await _sendCommand("mark_read", {
|
||||||
"room_id": room.metadata?.id,
|
"room_id": room.metadata?.id,
|
||||||
"receipt_type": "m.read",
|
"receipt_type": "m.read",
|
||||||
"event_id": room.events.last.eventId,
|
"event_id": room.events.last.eventId,
|
||||||
|
|
@ -165,7 +177,7 @@ class ClientController extends AsyncNotifier<int> {
|
||||||
|
|
||||||
Future<bool> login(LoginRequest login) async {
|
Future<bool> login(LoginRequest login) async {
|
||||||
try {
|
try {
|
||||||
await sendCommand("login", login.toJson());
|
await _sendCommand("login", login.toJson());
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -174,7 +186,7 @@ class ClientController extends AsyncNotifier<int> {
|
||||||
|
|
||||||
Future<String?> discoverHomeserver(Uri homeserver) async {
|
Future<String?> discoverHomeserver(Uri homeserver) async {
|
||||||
try {
|
try {
|
||||||
final response = await sendCommand("discover_homeserver", {
|
final response = await _sendCommand("discover_homeserver", {
|
||||||
"user_id": "@fakeuser:${homeserver.host}",
|
"user_id": "@fakeuser:${homeserver.host}",
|
||||||
});
|
});
|
||||||
return response["m.homeserver"]?["base_url"];
|
return response["m.homeserver"]?["base_url"];
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import "dart:ffi";
|
||||||
|
import "dart:isolate";
|
||||||
import "package:ffi/ffi.dart";
|
import "package:ffi/ffi.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";
|
||||||
|
|
@ -7,13 +9,14 @@ class HeaderController extends AsyncNotifier<Map<String, String>> {
|
||||||
@override
|
@override
|
||||||
Future<Map<String, String>> build() async {
|
Future<Map<String, String>> build() async {
|
||||||
final handle = await ref.watch(ClientController.provider.future);
|
final handle = await ref.watch(ClientController.provider.future);
|
||||||
final info = GomuksGetAccountInfo(handle);
|
final info = await Isolate.run(() => GomuksGetAccountInfo(handle));
|
||||||
final headers = {
|
final headers = {
|
||||||
|
if (info.access_token != nullptr)
|
||||||
"authorization":
|
"authorization":
|
||||||
"Bearer ${info.access_token.cast<Utf8>().toDartString()}",
|
"Bearer ${info.access_token.cast<Utf8>().toDartString()}",
|
||||||
};
|
};
|
||||||
|
|
||||||
GomuksFreeAccountInfo(info);
|
await Isolate.run(() => GomuksFreeAccountInfo(info));
|
||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,11 @@ import "package:nexus/controllers/new_events_controller.dart";
|
||||||
import "package:nexus/controllers/selected_room_controller.dart";
|
import "package:nexus/controllers/selected_room_controller.dart";
|
||||||
import "package:nexus/helpers/extensions/event_to_message.dart";
|
import "package:nexus/helpers/extensions/event_to_message.dart";
|
||||||
import "package:nexus/helpers/extensions/list_to_messages.dart";
|
import "package:nexus/helpers/extensions/list_to_messages.dart";
|
||||||
import "package:nexus/models/redact_event_request.dart";
|
import "package:nexus/models/requests/redact_event_request.dart";
|
||||||
import "package:nexus/models/relation_type.dart";
|
import "package:nexus/models/relation_type.dart";
|
||||||
|
import "package:nexus/models/requests/send_message_request.dart";
|
||||||
|
import "package:nexus/models/room.dart";
|
||||||
|
import "package:nexus/models/sync_data.dart";
|
||||||
|
|
||||||
class RoomChatController extends AsyncNotifier<ChatController> {
|
class RoomChatController extends AsyncNotifier<ChatController> {
|
||||||
final String roomId;
|
final String roomId;
|
||||||
|
|
@ -67,7 +70,11 @@ class RoomChatController extends AsyncNotifier<ChatController> {
|
||||||
);
|
);
|
||||||
|
|
||||||
final messages = await events.toMessages(client);
|
final messages = await events.toMessages(client);
|
||||||
return InMemoryChatController(messages: messages);
|
final controller = InMemoryChatController(messages: messages);
|
||||||
|
|
||||||
|
if (messages.length < 20) await loadOlder(controller);
|
||||||
|
|
||||||
|
return controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> insertMessage(Message message) async {
|
Future<void> insertMessage(Message message) async {
|
||||||
|
|
@ -98,9 +105,12 @@ class RoomChatController extends AsyncNotifier<ChatController> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> loadOlder() async {
|
Future<void> loadOlder([InMemoryChatController? chatController]) async {
|
||||||
// final currentEvents = await future;
|
final controller = chatController ?? await future;
|
||||||
// await ref.watch(EventsController.provider(room).notifier).prev();
|
final client = ref.watch(ClientController.provider.notifier);
|
||||||
|
|
||||||
|
client.
|
||||||
|
// await ref.watchInMemoryChatController? chatController(EventsController.provider(room).notifier).prev();
|
||||||
// final timeline = await ref.watch(EventsController.provider(room).future);
|
// final timeline = await ref.watch(EventsController.provider(room).future);
|
||||||
|
|
||||||
// final controller = await future;
|
// final controller = await future;
|
||||||
|
|
@ -127,25 +137,28 @@ class RoomChatController extends AsyncNotifier<ChatController> {
|
||||||
required RelationType relationType,
|
required RelationType relationType,
|
||||||
Message? relation,
|
Message? relation,
|
||||||
}) async {
|
}) async {
|
||||||
// var taggedMessage = message;
|
var taggedMessage = message;
|
||||||
|
|
||||||
// for (final tag in tags) {
|
for (final tag in tags) {
|
||||||
// final escaped = RegExp.escape(tag.id);
|
final escaped = RegExp.escape(tag.id); // TODO: Fix
|
||||||
// final pattern = RegExp(r"@+(" + escaped + r")(#[^#]*#)?");
|
final pattern = RegExp(r"@+(" + escaped + r")(#[^#]*#)?");
|
||||||
|
|
||||||
// taggedMessage = taggedMessage.replaceAllMapped(
|
taggedMessage = taggedMessage.replaceAllMapped(
|
||||||
// pattern,
|
pattern,
|
||||||
// (match) => match.group(1)!,
|
(match) => match.group(1)!,
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// await room.sendTextEvent(
|
final client = ref.watch(ClientController.provider.notifier);
|
||||||
// taggedMessage,
|
client.sendMessage(
|
||||||
// editEventId: relationType == RelationType.edit ? relation?.id : null,
|
SendMessageRequest(
|
||||||
// inReplyTo: (relationType == RelationType.reply && relation != null)
|
roomId: roomId,
|
||||||
// ? await room.getEventById(relation.id)
|
text: taggedMessage,
|
||||||
// : null,
|
relation: relation == null
|
||||||
// );
|
? null
|
||||||
|
: Relation(eventId: relation.id, relationType: relationType),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<chat.User> resolveUser(String id) async {
|
Future<chat.User> resolveUser(String id) async {
|
||||||
|
|
|
||||||
|
|
@ -45,19 +45,21 @@ class SpacesController extends Notifier<IList<Space>> {
|
||||||
)
|
)
|
||||||
.toISet();
|
.toISet();
|
||||||
|
|
||||||
final dmRooms = rooms.values
|
final otherRooms = rooms.entries
|
||||||
.where((room) => room.metadata?.dmUserId != null)
|
|
||||||
.toIList();
|
|
||||||
|
|
||||||
final homeRooms = rooms.entries
|
|
||||||
.where(
|
.where(
|
||||||
(e) =>
|
(e) =>
|
||||||
e.value.metadata?.dmUserId == null &&
|
|
||||||
!allNestedRoomIds.contains(e.key) &&
|
!allNestedRoomIds.contains(e.key) &&
|
||||||
!topLevelSpaceIds.contains(e.key) &&
|
!topLevelSpaceIds.contains(e.key) &&
|
||||||
!spaceEdges.containsKey(e.key),
|
!spaceEdges.containsKey(e.key),
|
||||||
)
|
)
|
||||||
.map((e) => e.value)
|
.map((e) => e.value);
|
||||||
|
|
||||||
|
final homeRooms = otherRooms
|
||||||
|
.where((room) => room.metadata?.dmUserId == null)
|
||||||
|
.toIList();
|
||||||
|
|
||||||
|
final dmRooms = otherRooms
|
||||||
|
.where((room) => room.metadata?.dmUserId != null)
|
||||||
.toIList();
|
.toIList();
|
||||||
|
|
||||||
final topLevelSpacesList = topLevelSpaceIds
|
final topLevelSpacesList = topLevelSpaceIds
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import "package:flutter_chat_core/flutter_chat_core.dart";
|
import "package:flutter_chat_core/flutter_chat_core.dart";
|
||||||
import "package:nexus/controllers/client_controller.dart";
|
import "package:nexus/controllers/client_controller.dart";
|
||||||
import "package:nexus/models/event.dart";
|
import "package:nexus/models/event.dart";
|
||||||
import "package:nexus/models/get_event_request.dart";
|
import "package:nexus/models/requests/get_event_request.dart";
|
||||||
import "package:nexus/models/get_related_events_request.dart";
|
import "package:nexus/models/requests/get_related_events_request.dart";
|
||||||
|
|
||||||
extension EventToMessage on Event {
|
extension EventToMessage on Event {
|
||||||
Future<Message?> toMessage(
|
Future<Message?> toMessage(
|
||||||
|
|
@ -92,8 +92,8 @@ extension EventToMessage on Event {
|
||||||
// ),
|
// ),
|
||||||
("m.sticker" || "m.room.message") => switch (content["msgtype"]) {
|
("m.sticker" || "m.room.message") => switch (content["msgtype"]) {
|
||||||
("m.sticker" || "m.image") => Message.image(
|
("m.sticker" || "m.image") => Message.image(
|
||||||
metadata: metadata,
|
|
||||||
id: eventId,
|
id: eventId,
|
||||||
|
metadata: metadata,
|
||||||
authorId: authorId,
|
authorId: authorId,
|
||||||
text: event.localContent?.sanitizedHtml,
|
text: event.localContent?.sanitizedHtml,
|
||||||
source: "(await getAttachmentUri()).toString()", // TODO
|
source: "(await getAttachmentUri()).toString()", // TODO
|
||||||
|
|
@ -102,8 +102,8 @@ extension EventToMessage on Event {
|
||||||
blurhash: (content["info"] as Map?)?["xyz.amorgan.blurhash"],
|
blurhash: (content["info"] as Map?)?["xyz.amorgan.blurhash"],
|
||||||
),
|
),
|
||||||
"m.audio" => Message.audio(
|
"m.audio" => Message.audio(
|
||||||
metadata: metadata,
|
|
||||||
id: eventId,
|
id: eventId,
|
||||||
|
metadata: metadata,
|
||||||
authorId: authorId,
|
authorId: authorId,
|
||||||
text: content["body"],
|
text: content["body"],
|
||||||
replyToMessageId: replyId,
|
replyToMessageId: replyId,
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ abstract class ClientState with _$ClientState {
|
||||||
required bool isInitialized,
|
required bool isInitialized,
|
||||||
required bool isLoggedIn,
|
required bool isLoggedIn,
|
||||||
required bool isVerified,
|
required bool isVerified,
|
||||||
required String userId,
|
required String? userId,
|
||||||
}) = _ClientState;
|
}) = _ClientState;
|
||||||
|
|
||||||
factory ClientState.fromJson(Map<String, Object?> json) =>
|
factory ClientState.fromJson(Map<String, Object?> json) =>
|
||||||
|
|
|
||||||
16
lib/models/paginate.dart
Normal file
16
lib/models/paginate.dart
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||||
|
import "package:freezed_annotation/freezed_annotation.dart";
|
||||||
|
import "package:nexus/models/event.dart";
|
||||||
|
part "paginate.freezed.dart";
|
||||||
|
part "paginate.g.dart";
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class Paginate with _$Paginate {
|
||||||
|
const factory Paginate({
|
||||||
|
required IList<Event> events,
|
||||||
|
required bool hasMore,
|
||||||
|
}) = _Paginate;
|
||||||
|
|
||||||
|
factory Paginate.fromJson(Map<String, Object?> json) =>
|
||||||
|
_$PaginateFromJson(json);
|
||||||
|
}
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
import "package:nexus/models/report_request.dart";
|
|
||||||
|
|
||||||
typedef RedactEventRequest = ReportRequest;
|
|
||||||
14
lib/models/requests/paginate_request.dart
Normal file
14
lib/models/requests/paginate_request.dart
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import "package:freezed_annotation/freezed_annotation.dart";
|
||||||
|
part "paginate_request.freezed.dart";
|
||||||
|
part "paginate_request.g.dart";
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class PaginateRequest with _$PaginateRequest {
|
||||||
|
const factory PaginateRequest({
|
||||||
|
required String roomId,
|
||||||
|
@Default(20) int limit,
|
||||||
|
}) = _PaginateRequest;
|
||||||
|
|
||||||
|
factory PaginateRequest.fromJson(Map<String, Object?> json) =>
|
||||||
|
_$PaginateRequestFromJson(json);
|
||||||
|
}
|
||||||
3
lib/models/requests/redact_event_request.dart
Normal file
3
lib/models/requests/redact_event_request.dart
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
import "package:nexus/models/requests/report_request.dart";
|
||||||
|
|
||||||
|
typedef RedactEventRequest = ReportRequest;
|
||||||
55
lib/models/requests/send_message_request.dart
Normal file
55
lib/models/requests/send_message_request.dart
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||||
|
import "package:freezed_annotation/freezed_annotation.dart";
|
||||||
|
import "package:nexus/models/relation_type.dart";
|
||||||
|
part "send_message_request.freezed.dart";
|
||||||
|
part "send_message_request.g.dart";
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class SendMessageRequest with _$SendMessageRequest {
|
||||||
|
const factory SendMessageRequest({
|
||||||
|
required String roomId,
|
||||||
|
required String text,
|
||||||
|
@Default(Mentions()) @JsonKey(name: "m.mentions") Mentions mentions,
|
||||||
|
@JsonKey(name: "m.relates_to") Relation? relation,
|
||||||
|
}) = _SendMessageRequest;
|
||||||
|
|
||||||
|
factory SendMessageRequest.fromJson(Map<String, Object?> json) =>
|
||||||
|
_$SendMessageRequestFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class Mentions with _$Mentions {
|
||||||
|
const factory Mentions({
|
||||||
|
@Default(false) bool room,
|
||||||
|
@Default(IList.empty()) IList<String> userIds,
|
||||||
|
}) = _Mentions;
|
||||||
|
|
||||||
|
factory Mentions.fromJson(Map<String, Object?> json) =>
|
||||||
|
_$MentionsFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class Relation with _$Relation {
|
||||||
|
const Relation._(); // required for custom methods
|
||||||
|
|
||||||
|
const factory Relation({
|
||||||
|
required String eventId,
|
||||||
|
required RelationType relationType,
|
||||||
|
}) = _Relation;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, Object?> toJson() {
|
||||||
|
switch (relationType) {
|
||||||
|
case RelationType.reply:
|
||||||
|
return {
|
||||||
|
"m.in_reply_to": {"event_id": eventId},
|
||||||
|
};
|
||||||
|
|
||||||
|
case RelationType.edit:
|
||||||
|
return {"rel_type": "m.replace", "event_id": eventId};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
factory Relation.fromJson(Map<String, Object?> json) =>
|
||||||
|
_$RelationFromJson(json);
|
||||||
|
}
|
||||||
|
|
@ -5,7 +5,7 @@ import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:nexus/controllers/client_controller.dart";
|
import "package:nexus/controllers/client_controller.dart";
|
||||||
import "package:nexus/helpers/launch_helper.dart";
|
import "package:nexus/helpers/launch_helper.dart";
|
||||||
import "package:nexus/models/homeserver.dart";
|
import "package:nexus/models/homeserver.dart";
|
||||||
import "package:nexus/models/login_request.dart";
|
import "package:nexus/models/requests/login_request.dart";
|
||||||
import "package:nexus/widgets/appbar.dart";
|
import "package:nexus/widgets/appbar.dart";
|
||||||
import "package:nexus/widgets/divider_text.dart";
|
import "package:nexus/widgets/divider_text.dart";
|
||||||
import "package:nexus/widgets/loading.dart";
|
import "package:nexus/widgets/loading.dart";
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import "package:nexus/helpers/extensions/better_when.dart";
|
||||||
import "package:nexus/helpers/extensions/get_headers.dart";
|
import "package:nexus/helpers/extensions/get_headers.dart";
|
||||||
import "package:nexus/helpers/extensions/show_context_menu.dart";
|
import "package:nexus/helpers/extensions/show_context_menu.dart";
|
||||||
import "package:nexus/models/relation_type.dart";
|
import "package:nexus/models/relation_type.dart";
|
||||||
import "package:nexus/models/report_request.dart";
|
import "package:nexus/models/requests/report_request.dart";
|
||||||
import "package:nexus/widgets/chat_page/chat_box.dart";
|
import "package:nexus/widgets/chat_page/chat_box.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/room_appbar.dart";
|
import "package:nexus/widgets/chat_page/room_appbar.dart";
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue