@@ -11,7 +11,9 @@ import 'package:kyber_launcher/features/maxima/widgets/maxima_avatar.dart';
1111import 'package:kyber_launcher/features/session/providers/session_cubit.dart' ;
1212import 'package:kyber_launcher/gen/fonts.gen.dart' ;
1313import 'package:kyber_launcher/gen/rust/api/maxima.dart' ;
14- import 'package:kyber_launcher/shared/ui/buttons/button.dart' ;
14+ import 'package:kyber_launcher/shared/ui/buttons/normal_button.dart' ;
15+ import 'package:kyber_launcher/shared/ui/ui.dart' ;
16+ import 'package:super_sliver_list/super_sliver_list.dart' ;
1517
1618class MaximaFriendsDialog extends StatelessWidget {
1719 const MaximaFriendsDialog ({super .key});
@@ -65,9 +67,10 @@ class _PartyPanel extends StatelessWidget {
6567 return Padding (
6668 padding: const .only (top: 20 ),
6769 child: Column (
68- crossAxisAlignment: .start ,
70+ crossAxisAlignment: .stretch ,
6971 children: [
7072 const _SectionHeader (title: 'Multiplayer Group' ),
73+ const SizedBox (height: 1 , child: ColoredBox (color: decoColor)),
7174 Expanded (
7275 child: BlocBuilder <SessionCubit , SessionState >(
7376 builder: (context, state) {
@@ -214,14 +217,33 @@ class _PartyMemberList extends StatelessWidget {
214217 Widget build (BuildContext context) {
215218 final members = party.party.members;
216219
217- return ListView .separated (
218- itemCount: members.length,
219- separatorBuilder: (_, __) => const _MemberDivider (),
220+ return SuperListView .separated (
221+ itemCount: members.length + 1 ,
220222 itemBuilder: (_, index) {
223+ if (index == members.length) {
224+ return const SizedBox .shrink ();
225+ }
226+
221227 final player = members[index].player;
228+ final isLeader = party.party.leaderId == player.id;
229+
222230 return _MemberTile (
223231 name: player.name,
224232 avatar: MaximaAvatar (pd: player.id, height: 50 , width: 50 ),
233+ id: player.id,
234+ status: switch (isLeader) {
235+ true => Text (
236+ 'Group Leader' ,
237+ style: .new (color: kActiveColor),
238+ ),
239+ _ => const Text ('Online' ),
240+ },
241+ );
242+ },
243+ separatorBuilder: (context, index) {
244+ return Container (
245+ height: 1 ,
246+ color: decoColor,
225247 );
226248 },
227249 );
@@ -237,6 +259,7 @@ class _CurrentUserTile extends StatelessWidget {
237259 _MemberTile (
238260 name: player.displayName,
239261 avatar: MaximaAvatar (pd: player.id, height: 50 , width: 50 ),
262+ id: player.id,
240263 ),
241264 const _MemberDivider (),
242265 ],
@@ -245,57 +268,100 @@ class _CurrentUserTile extends StatelessWidget {
245268}
246269
247270class _MemberTile extends StatelessWidget {
248- const _MemberTile ({required this .name, required this .avatar});
271+ const _MemberTile ({
272+ required this .name,
273+ required this .avatar,
274+ this .status,
275+ this .id = '' ,
276+ });
249277
250278 final String name;
251279 final Widget avatar;
280+ final Text ? status;
281+ final String id;
252282
253283 @override
254284 Widget build (BuildContext context) {
285+ final userId = context.read <MaximaCubit >().state.servicePlayer! .id;
286+
255287 return Container (
256288 decoration: BoxDecoration (
257289 color: Colors .white.withOpacity (.05 ),
258- border: const .symmetric (
259- horizontal: .new (color: decoColor, width: 1.5 ),
260- ),
261290 ),
262- child: Padding (
263- padding: const EdgeInsets .symmetric (
264- horizontal: 10 ,
265- vertical: 5 ,
266- ).copyWith (left: 15 ),
267- child: Row (
268- crossAxisAlignment: .start,
269- children: [
270- Container (
271- clipBehavior: .antiAliasWithSaveLayer,
272- decoration: const BoxDecoration (
273- borderRadius: .all (.circular (6 )),
274- ),
275- child: avatar,
291+ child: HoverBuilder (
292+ builder: (context, hovered) {
293+ final partyState = context.select (
294+ (SessionCubit cubit) => cubit.state,
295+ );
296+ final isLeader =
297+ partyState is InParty && partyState.party.leaderId == userId;
298+
299+ return Padding (
300+ padding: const .symmetric (
301+ horizontal: 15 ,
302+ vertical: 5 ,
276303 ),
277- const SizedBox (width: 10 ),
278- DefaultTextStyle (
279- style: const .new (height: 1 , fontFamily: FontFamily .battlefrontUI),
280- child: Column (
281- crossAxisAlignment: .start,
282- children: [
283- const SizedBox (height: 2 ),
284- Text (name, style: const .new (fontSize: 18 )),
285- const SizedBox (height: 5 ),
286- const Divider (
287- size: 10 ,
288- style: DividerThemeData (
289- horizontalMargin: .zero,
290- verticalMargin: .symmetric (vertical: 10 ),
291- decoration: BoxDecoration (color: decoColor),
304+ child: Stack (
305+ children: [
306+ Row (
307+ crossAxisAlignment: .start,
308+ children: [
309+ Container (
310+ clipBehavior: .antiAliasWithSaveLayer,
311+ decoration: const BoxDecoration (
312+ borderRadius: .all (.circular (6 )),
313+ ),
314+ child: avatar,
315+ ),
316+ const SizedBox (width: 10 ),
317+ DefaultTextStyle (
318+ style: const .new (
319+ height: 1 ,
320+ fontFamily: FontFamily .battlefrontUI,
321+ ),
322+ child: Padding (
323+ padding: const .symmetric (vertical: 2 ),
324+ child: Column (
325+ crossAxisAlignment: .start,
326+ mainAxisAlignment: .center,
327+ spacing: 5 ,
328+ children: [
329+ Text (name, style: const .new (fontSize: 18 )),
330+ const Divider (
331+ size: 10 ,
332+ style: DividerThemeData (
333+ horizontalMargin: .zero,
334+ verticalMargin: .symmetric (vertical: 10 ),
335+ decoration: BoxDecoration (color: decoColor),
336+ ),
337+ ),
338+ ? status,
339+ ],
340+ ),
341+ ),
342+ ),
343+ ],
344+ ),
345+ if (hovered && isLeader && userId != id)
346+ Positioned (
347+ right: 0 ,
348+ top: 0 ,
349+ bottom: 0 ,
350+ child: Row (
351+ children: [
352+ KOutlinedButton (
353+ child: Icon (mt.Icons .close_sharp, size: 25 ),
354+ onPressed: () {
355+ // TODO: Implement kick from party
356+ },
357+ ),
358+ ],
292359 ),
293360 ),
294- ],
295- ),
361+ ],
296362 ),
297- ],
298- ) ,
363+ );
364+ } ,
299365 ),
300366 );
301367 }
0 commit comments