1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-28 05:02:56 +08:00
osu-lazer/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

355 lines
13 KiB
C#
Raw Normal View History

2021-07-13 14:10:44 +08:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
2022-06-17 15:37:17 +08:00
#nullable disable
2021-07-13 14:10:44 +08:00
using System.Collections.Specialized;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
2021-07-13 14:10:44 +08:00
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
2021-07-13 14:10:44 +08:00
using osu.Game.Graphics.Sprites;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
2021-07-13 14:10:44 +08:00
using osu.Game.Users.Drawables;
using osuTK;
2021-07-13 15:02:18 +08:00
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
2021-07-13 14:10:44 +08:00
{
public class DrawableRoomParticipantsList : OnlinePlayComposite
2021-07-13 14:10:44 +08:00
{
private const float avatar_size = 36;
private FillFlowContainer<CircularAvatar> avatarFlow;
2021-08-12 17:51:50 +08:00
private CircularAvatar hostAvatar;
private LinkFlowContainer hostText;
2021-07-13 14:10:44 +08:00
private HiddenUserCount hiddenUsers;
2021-08-12 17:51:50 +08:00
private OsuSpriteText totalCount;
2021-07-13 14:10:44 +08:00
public DrawableRoomParticipantsList()
2021-07-13 14:10:44 +08:00
{
AutoSizeAxes = Axes.X;
Height = 60;
}
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colours)
2021-07-13 14:10:44 +08:00
{
InternalChildren = new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 10,
Shear = new Vector2(0.2f, 0),
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.Background4,
2021-07-13 14:10:44 +08:00
}
},
new FillFlowContainer
{
RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X,
2021-07-13 14:10:44 +08:00
Children = new Drawable[]
{
new FillFlowContainer
2021-07-13 14:10:44 +08:00
{
RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X,
Spacing = new Vector2(8),
Padding = new MarginPadding
{
Left = 8,
Right = 16
},
Children = new Drawable[]
{
hostAvatar = new CircularAvatar
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
},
hostText = new LinkFlowContainer
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
2021-09-30 10:52:14 +08:00
AutoSizeAxes = Axes.Both
}
}
2021-07-13 14:10:44 +08:00
},
new Container
2021-08-12 17:51:50 +08:00
{
RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X,
Children = new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 10,
Shear = new Vector2(0.2f, 0),
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.Background3,
}
},
new FillFlowContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(4),
Padding = new MarginPadding
{
Left = 8,
Right = 16
},
Children = new Drawable[]
{
new SpriteIcon
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Size = new Vector2(16),
Icon = FontAwesome.Solid.User,
},
totalCount = new OsuSpriteText
{
Font = OsuFont.Default.With(weight: FontWeight.Bold),
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
},
avatarFlow = new FillFlowContainer<CircularAvatar>
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(4),
Margin = new MarginPadding { Left = 4 },
},
hiddenUsers = new HiddenUserCount
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
}
}
}
}
2021-08-12 17:51:50 +08:00
},
2021-07-13 14:10:44 +08:00
}
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
RecentParticipants.BindCollectionChanged(onParticipantsChanged, true);
2021-08-12 17:51:50 +08:00
ParticipantCount.BindValueChanged(_ =>
{
updateHiddenUsers();
totalCount.Text = ParticipantCount.Value.ToString();
}, true);
Host.BindValueChanged(onHostChanged, true);
2021-07-13 14:10:44 +08:00
}
2021-08-12 17:47:22 +08:00
private int numberOfCircles = 4;
2021-07-13 14:10:44 +08:00
/// <summary>
/// The maximum number of circles visible (including the "hidden count" circle in the overflow case).
/// </summary>
public int NumberOfCircles
2021-07-13 14:10:44 +08:00
{
get => numberOfCircles;
2021-07-13 14:10:44 +08:00
set
{
numberOfCircles = value;
2021-07-13 14:10:44 +08:00
if (LoadState < LoadState.Loaded)
return;
// Reinitialising the list looks janky, but this is unlikely to be used in a setting where it's visible.
clearUsers();
foreach (var u in RecentParticipants)
addUser(u);
2021-08-12 17:47:22 +08:00
updateHiddenUsers();
2021-07-13 14:10:44 +08:00
}
}
private void onParticipantsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (var added in e.NewItems.OfType<APIUser>())
2021-07-13 14:10:44 +08:00
addUser(added);
break;
case NotifyCollectionChangedAction.Remove:
foreach (var removed in e.OldItems.OfType<APIUser>())
2021-07-13 14:10:44 +08:00
removeUser(removed);
break;
case NotifyCollectionChangedAction.Reset:
clearUsers();
break;
case NotifyCollectionChangedAction.Replace:
case NotifyCollectionChangedAction.Move:
// Easiest is to just reinitialise the whole list. These are unlikely to ever be use cases.
clearUsers();
foreach (var u in RecentParticipants)
addUser(u);
break;
}
2021-08-12 17:47:22 +08:00
updateHiddenUsers();
2021-07-13 14:10:44 +08:00
}
2021-08-12 17:47:22 +08:00
private int displayedCircles => avatarFlow.Count + (hiddenUsers.Count > 0 ? 1 : 0);
private void addUser(APIUser user)
2021-07-13 14:10:44 +08:00
{
2021-08-12 17:47:22 +08:00
if (displayedCircles < NumberOfCircles)
avatarFlow.Add(new CircularAvatar { User = user });
2021-07-13 14:10:44 +08:00
}
private void removeUser(APIUser user)
2021-07-13 14:10:44 +08:00
{
avatarFlow.RemoveAll(a => a.User == user, true);
2021-07-13 14:10:44 +08:00
}
private void clearUsers()
{
avatarFlow.Clear();
2021-08-12 17:47:22 +08:00
updateHiddenUsers();
2021-07-13 14:10:44 +08:00
}
2021-08-12 17:47:22 +08:00
private void updateHiddenUsers()
{
2021-08-12 17:47:22 +08:00
int hiddenCount = 0;
if (RecentParticipants.Count > NumberOfCircles)
hiddenCount = ParticipantCount.Value - NumberOfCircles + 1;
2021-08-12 17:47:22 +08:00
hiddenUsers.Count = hiddenCount;
2021-08-12 17:47:22 +08:00
if (displayedCircles > NumberOfCircles)
avatarFlow.Remove(avatarFlow.Last(), true);
2021-08-12 17:47:22 +08:00
else if (displayedCircles < NumberOfCircles)
{
var nextUser = RecentParticipants.FirstOrDefault(u => avatarFlow.All(a => a.User != u));
if (nextUser != null) addUser(nextUser);
}
}
private void onHostChanged(ValueChangedEvent<APIUser> host)
{
hostAvatar.User = host.NewValue;
hostText.Clear();
if (host.NewValue != null)
2021-09-30 11:04:30 +08:00
{
hostText.AddText("hosted by ");
hostText.AddUserLink(host.NewValue);
2021-09-30 11:04:30 +08:00
}
}
2021-07-13 14:10:44 +08:00
private class CircularAvatar : CompositeDrawable
{
public APIUser User
2021-07-13 14:10:44 +08:00
{
get => avatar.User;
set => avatar.User = value;
}
2021-08-12 17:47:22 +08:00
private readonly UpdateableAvatar avatar = new UpdateableAvatar(showUsernameTooltip: true) { RelativeSizeAxes = Axes.Both };
2021-07-13 14:10:44 +08:00
2021-08-12 17:47:22 +08:00
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colours)
2021-07-13 14:10:44 +08:00
{
Size = new Vector2(avatar_size);
InternalChild = new CircularContainer
{
RelativeSizeAxes = Axes.Both,
Masking = true,
2021-08-12 17:47:22 +08:00
Children = new Drawable[]
{
new Box
{
Colour = colours.Background5,
RelativeSizeAxes = Axes.Both,
},
avatar
}
2021-07-13 14:10:44 +08:00
};
}
}
public class HiddenUserCount : CompositeDrawable
{
public int Count
{
get => count;
set
{
count = value;
countText.Text = $"+{count}";
if (count > 0)
Show();
else
Hide();
}
}
private int count;
private readonly SpriteText countText = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.Default.With(weight: FontWeight.Bold),
};
2021-07-13 14:10:44 +08:00
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colours)
2021-07-13 14:10:44 +08:00
{
Size = new Vector2(avatar_size);
Alpha = 0;
InternalChild = new CircularContainer
{
RelativeSizeAxes = Axes.Both,
Masking = true,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.Background5,
2021-07-13 14:10:44 +08:00
},
countText
2021-07-13 14:10:44 +08:00
}
};
}
}
}
}