refactor: Not nullable room in ChatPage
This commit is contained in:
parent
217b952c45
commit
e690f1e14c
10 changed files with 102 additions and 95 deletions
|
|
@ -35,17 +35,48 @@ import 'send_file_dialog.dart';
|
|||
import 'send_location_dialog.dart';
|
||||
import 'sticker_picker_dialog.dart';
|
||||
|
||||
class Chat extends StatefulWidget {
|
||||
class ChatPage extends StatelessWidget {
|
||||
final Widget? sideView;
|
||||
|
||||
const Chat({Key? key, this.sideView}) : super(key: key);
|
||||
const ChatPage({Key? key, this.sideView}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final roomId = context.vRouter.pathParameters['roomid'];
|
||||
final room =
|
||||
roomId == null ? null : Matrix.of(context).client.getRoomById(roomId);
|
||||
if (room == null) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text(L10n.of(context)!.oopsSomethingWentWrong)),
|
||||
body: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child:
|
||||
Text(L10n.of(context)!.youAreNoLongerParticipatingInThisChat),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return ChatPageWithRoom(sideView: sideView, room: room);
|
||||
}
|
||||
}
|
||||
|
||||
class ChatPageWithRoom extends StatefulWidget {
|
||||
final Widget? sideView;
|
||||
final Room room;
|
||||
|
||||
const ChatPageWithRoom({
|
||||
Key? key,
|
||||
required this.sideView,
|
||||
required this.room,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
ChatController createState() => ChatController();
|
||||
}
|
||||
|
||||
class ChatController extends State<Chat> {
|
||||
Room? room;
|
||||
class ChatController extends State<ChatPageWithRoom> {
|
||||
Room get room => widget.room;
|
||||
|
||||
late Client sendingClient;
|
||||
|
||||
|
|
@ -53,7 +84,7 @@ class ChatController extends State<Chat> {
|
|||
|
||||
String? readMarkerEventId;
|
||||
|
||||
String? get roomId => context.vRouter.pathParameters['roomid'];
|
||||
String get roomId => widget.room.id;
|
||||
|
||||
final AutoScrollController scrollController = AutoScrollController();
|
||||
|
||||
|
|
@ -95,7 +126,7 @@ class ChatController extends State<Chat> {
|
|||
useRootNavigator: false,
|
||||
builder: (c) => SendFileDialog(
|
||||
files: matrixFiles,
|
||||
room: room!,
|
||||
room: room,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -134,13 +165,13 @@ class ChatController extends State<Chat> {
|
|||
|
||||
bool get lastReadEventVisible =>
|
||||
timeline == null ||
|
||||
room!.fullyRead.isEmpty ||
|
||||
timeline!.events.any((event) => event.eventId == room!.fullyRead);
|
||||
room.fullyRead.isEmpty ||
|
||||
timeline!.events.any((event) => event.eventId == room.fullyRead);
|
||||
|
||||
void recreateChat() async {
|
||||
final room = this.room;
|
||||
final userId = room?.directChatMatrixID;
|
||||
if (room == null || userId == null) {
|
||||
final userId = room.directChatMatrixID;
|
||||
if (userId == null) {
|
||||
throw Exception(
|
||||
'Try to recreate a room with is not a DM room. This should not be possible from the UI!',
|
||||
);
|
||||
|
|
@ -162,12 +193,6 @@ class ChatController extends State<Chat> {
|
|||
}
|
||||
|
||||
void leaveChat() async {
|
||||
final room = this.room;
|
||||
if (room == null) {
|
||||
throw Exception(
|
||||
'Leave room button clicked while room is null. This should not be possible from the UI!',
|
||||
);
|
||||
}
|
||||
final success = await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: room.leave,
|
||||
|
|
@ -262,12 +287,12 @@ class ChatController extends State<Chat> {
|
|||
if (timeline == null) {
|
||||
await Matrix.of(context).client.roomsLoading;
|
||||
await Matrix.of(context).client.accountDataLoading;
|
||||
timeline = await room!.getTimeline(
|
||||
timeline = await room.getTimeline(
|
||||
onUpdate: updateView,
|
||||
eventContextId: eventContextId,
|
||||
);
|
||||
if (timeline!.events.isNotEmpty) {
|
||||
if (room!.markedUnread) room!.markUnread(false);
|
||||
if (room.markedUnread) room.markUnread(false);
|
||||
setReadMarker();
|
||||
}
|
||||
|
||||
|
|
@ -293,8 +318,8 @@ class ChatController extends State<Chat> {
|
|||
void setReadMarker({String? eventId}) {
|
||||
if (_setReadMarkerFuture != null) return;
|
||||
if (lastReadEventVisible &&
|
||||
!room!.hasNewMessages &&
|
||||
room!.notificationCount == 0) {
|
||||
!room.hasNewMessages &&
|
||||
room.notificationCount == 0) {
|
||||
return;
|
||||
}
|
||||
if (!Matrix.of(context).webHasFocus) return;
|
||||
|
|
@ -312,7 +337,7 @@ class ChatController extends State<Chat> {
|
|||
_setReadMarkerFuture = timeline.setReadMarker(eventId).then((_) {
|
||||
_setReadMarkerFuture = null;
|
||||
});
|
||||
room!.client.updateIosBadge();
|
||||
room.client.updateIosBadge();
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -331,7 +356,7 @@ class ChatController extends State<Chat> {
|
|||
// no need to have the setting typing to false be blocking
|
||||
typingCoolDown?.cancel();
|
||||
typingCoolDown = null;
|
||||
room!.setTyping(false);
|
||||
room.setTyping(false);
|
||||
currentlyTyping = false;
|
||||
}
|
||||
// then set the new sending client
|
||||
|
|
@ -351,7 +376,7 @@ class ChatController extends State<Chat> {
|
|||
|
||||
final commandMatch = RegExp(r'^\/(\w+)').firstMatch(sendController.text);
|
||||
if (commandMatch != null &&
|
||||
!room!.client.commands.keys.contains(commandMatch[1]!.toLowerCase())) {
|
||||
!room.client.commands.keys.contains(commandMatch[1]!.toLowerCase())) {
|
||||
final l10n = L10n.of(context)!;
|
||||
final dialogResult = await showOkCancelAlertDialog(
|
||||
context: context,
|
||||
|
|
@ -366,7 +391,7 @@ class ChatController extends State<Chat> {
|
|||
}
|
||||
|
||||
// ignore: unawaited_futures
|
||||
room!.sendTextEvent(
|
||||
room.sendTextEvent(
|
||||
sendController.text,
|
||||
inReplyTo: replyEvent,
|
||||
editEventId: editEvent?.eventId,
|
||||
|
|
@ -403,7 +428,7 @@ class ChatController extends State<Chat> {
|
|||
).detectFileType,
|
||||
)
|
||||
.toList(),
|
||||
room: room!,
|
||||
room: room,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -428,7 +453,7 @@ class ChatController extends State<Chat> {
|
|||
).detectFileType,
|
||||
)
|
||||
.toList(),
|
||||
room: room!,
|
||||
room: room,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -449,7 +474,7 @@ class ChatController extends State<Chat> {
|
|||
name: file.path,
|
||||
)
|
||||
],
|
||||
room: room!,
|
||||
room: room,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -470,7 +495,7 @@ class ChatController extends State<Chat> {
|
|||
name: file.path,
|
||||
)
|
||||
],
|
||||
room: room!,
|
||||
room: room,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -478,7 +503,7 @@ class ChatController extends State<Chat> {
|
|||
void sendStickerAction() async {
|
||||
final sticker = await showAdaptiveBottomSheet<ImagePackImageContent>(
|
||||
context: context,
|
||||
builder: (c) => StickerPickerDialog(room: room!),
|
||||
builder: (c) => StickerPickerDialog(room: room),
|
||||
);
|
||||
if (sticker == null) return;
|
||||
final eventContent = <String, dynamic>{
|
||||
|
|
@ -487,7 +512,7 @@ class ChatController extends State<Chat> {
|
|||
'url': sticker.url.toString(),
|
||||
};
|
||||
// send the sticker
|
||||
await room!.sendEvent(
|
||||
await room.sendEvent(
|
||||
eventContent,
|
||||
type: EventTypes.Sticker,
|
||||
);
|
||||
|
|
@ -521,7 +546,7 @@ class ChatController extends State<Chat> {
|
|||
bytes: audioFile.readAsBytesSync(),
|
||||
name: audioFile.path,
|
||||
);
|
||||
await room!.sendFileEvent(
|
||||
await room.sendFileEvent(
|
||||
file,
|
||||
inReplyTo: replyEvent,
|
||||
extraContent: {
|
||||
|
|
@ -571,7 +596,7 @@ class ChatController extends State<Chat> {
|
|||
await showDialog(
|
||||
context: context,
|
||||
useRootNavigator: false,
|
||||
builder: (c) => SendLocationDialog(room: room!),
|
||||
builder: (c) => SendLocationDialog(room: room),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -677,7 +702,7 @@ class ChatController extends State<Chat> {
|
|||
if (client == null) {
|
||||
return;
|
||||
}
|
||||
final room = client.getRoomById(roomId!)!;
|
||||
final room = client.getRoomById(roomId)!;
|
||||
await Event.fromJson(event.toJson(), room).redactEvent();
|
||||
}
|
||||
} else {
|
||||
|
|
@ -694,7 +719,7 @@ class ChatController extends State<Chat> {
|
|||
|
||||
List<Client?> get currentRoomBundle {
|
||||
final clients = Matrix.of(context).currentBundle!;
|
||||
clients.removeWhere((c) => c!.getRoomById(roomId!) == null);
|
||||
clients.removeWhere((c) => c!.getRoomById(roomId) == null);
|
||||
return clients;
|
||||
}
|
||||
|
||||
|
|
@ -808,7 +833,7 @@ class ChatController extends State<Chat> {
|
|||
void forgetRoom() async {
|
||||
final result = await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: room!.forget,
|
||||
future: room.forget,
|
||||
);
|
||||
if (result.error != null) return;
|
||||
VRouter.of(context).to('/archive');
|
||||
|
|
@ -857,7 +882,7 @@ class ChatController extends State<Chat> {
|
|||
final events = List<Event>.from(selectedEvents);
|
||||
setState(() => selectedEvents.clear());
|
||||
for (final event in events) {
|
||||
await room!.sendReaction(
|
||||
await room.sendReaction(
|
||||
event.eventId,
|
||||
emoji!,
|
||||
);
|
||||
|
|
@ -904,7 +929,7 @@ class ChatController extends State<Chat> {
|
|||
useRootNavigator: false,
|
||||
context: context,
|
||||
title: L10n.of(context)!.goToTheNewRoom,
|
||||
message: room!
|
||||
message: room
|
||||
.getState(EventTypes.RoomTombstone)!
|
||||
.parsedTombstoneContent
|
||||
.body,
|
||||
|
|
@ -915,8 +940,8 @@ class ChatController extends State<Chat> {
|
|||
}
|
||||
final result = await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () => room!.client.joinRoom(
|
||||
room!
|
||||
future: () => room.client.joinRoom(
|
||||
room
|
||||
.getState(EventTypes.RoomTombstone)!
|
||||
.parsedTombstoneContent
|
||||
.replacementRoom,
|
||||
|
|
@ -924,7 +949,7 @@ class ChatController extends State<Chat> {
|
|||
);
|
||||
await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: room!.leave,
|
||||
future: room.leave,
|
||||
);
|
||||
if (result.error == null) {
|
||||
VRouter.of(context).toSegments(['rooms', result.result!]);
|
||||
|
|
@ -1001,18 +1026,16 @@ class ChatController extends State<Chat> {
|
|||
cancelLabel: L10n.of(context)!.cancel,
|
||||
);
|
||||
if (response == OkCancelResult.ok) {
|
||||
final events = room!.pinnedEventIds
|
||||
final events = room.pinnedEventIds
|
||||
..removeWhere((oldEvent) => oldEvent == eventId);
|
||||
showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () => room!.setPinnedEvents(events),
|
||||
future: () => room.setPinnedEvents(events),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void pinEvent() {
|
||||
final room = this.room;
|
||||
if (room == null) return;
|
||||
final pinnedEventIds = room.pinnedEventIds;
|
||||
final selectedEventIds = selectedEvents.map((e) => e.eventId).toSet();
|
||||
final unpin = selectedEventIds.length == 1 &&
|
||||
|
|
@ -1057,7 +1080,7 @@ class ChatController extends State<Chat> {
|
|||
typingCoolDown = Timer(const Duration(seconds: 2), () {
|
||||
typingCoolDown = null;
|
||||
currentlyTyping = false;
|
||||
room!.setTyping(false);
|
||||
room.setTyping(false);
|
||||
});
|
||||
typingTimeout ??= Timer(const Duration(seconds: 30), () {
|
||||
typingTimeout = null;
|
||||
|
|
@ -1065,14 +1088,13 @@ class ChatController extends State<Chat> {
|
|||
});
|
||||
if (!currentlyTyping) {
|
||||
currentlyTyping = true;
|
||||
room!
|
||||
.setTyping(true, timeout: const Duration(seconds: 30).inMilliseconds);
|
||||
room.setTyping(true, timeout: const Duration(seconds: 30).inMilliseconds);
|
||||
}
|
||||
setState(() => inputText = text);
|
||||
}
|
||||
|
||||
bool get isArchived =>
|
||||
{Membership.leave, Membership.ban}.contains(room?.membership);
|
||||
{Membership.leave, Membership.ban}.contains(room.membership);
|
||||
|
||||
void showEventInfo([Event? event]) =>
|
||||
(event ?? selectedEvents.single).showInfoDialog(context);
|
||||
|
|
@ -1120,7 +1142,7 @@ class ChatController extends State<Chat> {
|
|||
if (success.result != null) {
|
||||
final voipPlugin = Matrix.of(context).voipPlugin;
|
||||
try {
|
||||
await voipPlugin!.voip.inviteToCall(room!.id, callType);
|
||||
await voipPlugin!.voip.inviteToCall(room.id, callType);
|
||||
} catch (e) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(e.toLocalizedString(context))),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue