import "package:fast_immutable_collections/fast_immutable_collections.dart"; import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:material_ui/material_ui.dart"; import "package:nexus/widgets/sheet_layout.dart"; import "package:nexus/controllers/invites.dart"; import "package:nexus/helpers/extensions/get_localpart.dart"; import "package:nexus/helpers/extensions/join_room.dart"; import "package:nexus/main.dart"; import "package:nexus/widgets/avatar_or_hash.dart"; import "package:nexus/widgets/expandable_image.dart"; import "package:nexus/widgets/linkified_text.dart"; import "package:nexus/models/room_summary.dart"; class const RoomSummarySheet( final RoomSummary summary, { final IList? via, super.key, }) extends StatelessWidget { @override Widget build(BuildContext context) { final name = summary.name ?? summary.canonicalAlias ?? summary.roomId; final isInvite = summary.membership == .invite; final colorScheme = Theme.of(context).colorScheme; return SheetLayout( title: Row( spacing: 12, mainAxisSize: .min, children: [ if (summary.avatarUrl != null) ExpandableImage( summary.avatarUrl == null ? null : .new(mxc: summary.avatarUrl!), downloadFilename: name, child: AvatarOrHash( summary.avatarUrl, "", dimension: 64, fallback: Icon(Icons.numbers), ), ), Expanded( child: Text( summary.name ?? summary.canonicalAlias ?? "Unnamed Room", overflow: .ellipsis, maxLines: 3, ), ), ], ), actions: [ TextButton(onPressed: Navigator.of(context).pop, child: Text("Cancel")), if (isInvite) ...[ TextButton( onPressed: () { final container = ProviderScope.containerOf(context); Navigator.of(context).pop(); container .read(InvitesController.provider.notifier) .decline(summary.roomId) .onError(showError); }, style: TextButton.styleFrom(foregroundColor: colorScheme.error), child: Text("Decline"), ), TextButton( onPressed: () { final container = ProviderScope.containerOf(context); context .joinRoom( .new(roomIdOrAlias: summary.roomId, fromInvite: true), name: name, ) .then((roomId) { if (roomId != null) { container .read(InvitesController.provider.notifier) .remove(summary.roomId); } }); Navigator.of(context).pop(); }, child: Text("Accept"), ), ] else if (via != null) TextButton( onPressed: () { context.joinRoom( .new(roomIdOrAlias: summary.roomId, via: via!), name: name, ); Navigator.of(context).pop(); }, child: Text("Join"), ), ], children: [ Column( children: [ if (summary.invitedBy case final invitedBy?) ListTile( leading: AvatarOrHash( summary.inviterProfile?.avatarUrl, summary.inviterProfile?.displayName ?? invitedBy.localpart, ), title: Text( "${summary.isDirect ? "Direct message from" : "Invited by"} ${summary.inviterProfile?.displayName ?? invitedBy.localpart}", ), subtitle: SelectableText(invitedBy), ), if (summary.inviteReason case final reason?) ListTile( titleAlignment: ListTileTitleAlignment.titleHeight, leading: const Icon(Icons.format_quote), title: const Text("Invite reason"), subtitle: SelectableText(reason), ), // Invite state never includes the member count if (summary.joinedMembers != null || !isInvite) ListTile( title: Text( "${summary.joinedMembers ?? "Unknown number of"} members", ), leading: Icon(Icons.people), ), ListTile( title: Text( summary.canonicalAlias == null ? "Room ID" : "Canonical Alias", ), subtitle: SelectableText( summary.canonicalAlias ?? summary.roomId, ), leading: Icon(Icons.numbers), ), if (summary.topic != null) ListTile( title: Text("Topic"), subtitle: LinkifiedText(summary.topic!), leading: Icon(Icons.info), ), if (summary.encryption != null) ListTile(title: Text("Encrypted"), leading: Icon(Icons.lock)), if (summary.worldReadable == true) ListTile( title: Text("Anyone can read room history"), leading: Icon(Icons.public), ), ], ), ], ); } }