chore: show leaderboard on mobile (#3391)

This commit is contained in:
ggurdin 2025-07-10 11:33:53 -04:00 committed by GitHub
parent ad1a84bc5c
commit 4aac64e6b5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 162 additions and 0 deletions

View file

@ -21,6 +21,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/spaces/constants/space_constants.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/stream_extension.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
@ -854,6 +855,15 @@ class _SpaceViewState extends State<SpaceView> {
// },
// ),
KnockingUsersIndicator(room: room),
if (!FluffyThemes.isColumnMode(context))
SliverList.builder(
itemCount: 1,
itemBuilder: (context, i) {
return LeaderboardParticipantList(
space: room,
);
},
),
// Pangea#
SliverList.builder(
itemCount: joinedRooms.length,

View file

@ -0,0 +1,152 @@
import 'package:flutter/material.dart';
import 'package:matrix/matrix.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("")
.where((p) => p.membership == Membership.join)
.toList();
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,
),
),
),
),
),
);
},
);
},
),
),
),
);
},
);
},
);
}
}