2020-02-03 00:21:22 +08:00
|
|
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
2019-01-28 06:45:00 +08:00
|
|
|
// See the LICENCE file in the repository root for full licence text.
|
2019-01-11 08:12:19 +08:00
|
|
|
|
2022-06-17 15:37:17 +08:00
|
|
|
#nullable disable
|
|
|
|
|
2019-01-11 08:12:19 +08:00
|
|
|
using System;
|
2021-03-22 02:16:59 +08:00
|
|
|
using Humanizer;
|
2019-01-11 08:12:19 +08:00
|
|
|
using osu.Framework.Allocation;
|
2019-03-10 06:58:14 +08:00
|
|
|
using osu.Framework.Bindables;
|
2019-01-11 08:12:19 +08:00
|
|
|
using osu.Framework.Extensions;
|
|
|
|
using osu.Framework.Graphics;
|
|
|
|
using osu.Framework.Graphics.Containers;
|
|
|
|
using osu.Framework.Graphics.Shapes;
|
|
|
|
using osu.Framework.Graphics.Sprites;
|
2022-01-28 12:53:48 +08:00
|
|
|
using osu.Framework.Localisation;
|
2019-01-11 08:12:19 +08:00
|
|
|
using osu.Game.Graphics;
|
|
|
|
using osu.Game.Graphics.Containers;
|
2020-12-24 17:11:40 +08:00
|
|
|
using osu.Game.Online.API;
|
2021-11-04 17:02:44 +08:00
|
|
|
using osu.Game.Online.API.Requests.Responses;
|
2022-01-28 12:53:48 +08:00
|
|
|
using osu.Game.Resources.Localisation.Web;
|
2019-01-11 08:12:19 +08:00
|
|
|
using osuTK;
|
|
|
|
using osuTK.Graphics;
|
|
|
|
|
|
|
|
namespace osu.Game.Overlays.Profile.Header
|
|
|
|
{
|
2019-03-10 06:58:14 +08:00
|
|
|
public partial class BottomHeaderContainer : CompositeDrawable
|
2019-01-11 08:12:19 +08:00
|
|
|
{
|
2021-11-04 17:02:44 +08:00
|
|
|
public readonly Bindable<APIUser> User = new Bindable<APIUser>();
|
2019-04-25 17:42:19 +08:00
|
|
|
|
2020-02-03 00:21:22 +08:00
|
|
|
private LinkFlowContainer topLinkContainer;
|
|
|
|
private LinkFlowContainer bottomLinkContainer;
|
2019-01-11 08:12:19 +08:00
|
|
|
|
2019-04-25 17:42:19 +08:00
|
|
|
private Color4 iconColour;
|
2019-01-11 08:12:19 +08:00
|
|
|
|
2020-12-24 17:11:40 +08:00
|
|
|
[Resolved]
|
|
|
|
private IAPIProvider api { get; set; }
|
|
|
|
|
2019-04-25 17:42:19 +08:00
|
|
|
public BottomHeaderContainer()
|
2019-01-11 08:12:19 +08:00
|
|
|
{
|
2019-03-10 06:58:14 +08:00
|
|
|
AutoSizeAxes = Axes.Y;
|
2019-04-25 17:42:19 +08:00
|
|
|
}
|
2019-03-10 06:58:14 +08:00
|
|
|
|
2019-04-25 17:42:19 +08:00
|
|
|
[BackgroundDependencyLoader]
|
2020-01-30 05:10:19 +08:00
|
|
|
private void load(OverlayColourProvider colourProvider)
|
2019-04-25 17:42:19 +08:00
|
|
|
{
|
2020-01-30 05:10:19 +08:00
|
|
|
iconColour = colourProvider.Foreground1;
|
2019-04-25 19:05:59 +08:00
|
|
|
|
2019-03-10 06:58:14 +08:00
|
|
|
InternalChildren = new Drawable[]
|
2019-01-11 08:12:19 +08:00
|
|
|
{
|
|
|
|
new Box
|
|
|
|
{
|
|
|
|
RelativeSizeAxes = Axes.Both,
|
2020-01-30 05:10:19 +08:00
|
|
|
Colour = colourProvider.Background4
|
2019-01-11 08:12:19 +08:00
|
|
|
},
|
2020-02-03 00:21:22 +08:00
|
|
|
new FillFlowContainer
|
2019-01-11 08:12:19 +08:00
|
|
|
{
|
|
|
|
RelativeSizeAxes = Axes.X,
|
|
|
|
AutoSizeAxes = Axes.Y,
|
2020-02-03 00:21:22 +08:00
|
|
|
Direction = FillDirection.Vertical,
|
2019-01-11 08:12:19 +08:00
|
|
|
Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 },
|
|
|
|
Spacing = new Vector2(0, 10),
|
2020-02-03 00:21:22 +08:00
|
|
|
Children = new Drawable[]
|
|
|
|
{
|
|
|
|
topLinkContainer = new LinkFlowContainer(text => text.Font = text.Font.With(size: 12))
|
|
|
|
{
|
|
|
|
RelativeSizeAxes = Axes.X,
|
|
|
|
AutoSizeAxes = Axes.Y,
|
|
|
|
},
|
|
|
|
bottomLinkContainer = new LinkFlowContainer(text => text.Font = text.Font.With(size: 12))
|
|
|
|
{
|
|
|
|
RelativeSizeAxes = Axes.X,
|
|
|
|
AutoSizeAxes = Axes.Y,
|
|
|
|
}
|
|
|
|
}
|
2019-01-11 08:12:19 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-04-25 17:42:19 +08:00
|
|
|
User.BindValueChanged(user => updateDisplay(user.NewValue));
|
2019-01-11 08:12:19 +08:00
|
|
|
}
|
|
|
|
|
2021-11-04 17:02:44 +08:00
|
|
|
private void updateDisplay(APIUser user)
|
2019-01-11 08:12:19 +08:00
|
|
|
{
|
2020-02-03 00:21:22 +08:00
|
|
|
topLinkContainer.Clear();
|
|
|
|
bottomLinkContainer.Clear();
|
2019-01-11 08:12:19 +08:00
|
|
|
|
|
|
|
if (user == null) return;
|
|
|
|
|
|
|
|
if (user.JoinDate.ToUniversalTime().Year < 2008)
|
2022-01-28 12:53:48 +08:00
|
|
|
topLinkContainer.AddText(UsersStrings.ShowFirstMembers);
|
2019-01-11 08:12:19 +08:00
|
|
|
else
|
|
|
|
{
|
2020-02-03 00:21:22 +08:00
|
|
|
topLinkContainer.AddText("Joined ");
|
2020-02-03 00:22:48 +08:00
|
|
|
topLinkContainer.AddText(new DrawableDate(user.JoinDate, italic: false), embolden);
|
2019-01-11 08:12:19 +08:00
|
|
|
}
|
|
|
|
|
2020-02-03 00:21:22 +08:00
|
|
|
addSpacer(topLinkContainer);
|
2019-01-11 08:12:19 +08:00
|
|
|
|
2019-06-19 00:13:21 +08:00
|
|
|
if (user.IsOnline)
|
|
|
|
{
|
2022-01-28 12:53:48 +08:00
|
|
|
topLinkContainer.AddText(UsersStrings.ShowLastvisitOnline);
|
2020-02-03 00:21:22 +08:00
|
|
|
addSpacer(topLinkContainer);
|
2019-06-19 00:13:21 +08:00
|
|
|
}
|
2019-06-19 02:04:36 +08:00
|
|
|
else if (user.LastVisit.HasValue)
|
2019-01-11 08:12:19 +08:00
|
|
|
{
|
2020-02-03 00:21:22 +08:00
|
|
|
topLinkContainer.AddText("Last seen ");
|
2020-02-03 00:22:48 +08:00
|
|
|
topLinkContainer.AddText(new DrawableDate(user.LastVisit.Value, italic: false), embolden);
|
2019-01-11 08:12:19 +08:00
|
|
|
|
2020-02-03 00:21:22 +08:00
|
|
|
addSpacer(topLinkContainer);
|
2019-01-11 08:12:19 +08:00
|
|
|
}
|
|
|
|
|
2019-05-13 00:04:11 +08:00
|
|
|
if (user.PlayStyles?.Length > 0)
|
2019-01-11 08:12:19 +08:00
|
|
|
{
|
2020-02-03 00:21:22 +08:00
|
|
|
topLinkContainer.AddText("Plays with ");
|
2022-01-28 12:53:48 +08:00
|
|
|
|
|
|
|
LocalisableString playStylesString = user.PlayStyles[0].GetLocalisableDescription();
|
|
|
|
|
|
|
|
for (int i = 1; i < user.PlayStyles.Length; i++)
|
|
|
|
{
|
|
|
|
playStylesString = new TranslatableString(@"_", @"{0}{1}", playStylesString, CommonStrings.ArrayAndWordsConnector);
|
|
|
|
playStylesString = new TranslatableString(@"_", @"{0}{1}", playStylesString, user.PlayStyles[i].GetLocalisableDescription());
|
|
|
|
}
|
|
|
|
|
|
|
|
topLinkContainer.AddText(playStylesString, embolden);
|
2019-01-11 08:12:19 +08:00
|
|
|
|
2020-02-03 00:21:22 +08:00
|
|
|
addSpacer(topLinkContainer);
|
2019-01-11 08:12:19 +08:00
|
|
|
}
|
|
|
|
|
2020-02-03 00:21:22 +08:00
|
|
|
topLinkContainer.AddText("Contributed ");
|
2021-03-22 02:19:07 +08:00
|
|
|
topLinkContainer.AddLink("forum post".ToQuantity(user.PostCount, "#,##0"), $"{api.WebsiteRootUrl}/users/{user.Id}/posts", creationParameters: embolden);
|
2019-01-11 08:12:19 +08:00
|
|
|
|
2021-03-22 02:16:59 +08:00
|
|
|
addSpacer(topLinkContainer);
|
|
|
|
|
|
|
|
topLinkContainer.AddText("Posted ");
|
|
|
|
topLinkContainer.AddLink("comment".ToQuantity(user.CommentsCount, "#,##0"), $"{api.WebsiteRootUrl}/comments?user_id={user.Id}", creationParameters: embolden);
|
|
|
|
|
2020-01-31 00:46:59 +08:00
|
|
|
string websiteWithoutProtocol = user.Website;
|
2019-05-07 12:23:09 +08:00
|
|
|
|
2020-01-31 00:46:59 +08:00
|
|
|
if (!string.IsNullOrEmpty(websiteWithoutProtocol))
|
2019-01-11 08:12:19 +08:00
|
|
|
{
|
2020-01-31 00:46:59 +08:00
|
|
|
if (Uri.TryCreate(websiteWithoutProtocol, UriKind.Absolute, out var uri))
|
2019-04-25 17:42:19 +08:00
|
|
|
{
|
2020-01-31 00:46:59 +08:00
|
|
|
websiteWithoutProtocol = uri.Host + uri.PathAndQuery + uri.Fragment;
|
|
|
|
websiteWithoutProtocol = websiteWithoutProtocol.TrimEnd('/');
|
2019-04-25 17:42:19 +08:00
|
|
|
}
|
2019-01-11 08:12:19 +08:00
|
|
|
}
|
|
|
|
|
2020-02-03 00:21:22 +08:00
|
|
|
bool anyInfoAdded = false;
|
2020-02-02 22:07:39 +08:00
|
|
|
|
2020-02-03 00:21:22 +08:00
|
|
|
anyInfoAdded |= tryAddInfo(FontAwesome.Solid.MapMarker, user.Location);
|
|
|
|
anyInfoAdded |= tryAddInfo(OsuIcon.Heart, user.Interests);
|
|
|
|
anyInfoAdded |= tryAddInfo(FontAwesome.Solid.Suitcase, user.Occupation);
|
2020-02-03 00:39:58 +08:00
|
|
|
|
|
|
|
if (anyInfoAdded)
|
|
|
|
bottomLinkContainer.NewLine();
|
|
|
|
|
2019-01-11 08:12:19 +08:00
|
|
|
if (!string.IsNullOrEmpty(user.Twitter))
|
2020-02-03 00:21:22 +08:00
|
|
|
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Twitter, "@" + user.Twitter, $@"https://twitter.com/{user.Twitter}");
|
|
|
|
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Discord, user.Discord);
|
|
|
|
anyInfoAdded |= tryAddInfo(FontAwesome.Solid.Link, websiteWithoutProtocol, user.Website);
|
|
|
|
|
|
|
|
// If no information was added to the bottomLinkContainer, hide it to avoid unwanted padding
|
2020-02-03 00:41:42 +08:00
|
|
|
bottomLinkContainer.Alpha = anyInfoAdded ? 1 : 0;
|
2019-01-11 08:12:19 +08:00
|
|
|
}
|
2019-04-25 17:42:19 +08:00
|
|
|
|
|
|
|
private void addSpacer(OsuTextFlowContainer textFlow) => textFlow.AddArbitraryDrawable(new Container { Width = 15 });
|
|
|
|
|
2020-02-03 00:21:22 +08:00
|
|
|
private bool tryAddInfo(IconUsage icon, string content, string link = null)
|
2019-04-25 17:42:19 +08:00
|
|
|
{
|
2020-02-03 00:21:22 +08:00
|
|
|
if (string.IsNullOrEmpty(content)) return false;
|
2020-02-02 22:07:39 +08:00
|
|
|
|
2019-08-15 13:38:49 +08:00
|
|
|
// newlines could be contained in API returned user content.
|
2020-10-16 17:52:29 +08:00
|
|
|
content = content.Replace('\n', ' ');
|
2019-08-15 13:38:49 +08:00
|
|
|
|
2020-02-03 00:21:22 +08:00
|
|
|
bottomLinkContainer.AddIcon(icon, text =>
|
2019-04-25 17:42:19 +08:00
|
|
|
{
|
|
|
|
text.Font = text.Font.With(size: 10);
|
|
|
|
text.Colour = iconColour;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (link != null)
|
2020-02-03 00:21:22 +08:00
|
|
|
bottomLinkContainer.AddLink(" " + content, link, creationParameters: embolden);
|
2019-04-25 17:42:19 +08:00
|
|
|
else
|
2020-02-03 00:21:22 +08:00
|
|
|
bottomLinkContainer.AddText(" " + content, embolden);
|
2019-04-25 17:42:19 +08:00
|
|
|
|
2020-02-03 00:21:22 +08:00
|
|
|
addSpacer(bottomLinkContainer);
|
|
|
|
return true;
|
2019-04-25 17:42:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private void embolden(SpriteText text) => text.Font = text.Font.With(weight: FontWeight.Bold);
|
2019-01-11 08:12:19 +08:00
|
|
|
}
|
|
|
|
}
|