Merge pull request #2947 from pangeachat/2842-show-participants-in-chat-list
2842 show participants in chat list
This commit is contained in:
commit
4fccaa92f2
6 changed files with 260 additions and 22 deletions
|
|
@ -20,6 +20,7 @@ import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
|
||||||
import 'package:fluffychat/pangea/public_spaces/public_room_bottom_sheet.dart';
|
import 'package:fluffychat/pangea/public_spaces/public_room_bottom_sheet.dart';
|
||||||
import 'package:fluffychat/pangea/spaces/constants/space_constants.dart';
|
import 'package:fluffychat/pangea/spaces/constants/space_constants.dart';
|
||||||
import 'package:fluffychat/pangea/spaces/widgets/knocking_users_indicator.dart';
|
import 'package:fluffychat/pangea/spaces/widgets/knocking_users_indicator.dart';
|
||||||
|
import 'package:fluffychat/pangea/spaces/widgets/leaderboard_participant_list.dart';
|
||||||
import 'package:fluffychat/utils/localized_exception_extension.dart';
|
import 'package:fluffychat/utils/localized_exception_extension.dart';
|
||||||
import 'package:fluffychat/utils/stream_extension.dart';
|
import 'package:fluffychat/utils/stream_extension.dart';
|
||||||
import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
|
import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
|
||||||
|
|
@ -802,6 +803,14 @@ class _SpaceViewState extends State<SpaceView> {
|
||||||
// },
|
// },
|
||||||
// ),
|
// ),
|
||||||
KnockingUsersIndicator(room: room),
|
KnockingUsersIndicator(room: room),
|
||||||
|
SliverList.builder(
|
||||||
|
itemCount: 1,
|
||||||
|
itemBuilder: (context, i) {
|
||||||
|
return LeaderboardParticipantList(
|
||||||
|
space: room,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
// Pangea#
|
// Pangea#
|
||||||
SliverList.builder(
|
SliverList.builder(
|
||||||
itemCount: joinedRooms.length,
|
itemCount: joinedRooms.length,
|
||||||
|
|
|
||||||
|
|
@ -98,11 +98,21 @@ class PresenceAvatar extends StatelessWidget {
|
||||||
final CachedPresence presence;
|
final CachedPresence presence;
|
||||||
final double height;
|
final double height;
|
||||||
final void Function(Profile) onTap;
|
final void Function(Profile) onTap;
|
||||||
|
// #Pangea
|
||||||
|
final LinearGradient? gradient;
|
||||||
|
final Widget? floatingIndicator;
|
||||||
|
final bool showPresence;
|
||||||
|
// Pangea#
|
||||||
|
|
||||||
const PresenceAvatar({
|
const PresenceAvatar({
|
||||||
required this.presence,
|
required this.presence,
|
||||||
required this.height,
|
required this.height,
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
|
// #Pangea
|
||||||
|
this.gradient,
|
||||||
|
this.showPresence = true,
|
||||||
|
this.floatingIndicator,
|
||||||
|
// Pangea#
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -146,7 +156,11 @@ class PresenceAvatar extends StatelessWidget {
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(3),
|
padding: const EdgeInsets.all(3),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: presence.gradient,
|
// #Pangea
|
||||||
|
// gradient: presence.gradient,
|
||||||
|
gradient: gradient ??
|
||||||
|
(showPresence ? presence.gradient : null),
|
||||||
|
// Pangea#
|
||||||
borderRadius:
|
borderRadius:
|
||||||
BorderRadius.circular(avatarSize),
|
BorderRadius.circular(avatarSize),
|
||||||
),
|
),
|
||||||
|
|
@ -159,7 +173,11 @@ class PresenceAvatar extends StatelessWidget {
|
||||||
size: avatarSize - 6,
|
size: avatarSize - 6,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (presence.userid == client.userID)
|
// #Pangea
|
||||||
|
// if (presence.userid == client.userID)
|
||||||
|
if (floatingIndicator == null &&
|
||||||
|
presence.userid == client.userID)
|
||||||
|
// Pangea#
|
||||||
Positioned(
|
Positioned(
|
||||||
right: 0,
|
right: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
|
|
@ -182,6 +200,9 @@ class PresenceAvatar extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
// #Pangea
|
||||||
|
if (floatingIndicator != null) floatingIndicator!,
|
||||||
|
// Pangea#
|
||||||
if (statusMsg != null) ...[
|
if (statusMsg != null) ...[
|
||||||
Positioned(
|
Positioned(
|
||||||
left: 0,
|
left: 0,
|
||||||
|
|
|
||||||
|
|
@ -207,6 +207,36 @@ class SettingsController extends State<Settings> {
|
||||||
// Pangea#
|
// Pangea#
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #Pangea
|
||||||
|
void setStatus() async {
|
||||||
|
final client = Matrix.of(context).client;
|
||||||
|
final currentPresence = await client.fetchCurrentPresence(client.userID!);
|
||||||
|
final input = await showTextInputDialog(
|
||||||
|
useRootNavigator: false,
|
||||||
|
context: context,
|
||||||
|
title: L10n.of(context).setStatus,
|
||||||
|
message: L10n.of(context).leaveEmptyToClearStatus,
|
||||||
|
okLabel: L10n.of(context).ok,
|
||||||
|
cancelLabel: L10n.of(context).cancel,
|
||||||
|
hintText: L10n.of(context).statusExampleMessage,
|
||||||
|
maxLines: 6,
|
||||||
|
minLines: 1,
|
||||||
|
maxLength: 255,
|
||||||
|
initialText: currentPresence.statusMsg,
|
||||||
|
);
|
||||||
|
if (input == null) return;
|
||||||
|
if (!mounted) return;
|
||||||
|
await showFutureLoadingDialog(
|
||||||
|
context: context,
|
||||||
|
future: () => client.setPresence(
|
||||||
|
client.userID!,
|
||||||
|
PresenceType.online,
|
||||||
|
statusMsg: input,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Pangea#
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final client = Matrix.of(context).client;
|
final client = Matrix.of(context).client;
|
||||||
|
|
|
||||||
|
|
@ -165,6 +165,25 @@ class SettingsView extends StatelessWidget {
|
||||||
// style: const TextStyle(fontSize: 12),
|
// style: const TextStyle(fontSize: 12),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
// #Pangea
|
||||||
|
TextButton.icon(
|
||||||
|
onPressed: controller.setStatus,
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.add,
|
||||||
|
size: 14,
|
||||||
|
),
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
foregroundColor:
|
||||||
|
theme.colorScheme.secondary,
|
||||||
|
iconColor: theme.colorScheme.secondary,
|
||||||
|
),
|
||||||
|
label: Text(
|
||||||
|
L10n.of(context).setStatus,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Pangea#
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import 'package:flutter_linkify/flutter_linkify.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:matrix/matrix.dart';
|
import 'package:matrix/matrix.dart';
|
||||||
|
|
||||||
import 'package:fluffychat/config/app_config.dart';
|
|
||||||
import 'package:fluffychat/config/themes.dart';
|
import 'package:fluffychat/config/themes.dart';
|
||||||
import 'package:fluffychat/pages/chat_details/chat_details.dart';
|
import 'package:fluffychat/pages/chat_details/chat_details.dart';
|
||||||
import 'package:fluffychat/pages/chat_details/participant_list_item.dart';
|
import 'package:fluffychat/pages/chat_details/participant_list_item.dart';
|
||||||
|
|
@ -23,6 +22,7 @@ import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart';
|
||||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
|
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
|
||||||
import 'package:fluffychat/pangea/spaces/utils/load_participants_util.dart';
|
import 'package:fluffychat/pangea/spaces/utils/load_participants_util.dart';
|
||||||
import 'package:fluffychat/pangea/spaces/widgets/download_space_analytics_dialog.dart';
|
import 'package:fluffychat/pangea/spaces/widgets/download_space_analytics_dialog.dart';
|
||||||
|
import 'package:fluffychat/pangea/spaces/widgets/leaderboard_participant_list.dart';
|
||||||
import 'package:fluffychat/utils/fluffy_share.dart';
|
import 'package:fluffychat/utils/fluffy_share.dart';
|
||||||
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
|
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
|
||||||
import 'package:fluffychat/utils/url_launcher.dart';
|
import 'package:fluffychat/utils/url_launcher.dart';
|
||||||
|
|
@ -721,22 +721,15 @@ class RoomParticipantsSection extends StatelessWidget {
|
||||||
runAlignment: WrapAlignment.center,
|
runAlignment: WrapAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
...filteredParticipants.mapIndexed((index, user) {
|
...filteredParticipants.mapIndexed((index, user) {
|
||||||
Color? color = index == 0
|
|
||||||
? AppConfig.gold
|
|
||||||
: index == 1
|
|
||||||
? Colors.grey[400]!
|
|
||||||
: index == 2
|
|
||||||
? Colors.brown[400]!
|
|
||||||
: null;
|
|
||||||
|
|
||||||
final publicProfile = participantsLoader.getPublicProfile(
|
final publicProfile = participantsLoader.getPublicProfile(
|
||||||
user.id,
|
user.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
LinearGradient? gradient = index.leaderboardGradient;
|
||||||
if (user.id == BotName.byEnvironment ||
|
if (user.id == BotName.byEnvironment ||
|
||||||
publicProfile == null ||
|
publicProfile == null ||
|
||||||
publicProfile.level == null) {
|
publicProfile.level == null) {
|
||||||
color = null;
|
gradient = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
|
|
@ -748,21 +741,13 @@ class RoomParticipantsSection extends StatelessWidget {
|
||||||
Stack(
|
Stack(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
children: [
|
children: [
|
||||||
if (color != null)
|
if (gradient != null)
|
||||||
CircleAvatar(
|
CircleAvatar(
|
||||||
radius: _width / 2,
|
radius: _width / 2,
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
gradient: LinearGradient(
|
gradient: gradient,
|
||||||
begin: const Alignment(0.5, -0.5),
|
|
||||||
end: const Alignment(-0.5, 0.5),
|
|
||||||
colors: <Color>[
|
|
||||||
color,
|
|
||||||
Colors.white,
|
|
||||||
color,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
174
lib/pangea/spaces/widgets/leaderboard_participant_list.dart
Normal file
174
lib/pangea/spaces/widgets/leaderboard_participant_list.dart
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:matrix/matrix.dart';
|
||||||
|
|
||||||
|
import 'package:fluffychat/config/app_config.dart';
|
||||||
|
import 'package:fluffychat/config/themes.dart';
|
||||||
|
import 'package:fluffychat/pages/chat_list/status_msg_list.dart';
|
||||||
|
import 'package:fluffychat/pangea/bot/utils/bot_name.dart';
|
||||||
|
import 'package:fluffychat/pangea/spaces/utils/load_participants_util.dart';
|
||||||
|
import 'package:fluffychat/utils/stream_extension.dart';
|
||||||
|
import 'package:fluffychat/widgets/adaptive_dialogs/user_dialog.dart';
|
||||||
|
import 'package:fluffychat/widgets/matrix.dart';
|
||||||
|
import 'package:fluffychat/widgets/presence_builder.dart';
|
||||||
|
|
||||||
|
class LeaderboardParticipantList extends StatefulWidget {
|
||||||
|
final Room space;
|
||||||
|
|
||||||
|
const LeaderboardParticipantList({
|
||||||
|
required this.space,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
static const double height = 116;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<LeaderboardParticipantList> createState() =>
|
||||||
|
LeaderboardParticipantListState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class LeaderboardParticipantListState
|
||||||
|
extends State<LeaderboardParticipantList> {
|
||||||
|
final _scrollController = ScrollController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_scrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final client = Matrix.of(context).client;
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
|
||||||
|
return StreamBuilder(
|
||||||
|
stream: client.onSync.stream.rateLimit(const Duration(seconds: 3)),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
return LoadParticipantsUtil(
|
||||||
|
space: widget.space,
|
||||||
|
builder: (participantsLoader) {
|
||||||
|
final participants = participantsLoader.filteredParticipants("");
|
||||||
|
|
||||||
|
return AnimatedSize(
|
||||||
|
duration: FluffyThemes.animationDuration,
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 130.0,
|
||||||
|
child: Scrollbar(
|
||||||
|
controller: _scrollController,
|
||||||
|
child: ListView.builder(
|
||||||
|
controller: _scrollController,
|
||||||
|
padding: const EdgeInsets.fromLTRB(
|
||||||
|
8.0,
|
||||||
|
8.0,
|
||||||
|
8.0,
|
||||||
|
16.0,
|
||||||
|
),
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
itemCount: participants.length,
|
||||||
|
itemBuilder: (context, i) {
|
||||||
|
final user = participants[i];
|
||||||
|
final publicProfile = participantsLoader.getPublicProfile(
|
||||||
|
user.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
LinearGradient? gradient = i.leaderboardGradient;
|
||||||
|
|
||||||
|
if (user.id == BotName.byEnvironment ||
|
||||||
|
publicProfile == null ||
|
||||||
|
publicProfile.level == null) {
|
||||||
|
gradient = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PresenceBuilder(
|
||||||
|
userId: user.id,
|
||||||
|
builder: (context, presence) {
|
||||||
|
Color? dotColor;
|
||||||
|
if (presence != null) {
|
||||||
|
dotColor = presence.presence.isOnline
|
||||||
|
? Colors.green
|
||||||
|
: presence.presence.isUnavailable
|
||||||
|
? Colors.orange
|
||||||
|
: Colors.grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PresenceAvatar(
|
||||||
|
presence: presence ??
|
||||||
|
CachedPresence(
|
||||||
|
PresenceType.unavailable,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
user.id,
|
||||||
|
),
|
||||||
|
height: StatusMessageList.height,
|
||||||
|
onTap: (profile) => UserDialog.show(
|
||||||
|
context: context,
|
||||||
|
profile: profile,
|
||||||
|
),
|
||||||
|
gradient: gradient,
|
||||||
|
showPresence: false,
|
||||||
|
floatingIndicator: Positioned(
|
||||||
|
bottom: 0,
|
||||||
|
right: 0,
|
||||||
|
child: Container(
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: theme.colorScheme.surface,
|
||||||
|
borderRadius: BorderRadius.circular(32),
|
||||||
|
),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Container(
|
||||||
|
width: 10,
|
||||||
|
height: 10,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: dotColor,
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
border: Border.all(
|
||||||
|
width: 1,
|
||||||
|
color: theme.colorScheme.surface,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension LeaderboardGradient on int {
|
||||||
|
LinearGradient? get leaderboardGradient {
|
||||||
|
final Color? color = this == 0
|
||||||
|
? AppConfig.gold
|
||||||
|
: this == 1
|
||||||
|
? Colors.grey[400]!
|
||||||
|
: this == 2
|
||||||
|
? Colors.brown[400]!
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (color == null) return null;
|
||||||
|
|
||||||
|
return LinearGradient(
|
||||||
|
colors: [
|
||||||
|
color,
|
||||||
|
Colors.white,
|
||||||
|
color,
|
||||||
|
],
|
||||||
|
begin: Alignment.topLeft,
|
||||||
|
end: Alignment.bottomRight,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue