mirror of
https://gitlab.com/famedly/fluffychat.git
synced 2024-12-25 06:52:35 +01:00
refactor: Not nullable room in ChatPage
This commit is contained in:
parent
2f6799470c
commit
2acf49a12b
@ -72,7 +72,7 @@ class AppRoutes {
|
|||||||
),
|
),
|
||||||
VWidget(
|
VWidget(
|
||||||
path: ':roomid',
|
path: ':roomid',
|
||||||
widget: const Chat(),
|
widget: const ChatPage(),
|
||||||
stackedRoutes: [
|
stackedRoutes: [
|
||||||
VWidget(
|
VWidget(
|
||||||
path: 'encryption',
|
path: 'encryption',
|
||||||
@ -100,7 +100,7 @@ class AppRoutes {
|
|||||||
stackedRoutes: [
|
stackedRoutes: [
|
||||||
VWidget(
|
VWidget(
|
||||||
path: ':roomid',
|
path: ':roomid',
|
||||||
widget: const Chat(),
|
widget: const ChatPage(),
|
||||||
buildTransition: _dynamicTransition,
|
buildTransition: _dynamicTransition,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -174,14 +174,14 @@ class AppRoutes {
|
|||||||
VNester(
|
VNester(
|
||||||
path: ':roomid',
|
path: ':roomid',
|
||||||
widgetBuilder: (child) => SideViewLayout(
|
widgetBuilder: (child) => SideViewLayout(
|
||||||
mainView: const Chat(),
|
mainView: const ChatPage(),
|
||||||
sideView: child,
|
sideView: child,
|
||||||
),
|
),
|
||||||
buildTransition: _fadeTransition,
|
buildTransition: _fadeTransition,
|
||||||
nestedRoutes: [
|
nestedRoutes: [
|
||||||
VWidget(
|
VWidget(
|
||||||
path: '',
|
path: '',
|
||||||
widget: const Chat(),
|
widget: const ChatPage(),
|
||||||
buildTransition: _fadeTransition,
|
buildTransition: _fadeTransition,
|
||||||
),
|
),
|
||||||
VWidget(
|
VWidget(
|
||||||
@ -245,7 +245,7 @@ class AppRoutes {
|
|||||||
),
|
),
|
||||||
VWidget(
|
VWidget(
|
||||||
path: ':roomid',
|
path: ':roomid',
|
||||||
widget: const Chat(),
|
widget: const ChatPage(),
|
||||||
buildTransition: _dynamicTransition,
|
buildTransition: _dynamicTransition,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -35,17 +35,48 @@ import 'send_file_dialog.dart';
|
|||||||
import 'send_location_dialog.dart';
|
import 'send_location_dialog.dart';
|
||||||
import 'sticker_picker_dialog.dart';
|
import 'sticker_picker_dialog.dart';
|
||||||
|
|
||||||
class Chat extends StatefulWidget {
|
class ChatPage extends StatelessWidget {
|
||||||
final Widget? sideView;
|
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
|
@override
|
||||||
ChatController createState() => ChatController();
|
ChatController createState() => ChatController();
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChatController extends State<Chat> {
|
class ChatController extends State<ChatPageWithRoom> {
|
||||||
Room? room;
|
Room get room => widget.room;
|
||||||
|
|
||||||
late Client sendingClient;
|
late Client sendingClient;
|
||||||
|
|
||||||
@ -53,7 +84,7 @@ class ChatController extends State<Chat> {
|
|||||||
|
|
||||||
String? readMarkerEventId;
|
String? readMarkerEventId;
|
||||||
|
|
||||||
String? get roomId => context.vRouter.pathParameters['roomid'];
|
String get roomId => widget.room.id;
|
||||||
|
|
||||||
final AutoScrollController scrollController = AutoScrollController();
|
final AutoScrollController scrollController = AutoScrollController();
|
||||||
|
|
||||||
@ -95,7 +126,7 @@ class ChatController extends State<Chat> {
|
|||||||
useRootNavigator: false,
|
useRootNavigator: false,
|
||||||
builder: (c) => SendFileDialog(
|
builder: (c) => SendFileDialog(
|
||||||
files: matrixFiles,
|
files: matrixFiles,
|
||||||
room: room!,
|
room: room,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -134,13 +165,13 @@ class ChatController extends State<Chat> {
|
|||||||
|
|
||||||
bool get lastReadEventVisible =>
|
bool get lastReadEventVisible =>
|
||||||
timeline == null ||
|
timeline == null ||
|
||||||
room!.fullyRead.isEmpty ||
|
room.fullyRead.isEmpty ||
|
||||||
timeline!.events.any((event) => event.eventId == room!.fullyRead);
|
timeline!.events.any((event) => event.eventId == room.fullyRead);
|
||||||
|
|
||||||
void recreateChat() async {
|
void recreateChat() async {
|
||||||
final room = this.room;
|
final room = this.room;
|
||||||
final userId = room?.directChatMatrixID;
|
final userId = room.directChatMatrixID;
|
||||||
if (room == null || userId == null) {
|
if (userId == null) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
'Try to recreate a room with is not a DM room. This should not be possible from the UI!',
|
'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 {
|
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(
|
final success = await showFutureLoadingDialog(
|
||||||
context: context,
|
context: context,
|
||||||
future: room.leave,
|
future: room.leave,
|
||||||
@ -262,12 +287,12 @@ class ChatController extends State<Chat> {
|
|||||||
if (timeline == null) {
|
if (timeline == null) {
|
||||||
await Matrix.of(context).client.roomsLoading;
|
await Matrix.of(context).client.roomsLoading;
|
||||||
await Matrix.of(context).client.accountDataLoading;
|
await Matrix.of(context).client.accountDataLoading;
|
||||||
timeline = await room!.getTimeline(
|
timeline = await room.getTimeline(
|
||||||
onUpdate: updateView,
|
onUpdate: updateView,
|
||||||
eventContextId: eventContextId,
|
eventContextId: eventContextId,
|
||||||
);
|
);
|
||||||
if (timeline!.events.isNotEmpty) {
|
if (timeline!.events.isNotEmpty) {
|
||||||
if (room!.markedUnread) room!.markUnread(false);
|
if (room.markedUnread) room.markUnread(false);
|
||||||
setReadMarker();
|
setReadMarker();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,8 +318,8 @@ class ChatController extends State<Chat> {
|
|||||||
void setReadMarker({String? eventId}) {
|
void setReadMarker({String? eventId}) {
|
||||||
if (_setReadMarkerFuture != null) return;
|
if (_setReadMarkerFuture != null) return;
|
||||||
if (lastReadEventVisible &&
|
if (lastReadEventVisible &&
|
||||||
!room!.hasNewMessages &&
|
!room.hasNewMessages &&
|
||||||
room!.notificationCount == 0) {
|
room.notificationCount == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!Matrix.of(context).webHasFocus) return;
|
if (!Matrix.of(context).webHasFocus) return;
|
||||||
@ -312,7 +337,7 @@ class ChatController extends State<Chat> {
|
|||||||
_setReadMarkerFuture = timeline.setReadMarker(eventId).then((_) {
|
_setReadMarkerFuture = timeline.setReadMarker(eventId).then((_) {
|
||||||
_setReadMarkerFuture = null;
|
_setReadMarkerFuture = null;
|
||||||
});
|
});
|
||||||
room!.client.updateIosBadge();
|
room.client.updateIosBadge();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -331,7 +356,7 @@ class ChatController extends State<Chat> {
|
|||||||
// no need to have the setting typing to false be blocking
|
// no need to have the setting typing to false be blocking
|
||||||
typingCoolDown?.cancel();
|
typingCoolDown?.cancel();
|
||||||
typingCoolDown = null;
|
typingCoolDown = null;
|
||||||
room!.setTyping(false);
|
room.setTyping(false);
|
||||||
currentlyTyping = false;
|
currentlyTyping = false;
|
||||||
}
|
}
|
||||||
// then set the new sending client
|
// then set the new sending client
|
||||||
@ -351,7 +376,7 @@ class ChatController extends State<Chat> {
|
|||||||
|
|
||||||
final commandMatch = RegExp(r'^\/(\w+)').firstMatch(sendController.text);
|
final commandMatch = RegExp(r'^\/(\w+)').firstMatch(sendController.text);
|
||||||
if (commandMatch != null &&
|
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 l10n = L10n.of(context)!;
|
||||||
final dialogResult = await showOkCancelAlertDialog(
|
final dialogResult = await showOkCancelAlertDialog(
|
||||||
context: context,
|
context: context,
|
||||||
@ -366,7 +391,7 @@ class ChatController extends State<Chat> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ignore: unawaited_futures
|
// ignore: unawaited_futures
|
||||||
room!.sendTextEvent(
|
room.sendTextEvent(
|
||||||
sendController.text,
|
sendController.text,
|
||||||
inReplyTo: replyEvent,
|
inReplyTo: replyEvent,
|
||||||
editEventId: editEvent?.eventId,
|
editEventId: editEvent?.eventId,
|
||||||
@ -403,7 +428,7 @@ class ChatController extends State<Chat> {
|
|||||||
).detectFileType,
|
).detectFileType,
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
room: room!,
|
room: room,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -428,7 +453,7 @@ class ChatController extends State<Chat> {
|
|||||||
).detectFileType,
|
).detectFileType,
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
room: room!,
|
room: room,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -449,7 +474,7 @@ class ChatController extends State<Chat> {
|
|||||||
name: file.path,
|
name: file.path,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
room: room!,
|
room: room,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -470,7 +495,7 @@ class ChatController extends State<Chat> {
|
|||||||
name: file.path,
|
name: file.path,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
room: room!,
|
room: room,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -478,7 +503,7 @@ class ChatController extends State<Chat> {
|
|||||||
void sendStickerAction() async {
|
void sendStickerAction() async {
|
||||||
final sticker = await showAdaptiveBottomSheet<ImagePackImageContent>(
|
final sticker = await showAdaptiveBottomSheet<ImagePackImageContent>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (c) => StickerPickerDialog(room: room!),
|
builder: (c) => StickerPickerDialog(room: room),
|
||||||
);
|
);
|
||||||
if (sticker == null) return;
|
if (sticker == null) return;
|
||||||
final eventContent = <String, dynamic>{
|
final eventContent = <String, dynamic>{
|
||||||
@ -487,7 +512,7 @@ class ChatController extends State<Chat> {
|
|||||||
'url': sticker.url.toString(),
|
'url': sticker.url.toString(),
|
||||||
};
|
};
|
||||||
// send the sticker
|
// send the sticker
|
||||||
await room!.sendEvent(
|
await room.sendEvent(
|
||||||
eventContent,
|
eventContent,
|
||||||
type: EventTypes.Sticker,
|
type: EventTypes.Sticker,
|
||||||
);
|
);
|
||||||
@ -521,7 +546,7 @@ class ChatController extends State<Chat> {
|
|||||||
bytes: audioFile.readAsBytesSync(),
|
bytes: audioFile.readAsBytesSync(),
|
||||||
name: audioFile.path,
|
name: audioFile.path,
|
||||||
);
|
);
|
||||||
await room!.sendFileEvent(
|
await room.sendFileEvent(
|
||||||
file,
|
file,
|
||||||
inReplyTo: replyEvent,
|
inReplyTo: replyEvent,
|
||||||
extraContent: {
|
extraContent: {
|
||||||
@ -571,7 +596,7 @@ class ChatController extends State<Chat> {
|
|||||||
await showDialog(
|
await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
useRootNavigator: false,
|
useRootNavigator: false,
|
||||||
builder: (c) => SendLocationDialog(room: room!),
|
builder: (c) => SendLocationDialog(room: room),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -677,7 +702,7 @@ class ChatController extends State<Chat> {
|
|||||||
if (client == null) {
|
if (client == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final room = client.getRoomById(roomId!)!;
|
final room = client.getRoomById(roomId)!;
|
||||||
await Event.fromJson(event.toJson(), room).redactEvent();
|
await Event.fromJson(event.toJson(), room).redactEvent();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -694,7 +719,7 @@ class ChatController extends State<Chat> {
|
|||||||
|
|
||||||
List<Client?> get currentRoomBundle {
|
List<Client?> get currentRoomBundle {
|
||||||
final clients = Matrix.of(context).currentBundle!;
|
final clients = Matrix.of(context).currentBundle!;
|
||||||
clients.removeWhere((c) => c!.getRoomById(roomId!) == null);
|
clients.removeWhere((c) => c!.getRoomById(roomId) == null);
|
||||||
return clients;
|
return clients;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -808,7 +833,7 @@ class ChatController extends State<Chat> {
|
|||||||
void forgetRoom() async {
|
void forgetRoom() async {
|
||||||
final result = await showFutureLoadingDialog(
|
final result = await showFutureLoadingDialog(
|
||||||
context: context,
|
context: context,
|
||||||
future: room!.forget,
|
future: room.forget,
|
||||||
);
|
);
|
||||||
if (result.error != null) return;
|
if (result.error != null) return;
|
||||||
VRouter.of(context).to('/archive');
|
VRouter.of(context).to('/archive');
|
||||||
@ -857,7 +882,7 @@ class ChatController extends State<Chat> {
|
|||||||
final events = List<Event>.from(selectedEvents);
|
final events = List<Event>.from(selectedEvents);
|
||||||
setState(() => selectedEvents.clear());
|
setState(() => selectedEvents.clear());
|
||||||
for (final event in events) {
|
for (final event in events) {
|
||||||
await room!.sendReaction(
|
await room.sendReaction(
|
||||||
event.eventId,
|
event.eventId,
|
||||||
emoji!,
|
emoji!,
|
||||||
);
|
);
|
||||||
@ -904,7 +929,7 @@ class ChatController extends State<Chat> {
|
|||||||
useRootNavigator: false,
|
useRootNavigator: false,
|
||||||
context: context,
|
context: context,
|
||||||
title: L10n.of(context)!.goToTheNewRoom,
|
title: L10n.of(context)!.goToTheNewRoom,
|
||||||
message: room!
|
message: room
|
||||||
.getState(EventTypes.RoomTombstone)!
|
.getState(EventTypes.RoomTombstone)!
|
||||||
.parsedTombstoneContent
|
.parsedTombstoneContent
|
||||||
.body,
|
.body,
|
||||||
@ -915,8 +940,8 @@ class ChatController extends State<Chat> {
|
|||||||
}
|
}
|
||||||
final result = await showFutureLoadingDialog(
|
final result = await showFutureLoadingDialog(
|
||||||
context: context,
|
context: context,
|
||||||
future: () => room!.client.joinRoom(
|
future: () => room.client.joinRoom(
|
||||||
room!
|
room
|
||||||
.getState(EventTypes.RoomTombstone)!
|
.getState(EventTypes.RoomTombstone)!
|
||||||
.parsedTombstoneContent
|
.parsedTombstoneContent
|
||||||
.replacementRoom,
|
.replacementRoom,
|
||||||
@ -924,7 +949,7 @@ class ChatController extends State<Chat> {
|
|||||||
);
|
);
|
||||||
await showFutureLoadingDialog(
|
await showFutureLoadingDialog(
|
||||||
context: context,
|
context: context,
|
||||||
future: room!.leave,
|
future: room.leave,
|
||||||
);
|
);
|
||||||
if (result.error == null) {
|
if (result.error == null) {
|
||||||
VRouter.of(context).toSegments(['rooms', result.result!]);
|
VRouter.of(context).toSegments(['rooms', result.result!]);
|
||||||
@ -1001,18 +1026,16 @@ class ChatController extends State<Chat> {
|
|||||||
cancelLabel: L10n.of(context)!.cancel,
|
cancelLabel: L10n.of(context)!.cancel,
|
||||||
);
|
);
|
||||||
if (response == OkCancelResult.ok) {
|
if (response == OkCancelResult.ok) {
|
||||||
final events = room!.pinnedEventIds
|
final events = room.pinnedEventIds
|
||||||
..removeWhere((oldEvent) => oldEvent == eventId);
|
..removeWhere((oldEvent) => oldEvent == eventId);
|
||||||
showFutureLoadingDialog(
|
showFutureLoadingDialog(
|
||||||
context: context,
|
context: context,
|
||||||
future: () => room!.setPinnedEvents(events),
|
future: () => room.setPinnedEvents(events),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pinEvent() {
|
void pinEvent() {
|
||||||
final room = this.room;
|
|
||||||
if (room == null) return;
|
|
||||||
final pinnedEventIds = room.pinnedEventIds;
|
final pinnedEventIds = room.pinnedEventIds;
|
||||||
final selectedEventIds = selectedEvents.map((e) => e.eventId).toSet();
|
final selectedEventIds = selectedEvents.map((e) => e.eventId).toSet();
|
||||||
final unpin = selectedEventIds.length == 1 &&
|
final unpin = selectedEventIds.length == 1 &&
|
||||||
@ -1057,7 +1080,7 @@ class ChatController extends State<Chat> {
|
|||||||
typingCoolDown = Timer(const Duration(seconds: 2), () {
|
typingCoolDown = Timer(const Duration(seconds: 2), () {
|
||||||
typingCoolDown = null;
|
typingCoolDown = null;
|
||||||
currentlyTyping = false;
|
currentlyTyping = false;
|
||||||
room!.setTyping(false);
|
room.setTyping(false);
|
||||||
});
|
});
|
||||||
typingTimeout ??= Timer(const Duration(seconds: 30), () {
|
typingTimeout ??= Timer(const Duration(seconds: 30), () {
|
||||||
typingTimeout = null;
|
typingTimeout = null;
|
||||||
@ -1065,14 +1088,13 @@ class ChatController extends State<Chat> {
|
|||||||
});
|
});
|
||||||
if (!currentlyTyping) {
|
if (!currentlyTyping) {
|
||||||
currentlyTyping = true;
|
currentlyTyping = true;
|
||||||
room!
|
room.setTyping(true, timeout: const Duration(seconds: 30).inMilliseconds);
|
||||||
.setTyping(true, timeout: const Duration(seconds: 30).inMilliseconds);
|
|
||||||
}
|
}
|
||||||
setState(() => inputText = text);
|
setState(() => inputText = text);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get isArchived =>
|
bool get isArchived =>
|
||||||
{Membership.leave, Membership.ban}.contains(room?.membership);
|
{Membership.leave, Membership.ban}.contains(room.membership);
|
||||||
|
|
||||||
void showEventInfo([Event? event]) =>
|
void showEventInfo([Event? event]) =>
|
||||||
(event ?? selectedEvents.single).showInfoDialog(context);
|
(event ?? selectedEvents.single).showInfoDialog(context);
|
||||||
@ -1120,7 +1142,7 @@ class ChatController extends State<Chat> {
|
|||||||
if (success.result != null) {
|
if (success.result != null) {
|
||||||
final voipPlugin = Matrix.of(context).voipPlugin;
|
final voipPlugin = Matrix.of(context).voipPlugin;
|
||||||
try {
|
try {
|
||||||
await voipPlugin!.voip.inviteToCall(room!.id, callType);
|
await voipPlugin!.voip.inviteToCall(room.id, callType);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text(e.toLocalizedString(context))),
|
SnackBar(content: Text(e.toLocalizedString(context))),
|
||||||
|
@ -16,9 +16,6 @@ class ChatAppBarTitle extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final room = controller.room;
|
final room = controller.room;
|
||||||
if (room == null) {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
if (controller.selectedEvents.isNotEmpty) {
|
if (controller.selectedEvents.isNotEmpty) {
|
||||||
return Text(controller.selectedEvents.length.toString());
|
return Text(controller.selectedEvents.length.toString());
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ class ChatInputRow extends StatelessWidget {
|
|||||||
contentPadding: const EdgeInsets.all(0),
|
contentPadding: const EdgeInsets.all(0),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (controller.room!
|
if (controller.room
|
||||||
.getImagePacks(ImagePackUsage.sticker)
|
.getImagePacks(ImagePackUsage.sticker)
|
||||||
.isNotEmpty)
|
.isNotEmpty)
|
||||||
PopupMenuItem<String>(
|
PopupMenuItem<String>(
|
||||||
@ -227,7 +227,7 @@ class ChatInputRow extends StatelessWidget {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||||||
child: InputBar(
|
child: InputBar(
|
||||||
room: controller.room!,
|
room: controller.room,
|
||||||
minLines: 1,
|
minLines: 1,
|
||||||
maxLines: 8,
|
maxLines: 8,
|
||||||
autofocus: !PlatformInfos.isMobile,
|
autofocus: !PlatformInfos.isMobile,
|
||||||
|
@ -125,37 +125,26 @@ class ChatView extends StatelessWidget {
|
|||||||
} else {
|
} else {
|
||||||
return [
|
return [
|
||||||
if (Matrix.of(context).voipPlugin != null &&
|
if (Matrix.of(context).voipPlugin != null &&
|
||||||
controller.room!.isDirectChat)
|
controller.room.isDirectChat)
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: controller.onPhoneButtonTap,
|
onPressed: controller.onPhoneButtonTap,
|
||||||
icon: const Icon(Icons.call_outlined),
|
icon: const Icon(Icons.call_outlined),
|
||||||
tooltip: L10n.of(context)!.placeCall,
|
tooltip: L10n.of(context)!.placeCall,
|
||||||
),
|
),
|
||||||
EncryptionButton(controller.room!),
|
EncryptionButton(controller.room),
|
||||||
ChatSettingsPopupMenu(controller.room!, !controller.room!.isDirectChat),
|
ChatSettingsPopupMenu(controller.room, !controller.room.isDirectChat),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
controller.room = controller.sendingClient.getRoomById(controller.roomId!);
|
controller.readMarkerEventId ??= controller.room.fullyRead;
|
||||||
controller.readMarkerEventId ??= controller.room!.fullyRead;
|
|
||||||
if (controller.room == null) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(L10n.of(context)!.oopsSomethingWentWrong),
|
|
||||||
),
|
|
||||||
body: Center(
|
|
||||||
child: Text(L10n.of(context)!.youAreNoLongerParticipatingInThisChat),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (controller.room!.membership == Membership.invite) {
|
if (controller.room.membership == Membership.invite) {
|
||||||
showFutureLoadingDialog(
|
showFutureLoadingDialog(
|
||||||
context: context,
|
context: context,
|
||||||
future: () => controller.room!.join(),
|
future: () => controller.room.join(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
final bottomSheetPadding = FluffyThemes.isColumnMode(context) ? 16.0 : 8.0;
|
final bottomSheetPadding = FluffyThemes.isColumnMode(context) ? 16.0 : 8.0;
|
||||||
@ -175,7 +164,7 @@ class ChatView extends StatelessWidget {
|
|||||||
onTapDown: (_) => controller.setReadMarker(),
|
onTapDown: (_) => controller.setReadMarker(),
|
||||||
behavior: HitTestBehavior.opaque,
|
behavior: HitTestBehavior.opaque,
|
||||||
child: StreamBuilder(
|
child: StreamBuilder(
|
||||||
stream: controller.room!.onUpdate.stream
|
stream: controller.room.onUpdate.stream
|
||||||
.rateLimit(const Duration(seconds: 1)),
|
.rateLimit(const Duration(seconds: 1)),
|
||||||
builder: (context, snapshot) => FutureBuilder(
|
builder: (context, snapshot) => FutureBuilder(
|
||||||
future: controller.getTimeline(),
|
future: controller.getTimeline(),
|
||||||
@ -196,7 +185,7 @@ class ChatView extends StatelessWidget {
|
|||||||
color: Theme.of(context).colorScheme.primary,
|
color: Theme.of(context).colorScheme.primary,
|
||||||
)
|
)
|
||||||
: UnreadRoomsBadge(
|
: UnreadRoomsBadge(
|
||||||
filter: (r) => r.id != controller.roomId!,
|
filter: (r) => r.id != controller.roomId,
|
||||||
badgePosition: BadgePosition.topEnd(end: 8, top: 4),
|
badgePosition: BadgePosition.topEnd(end: 8, top: 4),
|
||||||
child: const Center(child: BackButton()),
|
child: const Center(child: BackButton()),
|
||||||
),
|
),
|
||||||
@ -269,8 +258,8 @@ class ChatView extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (controller.room!.canSendDefaultMessages &&
|
if (controller.room.canSendDefaultMessages &&
|
||||||
controller.room!.membership == Membership.join)
|
controller.room.membership == Membership.join)
|
||||||
Container(
|
Container(
|
||||||
margin: EdgeInsets.only(
|
margin: EdgeInsets.only(
|
||||||
bottom: bottomSheetPadding,
|
bottom: bottomSheetPadding,
|
||||||
@ -295,7 +284,7 @@ class ChatView extends StatelessWidget {
|
|||||||
Brightness.light
|
Brightness.light
|
||||||
? Colors.white
|
? Colors.white
|
||||||
: Colors.black,
|
: Colors.black,
|
||||||
child: controller.room?.isAbandonedDMRoom ==
|
child: controller.room.isAbandonedDMRoom ==
|
||||||
true
|
true
|
||||||
? Row(
|
? Row(
|
||||||
mainAxisAlignment:
|
mainAxisAlignment:
|
||||||
@ -359,14 +348,14 @@ class ChatView extends StatelessWidget {
|
|||||||
child: FloatingActionButton.extended(
|
child: FloatingActionButton.extended(
|
||||||
icon: const Icon(Icons.arrow_upward_outlined),
|
icon: const Icon(Icons.arrow_upward_outlined),
|
||||||
onPressed: () => controller
|
onPressed: () => controller
|
||||||
.scrollToEventId(controller.room!.fullyRead),
|
.scrollToEventId(controller.room.fullyRead),
|
||||||
label: Row(
|
label: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(L10n.of(context)!.jumpToLastReadMessage),
|
Text(L10n.of(context)!.jumpToLastReadMessage),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () => controller.setReadMarker(
|
onPressed: () => controller.setReadMarker(
|
||||||
eventId: controller.room!.fullyRead,
|
eventId: controller.room.fullyRead,
|
||||||
),
|
),
|
||||||
icon: const Icon(Icons.close),
|
icon: const Icon(Icons.close),
|
||||||
),
|
),
|
||||||
|
@ -46,14 +46,14 @@ class PinnedEvents extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final pinnedEventIds = controller.room!.pinnedEventIds;
|
final pinnedEventIds = controller.room.pinnedEventIds;
|
||||||
|
|
||||||
if (pinnedEventIds.isEmpty) {
|
if (pinnedEventIds.isEmpty) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
final completers = pinnedEventIds.map<Completer<Event?>>((e) {
|
final completers = pinnedEventIds.map<Completer<Event?>>((e) {
|
||||||
final completer = Completer<Event?>();
|
final completer = Completer<Event?>();
|
||||||
controller.room!
|
controller.room
|
||||||
.getEventById(e)
|
.getEventById(e)
|
||||||
.then((value) => completer.complete(value));
|
.then((value) => completer.complete(value));
|
||||||
return completer;
|
return completer;
|
||||||
@ -86,11 +86,10 @@ class PinnedEvents extends StatelessWidget {
|
|||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
icon: const Icon(Icons.push_pin),
|
icon: const Icon(Icons.push_pin),
|
||||||
tooltip: L10n.of(context)!.unpin,
|
tooltip: L10n.of(context)!.unpin,
|
||||||
onPressed: controller.room
|
onPressed:
|
||||||
?.canSendEvent(EventTypes.RoomPinnedEvents) ??
|
controller.room.canSendEvent(EventTypes.RoomPinnedEvents)
|
||||||
false
|
? () => controller.unpinEvent(event.eventId)
|
||||||
? () => controller.unpinEvent(event.eventId)
|
: null,
|
||||||
: null,
|
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
@ -18,7 +18,7 @@ class ReactionsPicker extends StatelessWidget {
|
|||||||
if (controller.showEmojiPicker) return const SizedBox.shrink();
|
if (controller.showEmojiPicker) return const SizedBox.shrink();
|
||||||
final display = controller.editEvent == null &&
|
final display = controller.editEvent == null &&
|
||||||
controller.replyEvent == null &&
|
controller.replyEvent == null &&
|
||||||
controller.room!.canSendDefaultMessages &&
|
controller.room.canSendDefaultMessages &&
|
||||||
controller.selectedEvents.isNotEmpty;
|
controller.selectedEvents.isNotEmpty;
|
||||||
return AnimatedContainer(
|
return AnimatedContainer(
|
||||||
duration: FluffyThemes.animationDuration,
|
duration: FluffyThemes.animationDuration,
|
||||||
|
@ -12,7 +12,7 @@ class SeenByRow extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final seenByUsers = controller.room!.getSeenByUsers(controller.timeline!);
|
final seenByUsers = controller.room.getSeenByUsers(controller.timeline!);
|
||||||
const maxAvatars = 7;
|
const maxAvatars = 7;
|
||||||
return Container(
|
return Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
|
@ -11,7 +11,7 @@ class TombstoneDisplay extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (controller.room!.getState(EventTypes.RoomTombstone) == null) {
|
if (controller.room.getState(EventTypes.RoomTombstone) == null) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
@ -26,7 +26,7 @@ class TombstoneDisplay extends StatelessWidget {
|
|||||||
child: const Icon(Icons.upgrade_outlined),
|
child: const Icon(Icons.upgrade_outlined),
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
controller.room!
|
controller.room
|
||||||
.getState(EventTypes.RoomTombstone)!
|
.getState(EventTypes.RoomTombstone)!
|
||||||
.parsedTombstoneContent
|
.parsedTombstoneContent
|
||||||
.body,
|
.body,
|
||||||
|
@ -12,7 +12,7 @@ class TypingIndicators extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final typingUsers = controller.room!.typingUsers
|
final typingUsers = controller.room.typingUsers
|
||||||
..removeWhere((u) => u.stateKey == Matrix.of(context).client.userID);
|
..removeWhere((u) => u.stateKey == Matrix.of(context).client.userID);
|
||||||
const topPadding = 20.0;
|
const topPadding = 20.0;
|
||||||
const bottomPadding = 4.0;
|
const bottomPadding = 4.0;
|
||||||
|
Loading…
Reference in New Issue
Block a user