invite-related fixups

This commit is contained in:
Henry Hiles 2026-10-15 20:01:24 -04:00
commit ba258c2fcd
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
6 changed files with 66 additions and 32 deletions

View file

@ -124,7 +124,6 @@ class const InviteCard(final RoomSummary invite, {super.key})
[
if (inviterName != null)
"${invite.isDirect ? "Direct message from" : "Invited by"} $inviterName",
?invite.topic,
].join("\n"),
maxLines: 2,
overflow: .ellipsis,

View file

@ -10,14 +10,17 @@ final class const LinkifiedText(
super.key,
}) extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) => Linkify(
text: text,
maxLines: maxLines,
style: style,
options: .new(humanize: false),
onOpen: (link) =>
ref.read(LaunchHelper.provider).launchUrl(.parse(link.url)),
linkStyle: .new(color: Theme.of(context).colorScheme.primary),
overflow: maxLines == null ? null : .ellipsis,
);
Widget build(BuildContext context, WidgetRef ref) =>
MaterialUiCompatibilityBridge(
child: Linkify(
text: text,
maxLines: maxLines,
style: style,
options: .new(humanize: false),
onOpen: (link) =>
ref.read(LaunchHelper.provider).launchUrl(.parse(link.url)),
linkStyle: .new(color: Theme.of(context).colorScheme.primary),
overflow: maxLines == null ? null : .ellipsis,
),
);
}

View file

@ -55,18 +55,21 @@ final class const RoomMenuButton(
builder: (context) => HookBuilder(
builder: (context) {
final userIdController = useTextEditingController();
final reasonController = useTextEditingController();
final text = useValueListenable(userIdController).text.trim();
final valid = RegExp(r"^@[^:\s]+:[^\s]+$").hasMatch(text);
void submit() {
if (!valid) return;
Navigator.of(context).pop();
final reason = reasonController.text.trim();
client
.setMembership(
.new(
userId: text,
roomId: room!.metadata!.id,
action: .invite,
reason: reason.isEmpty ? null : reason,
),
)
.onError(showError);
@ -74,18 +77,32 @@ final class const RoomMenuButton(
return AlertDialog(
title: Text("Invite User"),
content: TextField(
controller: userIdController,
autofocus: true,
keyboardType: .emailAddress,
onSubmitted: (_) => submit(),
decoration: .new(
labelText: "User ID",
hintText: "@user:example.com",
errorText: text.isEmpty || valid
? null
: "Enter a valid user ID",
),
content: Column(
mainAxisSize: .min,
spacing: 12,
children: [
TextField(
controller: userIdController,
autofocus: true,
keyboardType: .emailAddress,
onSubmitted: (_) => submit(),
decoration: .new(
labelText: "User ID",
hintText: "@user:example.com",
errorText: text.isEmpty || valid
? null
: "Enter a valid user ID",
),
),
TextField(
controller: reasonController,
textCapitalization: .sentences,
onSubmitted: (_) => submit(),
decoration: const .new(
labelText: "Invite reason (optional)",
),
),
],
),
actions: [
TextButton(

View file

@ -61,6 +61,13 @@ class const RoomSummaryDialog(
),
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(
@ -70,23 +77,23 @@ class const RoomSummaryDialog(
leading: Icon(Icons.people),
),
ListTile(
title: SelectableText(summary.canonicalAlias ?? summary.roomId),
title: Text(
summary.canonicalAlias == null ? "Room ID" : "Canonical Alias",
),
subtitle: SelectableText(summary.canonicalAlias ?? summary.roomId),
leading: Icon(Icons.numbers),
),
if (summary.topic != null)
ListTile(
titleAlignment: ListTileTitleAlignment.titleHeight,
title: LinkifiedText(
summary.topic!,
style: Theme.of(context).textTheme.bodyLarge,
),
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 the history"),
title: Text("Anyone can read room history"),
leading: Icon(Icons.public),
),
],