mirror of
https://gitlab.com/famedly/fluffychat.git
synced 2024-12-24 14:32:37 +01:00
refactor: Not nullable room in ChatPage
This commit is contained in:
parent
2f6799470c
commit
2acf49a12b
@ -72,7 +72,7 @@ class AppRoutes {
|
||||
),
|
||||
VWidget(
|
||||
path: ':roomid',
|
||||
widget: const Chat(),
|
||||
widget: const ChatPage(),
|
||||
stackedRoutes: [
|
||||
VWidget(
|
||||
path: 'encryption',
|
||||
@ -100,7 +100,7 @@ class AppRoutes {
|
||||
stackedRoutes: [
|
||||
VWidget(
|
||||
path: ':roomid',
|
||||
widget: const Chat(),
|
||||
widget: const ChatPage(),
|
||||
buildTransition: _dynamicTransition,
|
||||
),
|
||||
],
|
||||
@ -174,14 +174,14 @@ class AppRoutes {
|
||||
VNester(
|
||||
path: ':roomid',
|
||||
widgetBuilder: (child) => SideViewLayout(
|
||||
mainView: const Chat(),
|
||||
mainView: const ChatPage(),
|
||||
sideView: child,
|
||||
),
|
||||
buildTransition: _fadeTransition,
|
||||
nestedRoutes: [
|
||||
VWidget(
|
||||
path: '',
|
||||
widget: const Chat(),
|
||||
widget: const ChatPage(),
|
||||
buildTransition: _fadeTransition,
|
||||
),
|
||||
VWidget(
|
||||
@ -245,7 +245,7 @@ class AppRoutes {
|
||||
),
|
||||
VWidget(
|
||||
path: ':roomid',
|
||||
widget: const Chat(),
|
||||
widget: const ChatPage(),
|
||||
buildTransition: _dynamicTransition,
|
||||
),
|
||||
],
|
||||
|
@ -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))),
|
||||
|
@ -16,9 +16,6 @@ class ChatAppBarTitle extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final room = controller.room;
|
||||
if (room == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
if (controller.selectedEvents.isNotEmpty) {
|
||||
return Text(controller.selectedEvents.length.toString());
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ class ChatInputRow extends StatelessWidget {
|
||||
contentPadding: const EdgeInsets.all(0),
|
||||
),
|
||||
),
|
||||
if (controller.room!
|
||||
if (controller.room
|
||||
.getImagePacks(ImagePackUsage.sticker)
|
||||
.isNotEmpty)
|
||||
PopupMenuItem<String>(
|
||||
@ -227,7 +227,7 @@ class ChatInputRow extends StatelessWidget {
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||||
child: InputBar(
|
||||
room: controller.room!,
|
||||
room: controller.room,
|
||||
minLines: 1,
|
||||
maxLines: 8,
|
||||
autofocus: !PlatformInfos.isMobile,
|
||||
|
@ -125,37 +125,26 @@ class ChatView extends StatelessWidget {
|
||||
} else {
|
||||
return [
|
||||
if (Matrix.of(context).voipPlugin != null &&
|
||||
controller.room!.isDirectChat)
|
||||
controller.room.isDirectChat)
|
||||
IconButton(
|
||||
onPressed: controller.onPhoneButtonTap,
|
||||
icon: const Icon(Icons.call_outlined),
|
||||
tooltip: L10n.of(context)!.placeCall,
|
||||
),
|
||||
EncryptionButton(controller.room!),
|
||||
ChatSettingsPopupMenu(controller.room!, !controller.room!.isDirectChat),
|
||||
EncryptionButton(controller.room),
|
||||
ChatSettingsPopupMenu(controller.room, !controller.room.isDirectChat),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
controller.room = controller.sendingClient.getRoomById(controller.roomId!);
|
||||
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),
|
||||
),
|
||||
);
|
||||
}
|
||||
controller.readMarkerEventId ??= controller.room.fullyRead;
|
||||
|
||||
if (controller.room!.membership == Membership.invite) {
|
||||
if (controller.room.membership == Membership.invite) {
|
||||
showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () => controller.room!.join(),
|
||||
future: () => controller.room.join(),
|
||||
);
|
||||
}
|
||||
final bottomSheetPadding = FluffyThemes.isColumnMode(context) ? 16.0 : 8.0;
|
||||
@ -175,7 +164,7 @@ class ChatView extends StatelessWidget {
|
||||
onTapDown: (_) => controller.setReadMarker(),
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: StreamBuilder(
|
||||
stream: controller.room!.onUpdate.stream
|
||||
stream: controller.room.onUpdate.stream
|
||||
.rateLimit(const Duration(seconds: 1)),
|
||||
builder: (context, snapshot) => FutureBuilder(
|
||||
future: controller.getTimeline(),
|
||||
@ -196,7 +185,7 @@ class ChatView extends StatelessWidget {
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
)
|
||||
: UnreadRoomsBadge(
|
||||
filter: (r) => r.id != controller.roomId!,
|
||||
filter: (r) => r.id != controller.roomId,
|
||||
badgePosition: BadgePosition.topEnd(end: 8, top: 4),
|
||||
child: const Center(child: BackButton()),
|
||||
),
|
||||
@ -269,8 +258,8 @@ class ChatView extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
if (controller.room!.canSendDefaultMessages &&
|
||||
controller.room!.membership == Membership.join)
|
||||
if (controller.room.canSendDefaultMessages &&
|
||||
controller.room.membership == Membership.join)
|
||||
Container(
|
||||
margin: EdgeInsets.only(
|
||||
bottom: bottomSheetPadding,
|
||||
@ -295,7 +284,7 @@ class ChatView extends StatelessWidget {
|
||||
Brightness.light
|
||||
? Colors.white
|
||||
: Colors.black,
|
||||
child: controller.room?.isAbandonedDMRoom ==
|
||||
child: controller.room.isAbandonedDMRoom ==
|
||||
true
|
||||
? Row(
|
||||
mainAxisAlignment:
|
||||
@ -359,14 +348,14 @@ class ChatView extends StatelessWidget {
|
||||
child: FloatingActionButton.extended(
|
||||
icon: const Icon(Icons.arrow_upward_outlined),
|
||||
onPressed: () => controller
|
||||
.scrollToEventId(controller.room!.fullyRead),
|
||||
.scrollToEventId(controller.room.fullyRead),
|
||||
label: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(L10n.of(context)!.jumpToLastReadMessage),
|
||||
IconButton(
|
||||
onPressed: () => controller.setReadMarker(
|
||||
eventId: controller.room!.fullyRead,
|
||||
eventId: controller.room.fullyRead,
|
||||
),
|
||||
icon: const Icon(Icons.close),
|
||||
),
|
||||
|
@ -46,14 +46,14 @@ class PinnedEvents extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final pinnedEventIds = controller.room!.pinnedEventIds;
|
||||
final pinnedEventIds = controller.room.pinnedEventIds;
|
||||
|
||||
if (pinnedEventIds.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final completers = pinnedEventIds.map<Completer<Event?>>((e) {
|
||||
final completer = Completer<Event?>();
|
||||
controller.room!
|
||||
controller.room
|
||||
.getEventById(e)
|
||||
.then((value) => completer.complete(value));
|
||||
return completer;
|
||||
@ -86,11 +86,10 @@ class PinnedEvents extends StatelessWidget {
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
icon: const Icon(Icons.push_pin),
|
||||
tooltip: L10n.of(context)!.unpin,
|
||||
onPressed: controller.room
|
||||
?.canSendEvent(EventTypes.RoomPinnedEvents) ??
|
||||
false
|
||||
? () => controller.unpinEvent(event.eventId)
|
||||
: null,
|
||||
onPressed:
|
||||
controller.room.canSendEvent(EventTypes.RoomPinnedEvents)
|
||||
? () => controller.unpinEvent(event.eventId)
|
||||
: null,
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
|
@ -18,7 +18,7 @@ class ReactionsPicker extends StatelessWidget {
|
||||
if (controller.showEmojiPicker) return const SizedBox.shrink();
|
||||
final display = controller.editEvent == null &&
|
||||
controller.replyEvent == null &&
|
||||
controller.room!.canSendDefaultMessages &&
|
||||
controller.room.canSendDefaultMessages &&
|
||||
controller.selectedEvents.isNotEmpty;
|
||||
return AnimatedContainer(
|
||||
duration: FluffyThemes.animationDuration,
|
||||
|
@ -12,7 +12,7 @@ class SeenByRow extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final seenByUsers = controller.room!.getSeenByUsers(controller.timeline!);
|
||||
final seenByUsers = controller.room.getSeenByUsers(controller.timeline!);
|
||||
const maxAvatars = 7;
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
|
@ -11,7 +11,7 @@ class TombstoneDisplay extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (controller.room!.getState(EventTypes.RoomTombstone) == null) {
|
||||
if (controller.room.getState(EventTypes.RoomTombstone) == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return SizedBox(
|
||||
@ -26,7 +26,7 @@ class TombstoneDisplay extends StatelessWidget {
|
||||
child: const Icon(Icons.upgrade_outlined),
|
||||
),
|
||||
title: Text(
|
||||
controller.room!
|
||||
controller.room
|
||||
.getState(EventTypes.RoomTombstone)!
|
||||
.parsedTombstoneContent
|
||||
.body,
|
||||
|
@ -12,7 +12,7 @@ class TypingIndicators extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final typingUsers = controller.room!.typingUsers
|
||||
final typingUsers = controller.room.typingUsers
|
||||
..removeWhere((u) => u.stateKey == Matrix.of(context).client.userID);
|
||||
const topPadding = 20.0;
|
||||
const bottomPadding = 4.0;
|
||||
|
Loading…
Reference in New Issue
Block a user