parent
9e024fb6f2
commit
281bab0202
9 changed files with 230 additions and 204 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -42,3 +42,5 @@ password.txt
|
||||||
|
|
||||||
# Nix
|
# Nix
|
||||||
/result
|
/result
|
||||||
|
# Widget Preview related
|
||||||
|
.widget_preview/
|
||||||
|
|
|
||||||
36
lib/helpers/extensions/focus_room.dart
Normal file
36
lib/helpers/extensions/focus_room.dart
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import "package:collection/collection.dart";
|
||||||
|
import "package:flutter_riverpod/experimental/mutation.dart";
|
||||||
|
import "package:nexus/controllers/key.dart";
|
||||||
|
import "package:nexus/controllers/spaces.dart";
|
||||||
|
import "package:nexus/models/space.dart";
|
||||||
|
|
||||||
|
extension FocusRoom on MutationTarget {
|
||||||
|
Future<void> focusRoom(String id) async {
|
||||||
|
final spaces = container.read(SpacesController.provider);
|
||||||
|
|
||||||
|
if (spaces.firstWhereOrNull((space) => space.id == id) case Space _?) {
|
||||||
|
return await container
|
||||||
|
.read(KeyController.provider(KeyController.spaceKey).notifier)
|
||||||
|
.set(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
final parent = spaces.firstWhereOrNull(
|
||||||
|
(space) =>
|
||||||
|
space.children.any((room) => room.metadata?.id == id) ||
|
||||||
|
space.subSpaces.any(
|
||||||
|
(sub) =>
|
||||||
|
sub.room.metadata?.id == id ||
|
||||||
|
sub.children.any((room) => room.metadata?.id == id),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (parent == null) return;
|
||||||
|
|
||||||
|
await container
|
||||||
|
.read(KeyController.provider(KeyController.spaceKey).notifier)
|
||||||
|
.set(parent.id);
|
||||||
|
|
||||||
|
await container
|
||||||
|
.read(KeyController.provider(KeyController.roomKey).notifier)
|
||||||
|
.set(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,8 +7,9 @@ part "lazy_load_summary.g.dart";
|
||||||
@Freezed(toJson: false, fromJson: false)
|
@Freezed(toJson: false, fromJson: false)
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class const LazyLoadSummary({
|
class const LazyLoadSummary({
|
||||||
required final IList<String>? heroes,
|
@JsonKey(name: "m.heroes") required final IList<String>? heroes,
|
||||||
required final int? joinedMemberCount,
|
@JsonKey(name: "m.joined_member_count") required final int? joinedMemberCount,
|
||||||
|
@JsonKey(name: "m.invited_member_count")
|
||||||
required final int? invitedMemberCount,
|
required final int? invitedMemberCount,
|
||||||
}) with _$LazyLoadSummary {
|
}) with _$LazyLoadSummary {
|
||||||
Map<String, Object?> toJson() => _$LazyLoadSummaryToJson(this);
|
Map<String, Object?> toJson() => _$LazyLoadSummaryToJson(this);
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,6 @@ part "room_metadata.g.dart";
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class const RoomMetadata({
|
class const RoomMetadata({
|
||||||
@JsonKey(name: "room_id") required final String id,
|
@JsonKey(name: "room_id") required final String id,
|
||||||
|
|
||||||
// CreateEventContent creationContent,
|
|
||||||
// TombstoneEventContent tombstoneEventContent,
|
|
||||||
final String? name,
|
final String? name,
|
||||||
final Uri? avatar,
|
final Uri? avatar,
|
||||||
final String? dmUserId,
|
final String? dmUserId,
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,8 @@ final class const AvatarOrHash(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: .all(.circular((height - 8) / 2.5)),
|
borderRadius: .all(.circular((height - 8) / 2.5)),
|
||||||
child: SizedBox(
|
child: SizedBox.square(
|
||||||
width: height,
|
dimension: height,
|
||||||
height: height,
|
|
||||||
child: avatar == null
|
child: avatar == null
|
||||||
? fallback ?? box
|
? fallback ?? box
|
||||||
: Image(
|
: Image(
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,111 @@
|
||||||
import "package:collection/collection.dart";
|
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||||
import "package:material_ui/material_ui.dart";
|
import "package:material_ui/material_ui.dart";
|
||||||
import "package:flutter_hooks/flutter_hooks.dart";
|
import "package:flutter_hooks/flutter_hooks.dart";
|
||||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:nexus/controllers/client.dart";
|
import "package:nexus/controllers/client.dart";
|
||||||
import "package:nexus/controllers/key.dart";
|
import "package:nexus/controllers/room_summary.dart";
|
||||||
import "package:nexus/controllers/spaces.dart";
|
import "package:nexus/helpers/extensions/better_when.dart";
|
||||||
|
import "package:nexus/helpers/extensions/focus_room.dart";
|
||||||
import "package:nexus/helpers/extensions/link_to_mention.dart";
|
import "package:nexus/helpers/extensions/link_to_mention.dart";
|
||||||
|
import "package:nexus/widgets/room_summary_dialog.dart";
|
||||||
|
import "package:nexus/main.dart";
|
||||||
|
|
||||||
class const JoinDialog(final WidgetRef ref, {super.key}) extends HookWidget {
|
class const JoinDialog(final WidgetRef ref, {super.key}) extends HookWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final roomAlias = useTextEditingController();
|
final roomAlias = useTextEditingController();
|
||||||
|
|
||||||
|
Future<void> onJoin() async {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
|
final roomIdOrAlias = roomAlias.text.mention ?? roomAlias.text;
|
||||||
|
final IList<String> via = .new(
|
||||||
|
Uri.tryParse(roomAlias.text.replaceAll("/#", ""))
|
||||||
|
?.queryParametersAll["via"] ??
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => ref
|
||||||
|
.watch(
|
||||||
|
RoomSummaryController.provider(
|
||||||
|
.new(roomIdOrAlias: roomIdOrAlias, via: via),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.betterWhen(
|
||||||
|
data: (summary) => RoomSummaryDialog(
|
||||||
|
summary,
|
||||||
|
extraActions: .new([
|
||||||
|
TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
// Capture everything before the dialog closes.
|
||||||
|
final container = ProviderScope.containerOf(context);
|
||||||
|
final scaffoldMessenger = ScaffoldMessenger.of(context);
|
||||||
|
final colors = Theme.of(context).colorScheme;
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
|
final snackbar = scaffoldMessenger.showSnackBar(
|
||||||
|
.new(
|
||||||
|
content: Text("Joining room $roomIdOrAlias."),
|
||||||
|
duration: Duration(days: 999),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final id = await container
|
||||||
|
.read(ClientController.provider.notifier)
|
||||||
|
.joinRoom(
|
||||||
|
.new(roomIdOrAlias: roomIdOrAlias, via: via),
|
||||||
|
);
|
||||||
|
|
||||||
|
snackbar.close();
|
||||||
|
|
||||||
|
scaffoldMessenger.showSnackBar(
|
||||||
|
.new(
|
||||||
|
content: Text(
|
||||||
|
"Room $roomIdOrAlias successfully joined.",
|
||||||
|
),
|
||||||
|
action: .new(
|
||||||
|
label: "Open",
|
||||||
|
onPressed: () =>
|
||||||
|
container.focusRoom(id).onError(showError),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
snackbar.close();
|
||||||
|
scaffoldMessenger.showSnackBar(
|
||||||
|
.new(
|
||||||
|
backgroundColor: colors.errorContainer,
|
||||||
|
content: Text(
|
||||||
|
error.toString(),
|
||||||
|
style: .new(color: colors.onErrorContainer),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text("Join"),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
loading: () => Dialog(
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: .center,
|
||||||
|
mainAxisSize: .min,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: .all(24),
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Text("Join a Room"),
|
title: Text("Join a Room"),
|
||||||
content: Column(
|
content: Column(
|
||||||
|
|
@ -21,111 +116,14 @@ class const JoinDialog(final WidgetRef ref, {super.key}) extends HookWidget {
|
||||||
SizedBox(height: 12),
|
SizedBox(height: 12),
|
||||||
TextField(
|
TextField(
|
||||||
controller: roomAlias,
|
controller: roomAlias,
|
||||||
decoration: .new(hintText: "#room:server"),
|
decoration: .new(hintText: "#room:server.name"),
|
||||||
|
onEditingComplete: onJoin,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(onPressed: Navigator.of(context).pop, child: Text("Cancel")),
|
TextButton(onPressed: Navigator.of(context).pop, child: Text("Cancel")),
|
||||||
TextButton(
|
TextButton(onPressed: onJoin, child: Text("Join")),
|
||||||
onPressed: () async {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
|
|
||||||
if (context.mounted) {
|
|
||||||
final roomIdOrAlias = roomAlias.text.mention ?? roomAlias.text;
|
|
||||||
|
|
||||||
final scaffoldMessenger = ScaffoldMessenger.of(context);
|
|
||||||
|
|
||||||
final snackbar = scaffoldMessenger.showSnackBar(
|
|
||||||
.new(
|
|
||||||
content: Text("Joining room $roomIdOrAlias."),
|
|
||||||
duration: Duration(days: 999),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
final id = await ref
|
|
||||||
.watch(ClientController.provider.notifier)
|
|
||||||
.joinRoom(
|
|
||||||
.new(
|
|
||||||
roomIdOrAlias: roomIdOrAlias,
|
|
||||||
via: .new(
|
|
||||||
Uri.tryParse(roomAlias.text.replaceAll("/#", ""))
|
|
||||||
?.queryParametersAll["via"] ??
|
|
||||||
[],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
snackbar.close();
|
|
||||||
|
|
||||||
scaffoldMessenger.showSnackBar(
|
|
||||||
.new(
|
|
||||||
content: Text("Room $roomIdOrAlias successfully joined."),
|
|
||||||
action: .new(
|
|
||||||
label: "Open",
|
|
||||||
onPressed: () async {
|
|
||||||
final spaces = ref.watch(SpacesController.provider);
|
|
||||||
final space = spaces.firstWhereOrNull(
|
|
||||||
(space) => space.id == id,
|
|
||||||
);
|
|
||||||
|
|
||||||
await ref
|
|
||||||
.watch(
|
|
||||||
KeyController.provider(KeyController.spaceKey)
|
|
||||||
.notifier,
|
|
||||||
)
|
|
||||||
.set(
|
|
||||||
space?.id ??
|
|
||||||
spaces
|
|
||||||
.firstWhere(
|
|
||||||
(space) =>
|
|
||||||
space.children.any(
|
|
||||||
(child) =>
|
|
||||||
child.metadata?.id == id,
|
|
||||||
) ||
|
|
||||||
space.subSpaces.any(
|
|
||||||
(child) =>
|
|
||||||
child.room.metadata?.id == id,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (space == null) {
|
|
||||||
await ref
|
|
||||||
.watch(
|
|
||||||
KeyController.provider(KeyController.roomKey)
|
|
||||||
.notifier,
|
|
||||||
)
|
|
||||||
.set(id);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
snackbar.close();
|
|
||||||
if (context.mounted) {
|
|
||||||
scaffoldMessenger.showSnackBar(
|
|
||||||
.new(
|
|
||||||
backgroundColor: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.errorContainer,
|
|
||||||
content: Text(
|
|
||||||
error.toString(),
|
|
||||||
style: .new(
|
|
||||||
color: Theme.of(context).colorScheme.onErrorContainer,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Text("Join"),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
import "dart:async";
|
import "dart:async";
|
||||||
|
|
||||||
import "package:collection/collection.dart";
|
|
||||||
import "package:m3e_buttons/m3e_buttons.dart";
|
import "package:m3e_buttons/m3e_buttons.dart";
|
||||||
import "package:material_ui/material_ui.dart";
|
import "package:material_ui/material_ui.dart";
|
||||||
import "package:flutter_hooks/flutter_hooks.dart";
|
import "package:flutter_hooks/flutter_hooks.dart";
|
||||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:nexus/controllers/contextual_event.dart";
|
import "package:nexus/controllers/contextual_event.dart";
|
||||||
import "package:nexus/controllers/key.dart";
|
|
||||||
import "package:nexus/controllers/notifications.dart";
|
import "package:nexus/controllers/notifications.dart";
|
||||||
import "package:nexus/controllers/spaces.dart";
|
import "package:nexus/helpers/extensions/focus_room.dart";
|
||||||
import "package:nexus/models/event.dart";
|
import "package:nexus/models/event.dart";
|
||||||
import "package:nexus/widgets/appbar.dart";
|
import "package:nexus/widgets/appbar.dart";
|
||||||
import "package:nexus/widgets/error_dialog.dart";
|
import "package:nexus/widgets/error_dialog.dart";
|
||||||
|
|
@ -131,41 +129,7 @@ class const NotificationsPage({
|
||||||
child: HighlightWrapper(
|
child: HighlightWrapper(
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final spaces = ref.read(
|
await ref.focusRoom(event.roomId);
|
||||||
SpacesController.provider,
|
|
||||||
);
|
|
||||||
final space = spaces.firstWhereOrNull(
|
|
||||||
(space) =>
|
|
||||||
space.children.any(
|
|
||||||
(room) =>
|
|
||||||
room.metadata?.id ==
|
|
||||||
event.roomId,
|
|
||||||
) ||
|
|
||||||
space.subSpaces.any(
|
|
||||||
(subSpace) =>
|
|
||||||
subSpace.children.any(
|
|
||||||
(room) =>
|
|
||||||
room.metadata?.id ==
|
|
||||||
event.roomId,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (space == null) return;
|
|
||||||
|
|
||||||
await ref
|
|
||||||
.read(
|
|
||||||
KeyController.provider(
|
|
||||||
KeyController.spaceKey,
|
|
||||||
).notifier,
|
|
||||||
)
|
|
||||||
.set(space.id);
|
|
||||||
await ref
|
|
||||||
.read(
|
|
||||||
KeyController.provider(
|
|
||||||
KeyController.roomKey,
|
|
||||||
).notifier,
|
|
||||||
)
|
|
||||||
.set(event.roomId);
|
|
||||||
ref
|
ref
|
||||||
.watch(
|
.watch(
|
||||||
ContextualEventController.provider(
|
ContextualEventController.provider(
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,8 @@ import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:nexus/controllers/rooms.dart";
|
import "package:nexus/controllers/rooms.dart";
|
||||||
import "package:nexus/widgets/appbar.dart";
|
import "package:nexus/widgets/appbar.dart";
|
||||||
import "package:nexus/widgets/avatar_or_hash.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/widgets/room_menu.dart";
|
import "package:nexus/widgets/room_menu.dart";
|
||||||
|
import "package:nexus/widgets/room_summary_dialog.dart";
|
||||||
|
|
||||||
final class const RoomAppbar({
|
final class const RoomAppbar({
|
||||||
required final String? roomId,
|
required final String? roomId,
|
||||||
|
|
@ -25,61 +24,19 @@ final class const RoomAppbar({
|
||||||
: ref.watch(RoomsController.provider.select((value) => value[roomId!]));
|
: ref.watch(RoomsController.provider.select((value) => value[roomId!]));
|
||||||
|
|
||||||
return Appbar(
|
return Appbar(
|
||||||
onTap: room == null
|
onTap: room?.metadata == null
|
||||||
? null
|
? null
|
||||||
: () => showDialog(
|
: () => showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => Dialog(
|
builder: (context) => RoomSummaryDialog(
|
||||||
constraints: .loose(.fromWidth(400)),
|
.new(
|
||||||
child: Padding(
|
roomId: room!.metadata!.id,
|
||||||
padding: .all(24),
|
joinedMembers:
|
||||||
child: SingleChildScrollView(
|
room.metadata!.lazyLoadSummary?.joinedMemberCount ?? -1,
|
||||||
child: Column(
|
avatarUrl: room.metadata?.avatar,
|
||||||
mainAxisSize: .min,
|
canonicalAlias: room.metadata?.canonicalAlias,
|
||||||
crossAxisAlignment: .start,
|
name: room.metadata?.name,
|
||||||
spacing: 8,
|
topic: room.metadata?.topic,
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
spacing: 12,
|
|
||||||
mainAxisSize: .min,
|
|
||||||
children: [
|
|
||||||
if (room.metadata?.avatar != null)
|
|
||||||
ExpandableImage(
|
|
||||||
room.metadata?.avatar == null
|
|
||||||
? null
|
|
||||||
: .new(mxc: room.metadata!.avatar!),
|
|
||||||
child: AvatarOrHash(
|
|
||||||
room.metadata?.avatar,
|
|
||||||
room.metadata?.name ?? "Unnamed Room",
|
|
||||||
height: 64,
|
|
||||||
fallback: Icon(Icons.numbers),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
room.metadata?.name ?? "Unnamed Room",
|
|
||||||
overflow: .ellipsis,
|
|
||||||
maxLines: 3,
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.headlineSmall,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
if (room.metadata?.topic?.isNotEmpty == true)
|
|
||||||
LinkifiedText(
|
|
||||||
room.metadata!.topic!,
|
|
||||||
style: Theme.of(context).textTheme.bodyLarge
|
|
||||||
?.copyWith(
|
|
||||||
color: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.onSurfaceVariant,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
72
lib/widgets/room_summary_dialog.dart
Normal file
72
lib/widgets/room_summary_dialog.dart
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||||
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
|
import "package:material_ui/material_ui.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 RoomSummaryDialog(
|
||||||
|
final RoomSummary summary, {
|
||||||
|
final IList<Widget> extraActions = const IList.empty(),
|
||||||
|
super.key,
|
||||||
|
}) extends ConsumerWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) => AlertDialog(
|
||||||
|
constraints: .loose(.fromWidth(400)),
|
||||||
|
scrollable: true,
|
||||||
|
contentPadding: EdgeInsets.all(24).copyWith(top: 8),
|
||||||
|
title: Row(
|
||||||
|
spacing: 12,
|
||||||
|
mainAxisSize: .min,
|
||||||
|
children: [
|
||||||
|
if (summary.avatarUrl != null)
|
||||||
|
ExpandableImage(
|
||||||
|
summary.avatarUrl == null ? null : .new(mxc: summary.avatarUrl!),
|
||||||
|
child: AvatarOrHash(
|
||||||
|
summary.avatarUrl,
|
||||||
|
summary.name ?? "Unnamed Room",
|
||||||
|
height: 64,
|
||||||
|
fallback: Icon(Icons.numbers),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
summary.name ?? summary.canonicalAlias ?? summary.roomId,
|
||||||
|
overflow: .ellipsis,
|
||||||
|
maxLines: 3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
content: Column(
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
title: Text("${summary.joinedMembers} members"),
|
||||||
|
leading: Icon(Icons.people),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: SelectableText(summary.canonicalAlias ?? summary.roomId),
|
||||||
|
leading: Icon(Icons.numbers),
|
||||||
|
),
|
||||||
|
|
||||||
|
if (summary.topic != null)
|
||||||
|
ListTile(
|
||||||
|
isThreeLine: true,
|
||||||
|
subtitle: LinkifiedText(
|
||||||
|
summary.topic!,
|
||||||
|
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
leading: Icon(Icons.info),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
actions: [
|
||||||
|
TextButton(onPressed: Navigator.of(context).pop, child: Text("Cancel")),
|
||||||
|
...extraActions,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue