Skip to content

Commit

Permalink
Merge pull request #2176 from acterglobal/ben-show-suggested-rooms-on…
Browse files Browse the repository at this point in the history
…-overview

Show suggested rooms on overview
  • Loading branch information
gnunicorn authored Sep 13, 2024
2 parents 6cc6c97 + 9352ce2 commit ff5672c
Show file tree
Hide file tree
Showing 11 changed files with 305 additions and 114 deletions.
1 change: 1 addition & 0 deletions .changes/2176-show-suggested.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Suggested spaces and chats are preferably now shown on the overview of a space, if configured
58 changes: 58 additions & 0 deletions app/lib/common/providers/space_providers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,64 @@ final remoteChatRelationsProvider =
}
});

typedef RoomsAndRoomInfos = (List<String>, List<SpaceHierarchyRoomInfo>);

final suggestedChatsProvider =
FutureProvider.family<RoomsAndRoomInfos, String>((ref, spaceId) async {
try {
final relatedSpaces =
await ref.watch(spaceRelationsOverviewProvider(spaceId).future);
final suggestedRooms = relatedSpaces.suggestedIds;
if (suggestedRooms.isEmpty) {
return (List<String>.empty(), List<SpaceHierarchyRoomInfo>.empty());
}
final toIgnore = relatedSpaces.knownChats.toList();
final localRooms = relatedSpaces.knownChats
.where((r) => suggestedRooms.contains(r))
.toList();
final roomHierarchy =
await ref.watch(spaceRemoteRelationsProvider(spaceId).future);
// filter out the known rooms
final remoteRooms = roomHierarchy
.where((r) =>
!r.isSpace() &&
suggestedRooms.contains(r.roomIdStr()) &&
!toIgnore.contains(r.roomIdStr()),)
.toList();
return (localRooms, remoteRooms);
} on SpaceNotFound {
return (List<String>.empty(), List<SpaceHierarchyRoomInfo>.empty());
}
});

final suggestedSpacesProvider =
FutureProvider.family<RoomsAndRoomInfos, String>((ref, spaceId) async {
try {
final relatedSpaces =
await ref.watch(spaceRelationsOverviewProvider(spaceId).future);
final suggestedRooms = relatedSpaces.suggestedIds;
if (suggestedRooms.isEmpty) {
return (List<String>.empty(), List<SpaceHierarchyRoomInfo>.empty());
}
final toIgnore = relatedSpaces.knownSubspaces.toList();
final localRooms = relatedSpaces.knownSubspaces
.where((r) => suggestedRooms.contains(r))
.toList();
final roomHierarchy =
await ref.watch(spaceRemoteRelationsProvider(spaceId).future);
// filter out the known rooms
final remoteRooms = roomHierarchy
.where((r) =>
r.isSpace() &&
suggestedRooms.contains(r.roomIdStr()) &&
!toIgnore.contains(r.roomIdStr()),)
.toList();
return (localRooms, remoteRooms);
} on SpaceNotFound {
return (List<String>.empty(), List<SpaceHierarchyRoomInfo>.empty());
}
});

final remoteSubspaceRelationsProvider =
FutureProvider.family<List<SpaceHierarchyRoomInfo>, String>(
(ref, spaceId) async {
Expand Down
21 changes: 4 additions & 17 deletions app/lib/common/widgets/room/room_hierarchy_card.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import 'package:acter/common/providers/room_providers.dart';
import 'package:acter/common/widgets/room/room_with_profile_card.dart';
import 'package:acter_flutter_sdk/acter_flutter_sdk_ffi.dart';
import 'package:expandable_text/expandable_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class RoomHierarchyCard extends ConsumerWidget {
Expand Down Expand Up @@ -77,8 +75,8 @@ class RoomHierarchyCard extends ConsumerWidget {
/// Custom trailing widget.
final Widget? trailing;

/// Whether to show the suggested icon if this is a suggested space
final bool showIconIfSuggested;
/// Whether to show the suggested info if this is a suggested room
final bool indicateIfSuggested;

const RoomHierarchyCard({
super.key,
Expand All @@ -94,30 +92,19 @@ class RoomHierarchyCard extends ConsumerWidget {
this.contentPadding = const EdgeInsets.all(15),
this.shape,
this.withBorder = true,
this.showIconIfSuggested = false,
this.indicateIfSuggested = false,
this.trailing,
});

@override
Widget build(BuildContext context, WidgetRef ref) {
final roomId = roomInfo.roomIdStr();
final avatarInfo = ref.watch(roomHierarchyAvatarInfoProvider(roomInfo));
final topic = roomInfo.topic();
bool showSuggested = showIconIfSuggested && roomInfo.suggested();
final Widget? subtitle = topic?.isNotEmpty == true
? ExpandableText(
topic!,
maxLines: 2,
expandText: L10n.of(context).showMore,
collapseText: L10n.of(context).showLess,
linkColor: Theme.of(context).colorScheme.primary,
)
: null;
bool showSuggested = indicateIfSuggested && roomInfo.suggested();

return RoomWithAvatarInfoCard(
roomId: roomId,
avatarInfo: avatarInfo,
subtitle: subtitle,
onTap: onTap ?? () {},
onFocusChange: onFocusChange,
onLongPress: onLongPress,
Expand Down
2 changes: 1 addition & 1 deletion app/lib/features/space/dialogs/suggested_rooms.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class __SuggestedRoomsState extends ConsumerState<_SuggestedRooms> {
super.initState();

ref.listenManual(
suggestedRoomsProvider(widget.spaceId),
roomsToSuggestProvider(widget.spaceId),
(prev, next) {
if (next.hasValue) {
setState(() {
Expand Down
1 change: 1 addition & 0 deletions app/lib/features/space/pages/chats_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class SpaceChatsPage extends ConsumerWidget {

Widget _renderLoading(BuildContext context) {
return ListView.builder(
shrinkWrap: true,
itemCount: 3,
itemBuilder: (context, idx) => const LoadingConvoCard(roomId: 'fake'),
);
Expand Down
7 changes: 5 additions & 2 deletions app/lib/features/space/providers/suggested_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ final shouldShowSuggestedProvider =
}

final suggestedRooms =
await ref.watch(suggestedRoomsProvider(spaceId).future);
await ref.watch(roomsToSuggestProvider(spaceId).future);
// only if we really have some remote rooms that the user is suggested and not yet in
return suggestedRooms.chats.isNotEmpty || suggestedRooms.spaces.isNotEmpty;
} catch (e, s) {
Expand All @@ -33,11 +33,14 @@ typedef SuggestedRooms = ({
List<SpaceHierarchyRoomInfo> chats
});

final suggestedRoomsProvider =
// Will show the room _to_ suggest to the user, ergo excludes rooms they are
// already in
final roomsToSuggestProvider =
FutureProvider.family<SuggestedRooms, String>((ref, roomId) async {
final chats = await ref.watch(remoteChatRelationsProvider(roomId).future);
final spaces =
await ref.watch(remoteSubspaceRelationsProvider(roomId).future);

return (
chats: chats.where((r) => r.suggested()).toList(),
spaces: spaces.where((r) => r.suggested()).toList()
Expand Down
95 changes: 54 additions & 41 deletions app/lib/features/space/widgets/related/chats_helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:acter/common/widgets/room/room_hierarchy_card.dart';
import 'package:acter/common/widgets/room/room_hierarchy_join_button.dart';
import 'package:acter/common/widgets/room/room_hierarchy_options_menu.dart';
import 'package:acter/router/utils.dart';
import 'package:acter_flutter_sdk/acter_flutter_sdk_ffi.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
Expand All @@ -19,6 +20,7 @@ Widget chatsListUI(
List<String> chats,
int chatsLimit, {
bool showOptions = false,
bool showSuggestedMarkIfGiven = true,
}) {
final suggestedId =
ref.watch(suggestedIdsProvider(parentId)).valueOrNull ?? [];
Expand All @@ -32,7 +34,8 @@ Widget chatsListUI(
return RoomCard(
roomId: roomId,
showParents: false,
showSuggestedMark: suggestedId.contains(roomId),
showSuggestedMark:
showSuggestedMarkIfGiven && suggestedId.contains(roomId),
onTap: () => goToChat(context, roomId),
trailing: showOptions
? RoomHierarchyOptionsMenu(
Expand All @@ -46,6 +49,55 @@ Widget chatsListUI(
);
}

Widget renderRemoteChats(
BuildContext context,
WidgetRef ref,
String parentId,
List<SpaceHierarchyRoomInfo> chats,
int? maxItems, {
bool showSuggestedMarkIfGiven = true,
bool renderMenu = true,
}) {
if (chats.isEmpty) return const SizedBox.shrink();
return ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
itemCount: maxItems ?? chats.length,
itemBuilder: (context, index) {
final roomInfo = chats[index];
final roomId = roomInfo.roomIdStr();
return RoomHierarchyCard(
indicateIfSuggested: showSuggestedMarkIfGiven,
parentId: parentId,
roomInfo: roomInfo,
trailing: Wrap(
children: [
RoomHierarchyJoinButton(
joinRule: roomInfo.joinRuleStr().toLowerCase(),
roomId: roomId,
roomName: roomInfo.name() ?? roomId,
viaServerName: roomInfo.viaServerName(),
forward: (roomId) {
goToChat(context, roomId);
// make sure the UI refreshes when the user comes back here
ref.invalidate(spaceRelationsProvider(parentId));
ref.invalidate(spaceRemoteRelationsProvider(parentId));
},
),
if (renderMenu)
RoomHierarchyOptionsMenu(
isSuggested: roomInfo.suggested(),
childId: roomId,
parentId: parentId,
),
],
),
);
},
);
}

Widget renderFurther(
BuildContext context,
WidgetRef ref,
Expand All @@ -54,46 +106,7 @@ Widget renderFurther(
) {
final relatedChatsLoader = ref.watch(remoteChatRelationsProvider(spaceId));
return relatedChatsLoader.when(
data: (chats) {
if (chats.isEmpty) return const SizedBox.shrink();
return ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
itemCount: maxItems ?? chats.length,
itemBuilder: (context, index) {
final roomInfo = chats[index];
final roomId = roomInfo.roomIdStr();
final parentId = spaceId;
return RoomHierarchyCard(
showIconIfSuggested: true,
parentId: parentId,
roomInfo: roomInfo,
trailing: Wrap(
children: [
RoomHierarchyJoinButton(
joinRule: roomInfo.joinRuleStr().toLowerCase(),
roomId: roomId,
roomName: roomInfo.name() ?? roomId,
viaServerName: roomInfo.viaServerName(),
forward: (roomId) {
goToChat(context, roomId);
// make sure the UI refreshes when the user comes back here
ref.invalidate(spaceRelationsProvider(parentId));
ref.invalidate(spaceRemoteRelationsProvider(parentId));
},
),
RoomHierarchyOptionsMenu(
isSuggested: roomInfo.suggested(),
childId: roomId,
parentId: parentId,
),
],
),
);
},
);
},
data: (chats) => renderRemoteChats(context, ref, spaceId, chats, maxItems),
error: (e, s) {
_log.severe('Failed to load the related chats', e, s);
return Card(
Expand Down
Loading

0 comments on commit ff5672c

Please sign in to comment.