diff --git a/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs b/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs
index 1b7a2160d0..d098ea8b16 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs
@@ -26,7 +26,6 @@ namespace osu.Game.Tests.Visual.Online
typeof(HistoricalSection),
typeof(PaginatedMostPlayedBeatmapContainer),
typeof(DrawableMostPlayedBeatmap),
- typeof(DrawableProfileRow)
};
[Cached]
diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs
index f022425bf6..06091f3c81 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
+using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -12,6 +13,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Overlays;
using osu.Game.Overlays.Profile.Sections;
using osu.Game.Overlays.Profile.Sections.Recent;
@@ -28,6 +30,9 @@ namespace osu.Game.Tests.Visual.Online
typeof(MedalIcon)
};
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
+
public TestSceneUserProfileRecentSection()
{
Children = new Drawable[]
@@ -131,6 +136,22 @@ namespace osu.Game.Tests.Visual.Online
Beatmap = dummyBeatmap,
},
new APIRecentActivity
+ {
+ User = dummyUser,
+ Type = RecentActivityType.Rank,
+ Rank = 1,
+ Mode = "vitaru",
+ Beatmap = dummyBeatmap,
+ },
+ new APIRecentActivity
+ {
+ User = dummyUser,
+ Type = RecentActivityType.Rank,
+ Rank = 1,
+ Mode = "fruits",
+ Beatmap = dummyBeatmap,
+ },
+ new APIRecentActivity
{
User = dummyUser,
Type = RecentActivityType.RankLost,
diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs
index 13b547eed3..67a976fe6f 100644
--- a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs
@@ -10,7 +10,7 @@ using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays.Profile.Sections
{
///
- /// Display artist/title/mapper information, commonly used as the left portion of a profile or score display row (see ).
+ /// Display artist/title/mapper information, commonly used as the left portion of a profile or score display row.
///
public abstract class BeatmapMetadataContainer : OsuHoverContainer
{
diff --git a/osu.Game/Overlays/Profile/Sections/DrawableProfileRow.cs b/osu.Game/Overlays/Profile/Sections/DrawableProfileRow.cs
deleted file mode 100644
index 03ee29d0c2..0000000000
--- a/osu.Game/Overlays/Profile/Sections/DrawableProfileRow.cs
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using osu.Framework.Allocation;
-using osu.Framework.Extensions.Color4Extensions;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Effects;
-using osu.Framework.Graphics.Shapes;
-using osu.Framework.Input.Events;
-using osu.Game.Graphics;
-using osuTK;
-using osuTK.Graphics;
-
-namespace osu.Game.Overlays.Profile.Sections
-{
- public abstract class DrawableProfileRow : Container
- {
- private const int fade_duration = 200;
-
- private Box underscoreLine;
- private Box coloredBackground;
- private Container background;
-
- ///
- /// A visual element displayed to the left of content.
- ///
- protected abstract Drawable CreateLeftVisual();
-
- protected FillFlowContainer LeftFlowContainer { get; private set; }
- protected FillFlowContainer RightFlowContainer { get; private set; }
-
- protected override Container Content { get; }
-
- protected DrawableProfileRow()
- {
- RelativeSizeAxes = Axes.X;
- Height = 60;
-
- Content = new Container
- {
- RelativeSizeAxes = Axes.Both,
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- Width = 0.97f,
- };
- }
-
- [BackgroundDependencyLoader(true)]
- private void load(OsuColour colour)
- {
- InternalChildren = new Drawable[]
- {
- background = new Container
- {
- RelativeSizeAxes = Axes.Both,
- Masking = true,
- CornerRadius = 3,
- Alpha = 0,
- EdgeEffect = new EdgeEffectParameters
- {
- Type = EdgeEffectType.Shadow,
- Offset = new Vector2(0f, 1f),
- Radius = 1f,
- Colour = Color4.Black.Opacity(0.2f),
- },
- Child = coloredBackground = new Box { RelativeSizeAxes = Axes.Both }
- },
- Content,
- underscoreLine = new Box
- {
- Anchor = Anchor.BottomCentre,
- Origin = Anchor.BottomCentre,
- RelativeSizeAxes = Axes.X,
- Height = 1,
- },
- new FillFlowContainer
- {
- RelativeSizeAxes = Axes.Both,
- Direction = FillDirection.Horizontal,
- Children = new[]
- {
- CreateLeftVisual(),
- LeftFlowContainer = new FillFlowContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Anchor = Anchor.CentreLeft,
- Origin = Anchor.CentreLeft,
- Margin = new MarginPadding { Left = 10 },
- Direction = FillDirection.Vertical,
- },
- }
- },
- RightFlowContainer = new FillFlowContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Anchor = Anchor.CentreRight,
- Origin = Anchor.CentreRight,
- Direction = FillDirection.Vertical,
- },
- };
-
- coloredBackground.Colour = underscoreLine.Colour = colour.Gray4;
- }
-
- protected override bool OnClick(ClickEvent e) => true;
-
- protected override bool OnHover(HoverEvent e)
- {
- background.FadeIn(fade_duration, Easing.OutQuint);
- underscoreLine.FadeOut(fade_duration, Easing.OutQuint);
- return true;
- }
-
- protected override void OnHoverLost(HoverLostEvent e)
- {
- background.FadeOut(fade_duration, Easing.OutQuint);
- underscoreLine.FadeIn(fade_duration, Easing.OutQuint);
- base.OnHoverLost(e);
- }
- }
-}
diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs
index 4e856845ac..8782e82642 100644
--- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs
+++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs
@@ -1,9 +1,11 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API;
@@ -11,12 +13,19 @@ using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Chat;
using osu.Game.Online.Leaderboards;
+using osu.Game.Rulesets;
namespace osu.Game.Overlays.Profile.Sections.Recent
{
- public class DrawableRecentActivity : DrawableProfileRow
+ public class DrawableRecentActivity : CompositeDrawable
{
- private IAPIProvider api;
+ private const int font_size = 14;
+
+ [Resolved]
+ private IAPIProvider api { get; set; }
+
+ [Resolved]
+ private RulesetStore rulesets { get; set; }
private readonly APIRecentActivity activity;
@@ -28,139 +37,191 @@ namespace osu.Game.Overlays.Profile.Sections.Recent
}
[BackgroundDependencyLoader]
- private void load(IAPIProvider api)
+ private void load(OverlayColourProvider colourProvider)
{
- this.api = api;
-
- LeftFlowContainer.Padding = new MarginPadding { Left = 10, Right = 160 };
-
- LeftFlowContainer.Add(content = new LinkFlowContainer
+ RelativeSizeAxes = Axes.X;
+ AutoSizeAxes = Axes.Y;
+ AddInternal(new GridContainer
{
- AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ ColumnDimensions = new[]
+ {
+ new Dimension(GridSizeMode.Absolute, size: 28),
+ new Dimension(),
+ new Dimension(GridSizeMode.AutoSize)
+ },
+ RowDimensions = new[]
+ {
+ new Dimension(GridSizeMode.AutoSize)
+ },
+ Content = new[]
+ {
+ new Drawable[]
+ {
+ new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Child = createIcon().With(icon =>
+ {
+ icon.Anchor = Anchor.Centre;
+ icon.Origin = Anchor.Centre;
+ })
+ },
+ content = new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: font_size))
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ AutoSizeAxes = Axes.Y,
+ RelativeSizeAxes = Axes.X,
+ },
+ new DrawableDate(activity.CreatedAt)
+ {
+ Anchor = Anchor.CentreRight,
+ Origin = Anchor.CentreRight,
+ Colour = colourProvider.Foreground1,
+ Font = OsuFont.GetFont(size: font_size),
+ }
+ }
+ }
});
- RightFlowContainer.Add(new DrawableDate(activity.CreatedAt)
- {
- Font = OsuFont.GetFont(size: 13),
- Colour = OsuColour.Gray(0xAA),
- Anchor = Anchor.TopRight,
- Origin = Anchor.TopRight,
- });
-
- var formatted = createMessage();
-
- content.AddLinks(formatted.Text, formatted.Links);
+ createMessage();
}
- protected override Drawable CreateLeftVisual()
+ private Drawable createIcon()
{
switch (activity.Type)
{
case RecentActivityType.Rank:
return new UpdateableRank(activity.ScoreRank)
{
- RelativeSizeAxes = Axes.Y,
- Width = 60,
+ RelativeSizeAxes = Axes.X,
+ Height = 11,
FillMode = FillMode.Fit,
+ Margin = new MarginPadding { Top = 2 }
};
case RecentActivityType.Achievement:
return new DelayedLoadWrapper(new MedalIcon(activity.Achievement.Slug)
{
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
FillMode = FillMode.Fit,
})
{
- RelativeSizeAxes = Axes.Y,
- Width = 60,
+ RelativeSizeAxes = Axes.X,
+ Width = 0.5f,
+ Height = 18
};
default:
- return new Container
- {
- RelativeSizeAxes = Axes.Y,
- Width = 60,
- FillMode = FillMode.Fit,
- };
+ return Empty();
}
}
- private string toAbsoluteUrl(string url) => $"{api.Endpoint}{url}";
-
- private MessageFormatter.MessageFormatterResult createMessage()
+ private void createMessage()
{
- string userLinkTemplate() => $"[{toAbsoluteUrl(activity.User?.Url)} {activity.User?.Username}]";
- string beatmapLinkTemplate() => $"[{toAbsoluteUrl(activity.Beatmap?.Url)} {activity.Beatmap?.Title}]";
- string beatmapsetLinkTemplate() => $"[{toAbsoluteUrl(activity.Beatmapset?.Url)} {activity.Beatmapset?.Title}]";
-
- string message;
-
switch (activity.Type)
{
case RecentActivityType.Achievement:
- message = $"{userLinkTemplate()} unlocked the {activity.Achievement.Name} medal!";
+ addUserLink();
+ addText($" unlocked the \"{activity.Achievement.Name}\" medal!");
break;
case RecentActivityType.BeatmapPlaycount:
- message = $"{beatmapLinkTemplate()} has been played {activity.Count} times!";
+ addBeatmapLink();
+ addText($" has been played {activity.Count} times!");
break;
case RecentActivityType.BeatmapsetApprove:
- message = $"{beatmapsetLinkTemplate()} has been {activity.Approval.ToString().ToLowerInvariant()}!";
+ addBeatmapsetLink();
+ addText($" has been {activity.Approval.ToString().ToLowerInvariant()}!");
break;
case RecentActivityType.BeatmapsetDelete:
- message = $"{beatmapsetLinkTemplate()} has been deleted.";
+ addBeatmapsetLink();
+ addText(" has been deleted.");
break;
case RecentActivityType.BeatmapsetRevive:
- message = $"{beatmapsetLinkTemplate()} has been revived from eternal slumber by {userLinkTemplate()}.";
+ addBeatmapsetLink();
+ addText(" has been revived from eternal slumber by ");
+ addUserLink();
break;
case RecentActivityType.BeatmapsetUpdate:
- message = $"{userLinkTemplate()} has updated the beatmap {beatmapsetLinkTemplate()}!";
+ addUserLink();
+ addText(" has updated the beatmap ");
+ addBeatmapsetLink();
break;
case RecentActivityType.BeatmapsetUpload:
- message = $"{userLinkTemplate()} has submitted a new beatmap {beatmapsetLinkTemplate()}!";
+ addUserLink();
+ addText(" has submitted a new beatmap ");
+ addBeatmapsetLink();
break;
case RecentActivityType.Medal:
// apparently this shouldn't exist look at achievement instead (https://github.com/ppy/osu-web/blob/master/resources/assets/coffee/react/profile-page/recent-activity.coffee#L111)
- message = string.Empty;
break;
case RecentActivityType.Rank:
- message = $"{userLinkTemplate()} achieved rank #{activity.Rank} on {beatmapLinkTemplate()} ({activity.Mode}!)";
+ addUserLink();
+ addText($" achieved rank #{activity.Rank} on ");
+ addBeatmapLink();
+ addText($" ({getRulesetName()})");
break;
case RecentActivityType.RankLost:
- message = $"{userLinkTemplate()} has lost first place on {beatmapLinkTemplate()} ({activity.Mode}!)";
+ addUserLink();
+ addText(" has lost first place on ");
+ addBeatmapLink();
+ addText($" ({getRulesetName()})");
break;
case RecentActivityType.UserSupportAgain:
- message = $"{userLinkTemplate()} has once again chosen to support osu! - thanks for your generosity!";
+ addUserLink();
+ addText(" has once again chosen to support osu! - thanks for your generosity!");
break;
case RecentActivityType.UserSupportFirst:
- message = $"{userLinkTemplate()} has become an osu!supporter - thanks for your generosity!";
+ addUserLink();
+ addText(" has become an osu!supporter - thanks for your generosity!");
break;
case RecentActivityType.UserSupportGift:
- message = $"{userLinkTemplate()} has received the gift of osu!supporter!";
+ addUserLink();
+ addText(" has received the gift of osu!supporter!");
break;
case RecentActivityType.UsernameChange:
- message = $"{activity.User?.PreviousUsername} has changed their username to {userLinkTemplate()}!";
- break;
-
- default:
- message = string.Empty;
+ addText($"{activity.User?.PreviousUsername} has changed their username to ");
+ addUserLink();
break;
}
-
- return MessageFormatter.FormatText(message);
}
+
+ private string getRulesetName() =>
+ rulesets.AvailableRulesets.FirstOrDefault(r => r.ShortName == activity.Mode)?.Name ?? activity.Mode;
+
+ private void addUserLink()
+ => content.AddLink(activity.User?.Username, LinkAction.OpenUserProfile, getLinkArgument(activity.User?.Url), creationParameters: t => t.Font = getLinkFont(FontWeight.Bold));
+
+ private void addBeatmapLink()
+ => content.AddLink(activity.Beatmap?.Title, LinkAction.OpenBeatmap, getLinkArgument(activity.Beatmap?.Url), creationParameters: t => t.Font = getLinkFont());
+
+ private void addBeatmapsetLink()
+ => content.AddLink(activity.Beatmapset?.Title, LinkAction.OpenBeatmapSet, getLinkArgument(activity.Beatmapset?.Url), creationParameters: t => t.Font = getLinkFont());
+
+ private string getLinkArgument(string url) => MessageFormatter.GetLinkDetails($"{api.Endpoint}{url}").Argument;
+
+ private FontUsage getLinkFont(FontWeight fontWeight = FontWeight.Regular)
+ => OsuFont.GetFont(size: font_size, weight: fontWeight, italics: true);
+
+ private void addText(string text)
+ => content.AddText(text, t => t.Font = OsuFont.GetFont(size: font_size, weight: FontWeight.SemiBold));
}
}
diff --git a/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs
index 4563510046..0c1f8b2e92 100644
--- a/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs
+++ b/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs
@@ -23,8 +23,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent
Child = sprite = new Sprite
{
- Height = 40,
- Width = 40,
+ RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
};
diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs
index 3f9d4dc93e..a37f398272 100644
--- a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs
@@ -8,6 +8,7 @@ using osu.Framework.Bindables;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.API;
using System.Collections.Generic;
+using osuTK;
namespace osu.Game.Overlays.Profile.Sections.Recent
{
@@ -16,7 +17,8 @@ namespace osu.Game.Overlays.Profile.Sections.Recent
public PaginatedRecentActivityContainer(Bindable user, string header, string missing)
: base(user, header, missing)
{
- ItemsPerPage = 5;
+ ItemsPerPage = 10;
+ ItemsContainer.Spacing = new Vector2(0, 8);
}
protected override APIRequest> CreateRequest() =>