From e3a1b07172ec3253b1de7af5e450bcdfc48976c2 Mon Sep 17 00:00:00 2001 From: naoey Date: Sun, 25 Feb 2018 19:18:39 +0530 Subject: [PATCH 01/14] Create API request and reponse model. --- .../GetUserRecentActivitiesRequest.cs | 89 +++++++++++++++++++ .../PaginatedRecentActivityContainer.cs | 63 +++++++++++++ .../Profile/Sections/RecentSection.cs | 10 ++- osu.Game/Overlays/UserProfileOverlay.cs | 2 +- osu.Game/osu.Game.csproj | 4 +- 5 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs create mode 100644 osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs diff --git a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs new file mode 100644 index 0000000000..cb7d0323f4 --- /dev/null +++ b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs @@ -0,0 +1,89 @@ +using Newtonsoft.Json; +using osu.Game.Rulesets.Scoring; +using Humanizer; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using osu.Game.Rulesets; +using osu.Game.Overlays.Profile.Sections.Recent; + +namespace osu.Game.Online.API.Requests +{ + public class GetUserRecentActivitiesRequest : APIRequest> + { + } + + public class RecentActivity + { + [JsonProperty("id")] + public int ID; + + [JsonProperty("created_at")] + public DateTimeOffset CreatedAt; + + [JsonProperty] + private string type + { + set => Type = (RecentActivityType)Enum.Parse(typeof(RecentActivityType), value.Pascalize()); + } + + public RecentActivityType Type; + + [JsonProperty] + private string scoreRank + { + set => ScoreRank = (ScoreRank)Enum.Parse(typeof(ScoreRank), value); + } + + public ScoreRank ScoreRank; + + [JsonProperty("rank")] + public int Rank; + + [JsonProperty("mode")] + public string Mode; + + [JsonProperty("beatmap")] + public RecentActivityBeatmap Beatmap; + + [JsonProperty("user")] + public RecentActivityUser User; + + public class RecentActivityBeatmap + { + [JsonProperty("title")] + public string Title; + + [JsonProperty("url")] + public string Url; + } + + public class RecentActivityUser + { + [JsonProperty("username")] + public string Username; + + [JsonProperty("url")] + public string Url; + } + } + + public enum RecentActivityType + { + Achievement, + BeatmapPlaycount, + BeatmapsetApprove, + BeatmapsetDelete, + BeatmapsetRevive, + BeatmapsetUpdate, + Medal, + Rank, + RankLost, + UserSupportAgain, + UserSupportFirst, + UserSupportGift, + UsernameChange, + } +} diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs new file mode 100644 index 0000000000..11b48ad68e --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs @@ -0,0 +1,63 @@ +using osu.Framework.Configuration; +using osu.Game.Online.API.Requests; +using osu.Game.Users; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace osu.Game.Overlays.Profile.Sections +{ + class PaginatedRecentActivityContainer : PaginatedContainer + { + public PaginatedRecentActivityContainer(Bindable user, string header, string missing) + : base(user, header, missing) + { + ItemsPerPage = 5; + } + + //protected override void ShowMore() + //{ + // base.ShowMore(); + + // var req = new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++ * ItemsPerPage); + + // req.Success += scores => + // { + // foreach (var s in scores) + // s.ApplyRuleset(Rulesets.GetRuleset(s.OnlineRulesetID)); + + // ShowMoreButton.FadeTo(scores.Count == ItemsPerPage ? 1 : 0); + // ShowMoreLoading.Hide(); + + // if (!scores.Any() && VisiblePages == 1) + // { + // MissingText.Show(); + // return; + // } + + // MissingText.Hide(); + + // foreach (OnlineScore score in scores) + // { + // DrawableProfileScore drawableScore; + + // switch (type) + // { + // default: + // drawableScore = new DrawablePerformanceScore(score, includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null); + // break; + // case ScoreType.Recent: + // drawableScore = new DrawableTotalScore(score); + // break; + // } + + // ItemsContainer.Add(drawableScore); + // } + // }; + + // Api.Queue(req); + //} + } +} diff --git a/osu.Game/Overlays/Profile/Sections/RecentSection.cs b/osu.Game/Overlays/Profile/Sections/RecentSection.cs index 78b139efe8..757e2457d2 100644 --- a/osu.Game/Overlays/Profile/Sections/RecentSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RecentSection.cs @@ -7,6 +7,14 @@ namespace osu.Game.Overlays.Profile.Sections { public override string Title => "Recent"; - public override string Identifier => "recent_activities"; + public override string Identifier => "recent_activity"; + + public RecentSection() + { + Children = new[] + { + new PaginatedRecentActivityContainer(User, @"Recent", @"This user hasn't done anything notable recently!"), + }; + } } } diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 59f940a19d..3bc12ccb24 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -82,7 +82,7 @@ namespace osu.Game.Overlays sections = new ProfileSection[] { //new AboutSection(), - //new RecentSection(), + new RecentSection(), new RanksSection(), //new MedalsSection(), new HistoricalSection(), diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 6a06bf540b..ad9105f1e8 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -293,12 +293,14 @@ + 20180125143340_Settings.cs + @@ -936,4 +938,4 @@ - + \ No newline at end of file From 7e4bd363916f6c85b18b94807c3b83981c7f323f Mon Sep 17 00:00:00 2001 From: naoey Date: Sun, 25 Feb 2018 22:41:47 +0530 Subject: [PATCH 02/14] Create drawable and add response to profile. - Add missing JSON fields to response model - Add missing enum value --- .../GetUserRecentActivitiesRequest.cs | 21 +++- .../Sections/Recent/DrawableRecentActivity.cs | 117 ++++++++++++++++++ .../PaginatedRecentActivityContainer.cs | 59 ++++----- osu.Game/osu.Game.csproj | 1 + 4 files changed, 161 insertions(+), 37 deletions(-) create mode 100644 osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs diff --git a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs index cb7d0323f4..14997b070b 100644 --- a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs @@ -7,12 +7,21 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using osu.Game.Rulesets; -using osu.Game.Overlays.Profile.Sections.Recent; namespace osu.Game.Online.API.Requests { public class GetUserRecentActivitiesRequest : APIRequest> { + private readonly long userId; + private readonly int offset; + + public GetUserRecentActivitiesRequest(long userId, int offset = 0) + { + this.userId = userId; + this.offset = offset; + } + + protected override string Target => $"users/{userId}/recent_activity?offset={offset}"; } public class RecentActivity @@ -42,6 +51,9 @@ namespace osu.Game.Online.API.Requests [JsonProperty("rank")] public int Rank; + [JsonProperty("count")] + public int Count; + [JsonProperty("mode")] public string Mode; @@ -51,6 +63,9 @@ namespace osu.Game.Online.API.Requests [JsonProperty("user")] public RecentActivityUser User; + [JsonProperty("achivementName")] + public string AchivementName; + public class RecentActivityBeatmap { [JsonProperty("title")] @@ -67,6 +82,9 @@ namespace osu.Game.Online.API.Requests [JsonProperty("url")] public string Url; + + [JsonProperty("previousUsername")] + public string PreviousUsername; } } @@ -78,6 +96,7 @@ namespace osu.Game.Online.API.Requests BeatmapsetDelete, BeatmapsetRevive, BeatmapsetUpdate, + BeatmapsetUpload, Medal, Rank, RankLost, diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs new file mode 100644 index 0000000000..e0f7a97140 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests; +using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Users; + +namespace osu.Game.Overlays.Profile.Sections.Recent +{ + public class DrawableRecentActivity : DrawableProfileRow + { + private RecentActivity activity; + private User user; + + public DrawableRecentActivity(RecentActivity activity, User user) + { + this.activity = activity; + this.user = user; + } + + [BackgroundDependencyLoader] + private void load() + { + LeftFlowContainer.Add(new OsuSpriteText + { + Text = activityToString(), + }); + + RightFlowContainer.Add(new OsuSpriteText + { + Text = activity.CreatedAt.LocalDateTime.ToShortDateString(), + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Font = "Exo2.0-RegularItalic", + TextSize = 12, + Colour = OsuColour.Gray(0xAA), + }); + } + + protected override Drawable CreateLeftVisual() + { + switch (activity.Type) + { + case RecentActivityType.Rank: + return new DrawableRank(activity.ScoreRank) + { + RelativeSizeAxes = Axes.Y, + Width = 60, + FillMode = FillMode.Fit, + }; + + default: + return new Container + { + RelativeSizeAxes = Axes.Y, + Width = 60, + FillMode = FillMode.Fit, + }; + } + } + + private string activityToString() + { + switch (activity.Type) + { + case RecentActivityType.Achievement: + return $"{activity.User.Username} unlocked the {activity.AchivementName} achievement!"; + + case RecentActivityType.BeatmapPlaycount: + return $"{activity.Beatmap.Title} has been played {activity.Count} times!"; + + case RecentActivityType.BeatmapsetDelete: + return $"{activity.Beatmap.Title} has been deleted."; + + case RecentActivityType.BeatmapsetRevive: + return $"{activity.Beatmap.Title} has been revived from eternal slumber by ${activity.User.Username}"; + + case RecentActivityType.BeatmapsetUpdate: + return $"{activity.User.Username} has updated the beatmap ${activity.Beatmap.Title}"; + + case RecentActivityType.BeatmapsetUpload: + return $"{activity.User.Username} has submitted a new beatmap ${activity.Beatmap.Title}"; + + case RecentActivityType.Medal: + return $"{activity.User.Username} has unlocked the {activity.AchivementName} medal!"; + + case RecentActivityType.Rank: + return $"{activity.User.Username} achieved rank #{activity.Rank} on {activity.Beatmap?.Title}"; + + case RecentActivityType.RankLost: + return $"{activity.User.Username} has lost first place on {activity.Beatmap.Title}!"; + + case RecentActivityType.UserSupportAgain: + return $"{activity.User.Username} has once again chosen to support osu! - thanks for your generosity!"; + + case RecentActivityType.UserSupportFirst: + return $"{activity.User.Username} has become an osu! supporter - thanks for your generosity!"; + + case RecentActivityType.UsernameChange: + return $"{activity.User.PreviousUsername} has changed their username to {activity.User.Username}"; + + case RecentActivityType.UserSupportGift: + return $"{activity.User.Username} has received the gift of osu! supporter!"; + + default: + return string.Empty; + } + } + } +} diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs index 11b48ad68e..307c06b744 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs @@ -1,5 +1,7 @@ using osu.Framework.Configuration; +using osu.Framework.Graphics; using osu.Game.Online.API.Requests; +using osu.Game.Overlays.Profile.Sections.Recent; using osu.Game.Users; using System; using System.Collections.Generic; @@ -17,47 +19,32 @@ namespace osu.Game.Overlays.Profile.Sections ItemsPerPage = 5; } - //protected override void ShowMore() - //{ - // base.ShowMore(); + protected override void ShowMore() + { + base.ShowMore(); - // var req = new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++ * ItemsPerPage); + var req = new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++ * ItemsPerPage); - // req.Success += scores => - // { - // foreach (var s in scores) - // s.ApplyRuleset(Rulesets.GetRuleset(s.OnlineRulesetID)); + req.Success += activities => + { + ShowMoreButton.FadeTo(activities.Count == ItemsPerPage ? 1 : 0); + ShowMoreLoading.Hide(); - // ShowMoreButton.FadeTo(scores.Count == ItemsPerPage ? 1 : 0); - // ShowMoreLoading.Hide(); + if (!activities.Any() && VisiblePages == 1) + { + MissingText.Show(); + return; + } - // if (!scores.Any() && VisiblePages == 1) - // { - // MissingText.Show(); - // return; - // } + MissingText.Hide(); - // MissingText.Hide(); + foreach (RecentActivity activity in activities) + { + ItemsContainer.Add(new DrawableRecentActivity(activity, User)); + } + }; - // foreach (OnlineScore score in scores) - // { - // DrawableProfileScore drawableScore; - - // switch (type) - // { - // default: - // drawableScore = new DrawablePerformanceScore(score, includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null); - // break; - // case ScoreType.Recent: - // drawableScore = new DrawableTotalScore(score); - // break; - // } - - // ItemsContainer.Add(drawableScore); - // } - // }; - - // Api.Queue(req); - //} + Api.Queue(req); + } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ad9105f1e8..cd40b42365 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -300,6 +300,7 @@ 20180125143340_Settings.cs + From bb40919f9ce2e8948ac73548cd075ac3024ce1d3 Mon Sep 17 00:00:00 2001 From: naoey Date: Mon, 26 Feb 2018 00:36:55 +0530 Subject: [PATCH 03/14] Add link handling to recent activities. - Add a show user action to link handling --- .../Graphics/Containers/LinkFlowContainer.cs | 7 ++- osu.Game/Online/Chat/MessageFormatter.cs | 15 ++++++ .../Sections/Recent/DrawableRecentActivity.cs | 54 +++++++++++++------ osu.Game/Overlays/UserProfileOverlay.cs | 5 ++ 4 files changed, 64 insertions(+), 17 deletions(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index 9f1b44af44..8edae7a976 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -23,14 +23,16 @@ namespace osu.Game.Graphics.Containers public override bool HandleMouseInput => true; private OsuGame game; + private UserProfileOverlay userProfile; private Action showNotImplementedError; [BackgroundDependencyLoader(true)] - private void load(OsuGame game, NotificationOverlay notifications) + private void load(OsuGame game, NotificationOverlay notifications, UserProfileOverlay userProfile) { // will be null in tests this.game = game; + this.userProfile = userProfile; showNotImplementedError = () => notifications?.Post(new SimpleNotification { @@ -90,6 +92,9 @@ namespace osu.Game.Graphics.Containers case LinkAction.External: Process.Start(url); break; + case LinkAction.OpenUserProfile: + userProfile?.ShowUser(Convert.ToInt64(linkArgument)); + break; default: throw new NotImplementedException($"This {nameof(LinkAction)} ({linkType.ToString()}) is missing an associated action."); } diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs index 906f42d50e..3fdce3ec12 100644 --- a/osu.Game/Online/Chat/MessageFormatter.cs +++ b/osu.Game/Online/Chat/MessageFormatter.cs @@ -118,6 +118,8 @@ namespace osu.Game.Online.Chat case "beatmapsets": case "d": return new LinkDetails(LinkAction.OpenBeatmapSet, args[3]); + case "u": + return new LinkDetails(LinkAction.OpenUserProfile, args[3]); } } @@ -146,6 +148,9 @@ namespace osu.Game.Online.Chat case "spectate": linkType = LinkAction.Spectate; break; + case "u": + linkType = LinkAction.OpenUserProfile; + break; default: linkType = LinkAction.External; break; @@ -205,6 +210,15 @@ namespace osu.Game.Online.Chat return inputMessage; } + public static List GetLinks(string text) + { + var result = format(text); + + result.Links.Sort(); + + return result.Links; + } + public class MessageFormatterResult { public List Links = new List(); @@ -239,6 +253,7 @@ namespace osu.Game.Online.Chat OpenEditorTimestamp, JoinMultiplayerMatch, Spectate, + OpenUserProfile, } public class Link : IComparable diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index e0f7a97140..6abf68e3e9 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -7,10 +7,14 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Online.API; using osu.Game.Online.API.Requests; +using osu.Game.Online.Chat; using osu.Game.Screens.Select.Leaderboards; using osu.Game.Users; +using static osu.Game.Online.API.Requests.RecentActivity; namespace osu.Game.Overlays.Profile.Sections.Recent { @@ -18,19 +22,31 @@ namespace osu.Game.Overlays.Profile.Sections.Recent { private RecentActivity activity; private User user; + private APIAccess api; + + private string userLinkTemplate; + private string beatmapLinkTemplate; + + private LinkFlowContainer content; public DrawableRecentActivity(RecentActivity activity, User user) { this.activity = activity; this.user = user; + + userLinkTemplate = $"[{activity.User?.Username}]({urlToAbsolute(activity.User?.Url)})"; + beatmapLinkTemplate = $"[{activity.Beatmap?.Title}]({urlToAbsolute(activity.Beatmap?.Url)})"; } [BackgroundDependencyLoader] - private void load() + private void load(APIAccess api) { - LeftFlowContainer.Add(new OsuSpriteText + this.api = api; + + LeftFlowContainer.Add(content = new LinkFlowContainer { - Text = activityToString(), + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, }); RightFlowContainer.Add(new OsuSpriteText @@ -42,6 +58,10 @@ namespace osu.Game.Overlays.Profile.Sections.Recent TextSize = 12, Colour = OsuColour.Gray(0xAA), }); + + string text = activityToString(); + + content.AddLinks(text, MessageFormatter.GetLinks(text)); } protected override Drawable CreateLeftVisual() @@ -66,48 +86,50 @@ namespace osu.Game.Overlays.Profile.Sections.Recent } } + private string urlToAbsolute(string url) => $"{api?.Endpoint ?? @"https://osu.ppy.sh"}{url}"; + private string activityToString() { switch (activity.Type) { case RecentActivityType.Achievement: - return $"{activity.User.Username} unlocked the {activity.AchivementName} achievement!"; + return $"{userLinkTemplate} unlocked the {activity.AchivementName} achievement!"; case RecentActivityType.BeatmapPlaycount: - return $"{activity.Beatmap.Title} has been played {activity.Count} times!"; + return $"{beatmapLinkTemplate} has been played {activity.Count} times!"; case RecentActivityType.BeatmapsetDelete: - return $"{activity.Beatmap.Title} has been deleted."; + return $"{beatmapLinkTemplate} has been deleted."; case RecentActivityType.BeatmapsetRevive: - return $"{activity.Beatmap.Title} has been revived from eternal slumber by ${activity.User.Username}"; + return $"{beatmapLinkTemplate} has been revived from eternal slumber by ${userLinkTemplate}"; case RecentActivityType.BeatmapsetUpdate: - return $"{activity.User.Username} has updated the beatmap ${activity.Beatmap.Title}"; + return $"{userLinkTemplate} has updated the beatmap ${beatmapLinkTemplate}"; case RecentActivityType.BeatmapsetUpload: - return $"{activity.User.Username} has submitted a new beatmap ${activity.Beatmap.Title}"; + return $"{userLinkTemplate} has submitted a new beatmap ${beatmapLinkTemplate}"; case RecentActivityType.Medal: - return $"{activity.User.Username} has unlocked the {activity.AchivementName} medal!"; + return $"{userLinkTemplate} has unlocked the {activity.AchivementName} medal!"; case RecentActivityType.Rank: - return $"{activity.User.Username} achieved rank #{activity.Rank} on {activity.Beatmap?.Title}"; + return $"{userLinkTemplate} achieved rank #{activity.Rank} on {beatmapLinkTemplate}"; case RecentActivityType.RankLost: - return $"{activity.User.Username} has lost first place on {activity.Beatmap.Title}!"; + return $"{userLinkTemplate} has lost first place on {beatmapLinkTemplate}!"; case RecentActivityType.UserSupportAgain: - return $"{activity.User.Username} has once again chosen to support osu! - thanks for your generosity!"; + return $"{userLinkTemplate} has once again chosen to support osu! - thanks for your generosity!"; case RecentActivityType.UserSupportFirst: - return $"{activity.User.Username} has become an osu! supporter - thanks for your generosity!"; + return $"{userLinkTemplate} has become an osu! supporter - thanks for your generosity!"; case RecentActivityType.UsernameChange: - return $"{activity.User.PreviousUsername} has changed their username to {activity.User.Username}"; + return $"{activity.User.PreviousUsername} has changed their username to {userLinkTemplate}"; case RecentActivityType.UserSupportGift: - return $"{activity.User.Username} has received the gift of osu! supporter!"; + return $"{userLinkTemplate} has received the gift of osu! supporter!"; default: return string.Empty; diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 3bc12ccb24..39cb71ea27 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -73,6 +73,11 @@ namespace osu.Game.Overlays FadeEdgeEffectTo(0, DISAPPEAR_DURATION, Easing.Out); } + public void ShowUser(long userId) + { + ShowUser(new User { Id = userId }, true); + } + public void ShowUser(User user, bool fetchOnline = true) { userReq?.Cancel(); From 75fdca928e9d19ae12e2a8ce739cc9af42fda20b Mon Sep 17 00:00:00 2001 From: naoey Date: Mon, 26 Feb 2018 00:58:20 +0530 Subject: [PATCH 04/14] Handle links correctly and don't re-open profile if the user is same. --- osu.Game/Online/Chat/MessageFormatter.cs | 4 ++-- .../Profile/Sections/Recent/DrawableRecentActivity.cs | 8 ++++---- osu.Game/Overlays/UserProfileOverlay.cs | 3 +++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs index 3fdce3ec12..9966f78435 100644 --- a/osu.Game/Online/Chat/MessageFormatter.cs +++ b/osu.Game/Online/Chat/MessageFormatter.cs @@ -210,13 +210,13 @@ namespace osu.Game.Online.Chat return inputMessage; } - public static List GetLinks(string text) + public static MessageFormatterResult FormatText(string text) { var result = format(text); result.Links.Sort(); - return result.Links; + return result; } public class MessageFormatterResult diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index 6abf68e3e9..4d215467bb 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -34,8 +34,8 @@ namespace osu.Game.Overlays.Profile.Sections.Recent this.activity = activity; this.user = user; - userLinkTemplate = $"[{activity.User?.Username}]({urlToAbsolute(activity.User?.Url)})"; - beatmapLinkTemplate = $"[{activity.Beatmap?.Title}]({urlToAbsolute(activity.Beatmap?.Url)})"; + userLinkTemplate = $"[{urlToAbsolute(activity.User?.Url)} {activity.User?.Username}]"; + beatmapLinkTemplate = $"[{urlToAbsolute(activity.Beatmap?.Url)} {activity.Beatmap?.Title}]"; } [BackgroundDependencyLoader] @@ -59,9 +59,9 @@ namespace osu.Game.Overlays.Profile.Sections.Recent Colour = OsuColour.Gray(0xAA), }); - string text = activityToString(); + var formatted = MessageFormatter.FormatText(activityToString()); - content.AddLinks(text, MessageFormatter.GetLinks(text)); + content.AddLinks(formatted.Text, formatted.Links); } protected override Drawable CreateLeftVisual() diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 39cb71ea27..f19fc4062c 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -75,6 +75,9 @@ namespace osu.Game.Overlays public void ShowUser(long userId) { + if (userId == Header.User.Id) + return; + ShowUser(new User { Id = userId }, true); } From 1ad45b094178dc644ffcbc3ca808a2cb1c4ad0ac Mon Sep 17 00:00:00 2001 From: naoey Date: Mon, 26 Feb 2018 01:16:46 +0530 Subject: [PATCH 05/14] R# fixes. --- .../GetUserRecentActivitiesRequest.cs | 4 ---- .../Sections/Recent/DrawableRecentActivity.cs | 19 +++++-------------- .../PaginatedRecentActivityContainer.cs | 11 +++-------- .../Profile/Sections/RecentSection.cs | 2 ++ osu.Game/Overlays/UserProfileOverlay.cs | 2 +- 5 files changed, 11 insertions(+), 27 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs index 14997b070b..d52d0c884e 100644 --- a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs @@ -3,10 +3,6 @@ using osu.Game.Rulesets.Scoring; using Humanizer; using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using osu.Game.Rulesets; namespace osu.Game.Online.API.Requests { diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index 4d215467bb..940cd7f5ac 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using osu.Framework.Allocation; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; @@ -13,26 +8,22 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.Chat; using osu.Game.Screens.Select.Leaderboards; -using osu.Game.Users; -using static osu.Game.Online.API.Requests.RecentActivity; namespace osu.Game.Overlays.Profile.Sections.Recent { public class DrawableRecentActivity : DrawableProfileRow { - private RecentActivity activity; - private User user; private APIAccess api; - private string userLinkTemplate; - private string beatmapLinkTemplate; + private readonly RecentActivity activity; + private readonly string userLinkTemplate; + private readonly string beatmapLinkTemplate; private LinkFlowContainer content; - public DrawableRecentActivity(RecentActivity activity, User user) + public DrawableRecentActivity(RecentActivity activity) { this.activity = activity; - this.user = user; userLinkTemplate = $"[{urlToAbsolute(activity.User?.Url)} {activity.User?.Username}]"; beatmapLinkTemplate = $"[{urlToAbsolute(activity.Beatmap?.Url)} {activity.Beatmap?.Title}]"; diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs index 307c06b744..f1857096aa 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs @@ -1,17 +1,12 @@ using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Game.Online.API.Requests; -using osu.Game.Overlays.Profile.Sections.Recent; using osu.Game.Users; -using System; -using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace osu.Game.Overlays.Profile.Sections +namespace osu.Game.Overlays.Profile.Sections.Recent { - class PaginatedRecentActivityContainer : PaginatedContainer + internal class PaginatedRecentActivityContainer : PaginatedContainer { public PaginatedRecentActivityContainer(Bindable user, string header, string missing) : base(user, header, missing) @@ -40,7 +35,7 @@ namespace osu.Game.Overlays.Profile.Sections foreach (RecentActivity activity in activities) { - ItemsContainer.Add(new DrawableRecentActivity(activity, User)); + ItemsContainer.Add(new DrawableRecentActivity(activity)); } }; diff --git a/osu.Game/Overlays/Profile/Sections/RecentSection.cs b/osu.Game/Overlays/Profile/Sections/RecentSection.cs index 757e2457d2..db97dca440 100644 --- a/osu.Game/Overlays/Profile/Sections/RecentSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RecentSection.cs @@ -1,6 +1,8 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Game.Overlays.Profile.Sections.Recent; + namespace osu.Game.Overlays.Profile.Sections { public class RecentSection : ProfileSection diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index f19fc4062c..f3fd7aeac5 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -78,7 +78,7 @@ namespace osu.Game.Overlays if (userId == Header.User.Id) return; - ShowUser(new User { Id = userId }, true); + ShowUser(new User { Id = userId }); } public void ShowUser(User user, bool fetchOnline = true) From 5724618b2a3f8109254246c493b00738fa1117df Mon Sep 17 00:00:00 2001 From: naoey Date: Mon, 26 Feb 2018 09:38:37 +0530 Subject: [PATCH 06/14] Add license headers and sanitise open profile argument. --- osu.Game/Graphics/Containers/LinkFlowContainer.cs | 3 ++- .../Online/API/Requests/GetUserRecentActivitiesRequest.cs | 5 ++++- .../Profile/Sections/Recent/DrawableRecentActivity.cs | 5 ++++- .../Sections/Recent/PaginatedRecentActivityContainer.cs | 5 ++++- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index 8edae7a976..c16ccbce86 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -93,7 +93,8 @@ namespace osu.Game.Graphics.Containers Process.Start(url); break; case LinkAction.OpenUserProfile: - userProfile?.ShowUser(Convert.ToInt64(linkArgument)); + if (long.TryParse(linkArgument, out long userId)) + userProfile?.ShowUser(userId); break; default: throw new NotImplementedException($"This {nameof(LinkAction)} ({linkType.ToString()}) is missing an associated action."); diff --git a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs index d52d0c884e..451c39fdfe 100644 --- a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs @@ -1,4 +1,7 @@ -using Newtonsoft.Json; +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using Newtonsoft.Json; using osu.Game.Rulesets.Scoring; using Humanizer; using System; diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index 940cd7f5ac..901791d340 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -1,4 +1,7 @@ -using osu.Framework.Allocation; +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs index f1857096aa..3de005cf9b 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs @@ -1,4 +1,7 @@ -using osu.Framework.Configuration; +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Game.Online.API.Requests; using osu.Game.Users; From a20e4bc2c3494f37d14448f8ccb1d712dad5a0f5 Mon Sep 17 00:00:00 2001 From: naoey Date: Mon, 26 Feb 2018 11:46:16 +0530 Subject: [PATCH 07/14] Fix typos and missing fields in JSON mappings. --- .../GetUserRecentActivitiesRequest.cs | 17 +++++++++++-- .../Sections/Recent/DrawableRecentActivity.cs | 25 ++++++++++++------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs index 451c39fdfe..7926bd9d34 100644 --- a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs @@ -28,7 +28,7 @@ namespace osu.Game.Online.API.Requests [JsonProperty("id")] public int ID; - [JsonProperty("created_at")] + [JsonProperty("createdAt")] public DateTimeOffset CreatedAt; [JsonProperty] @@ -50,6 +50,9 @@ namespace osu.Game.Online.API.Requests [JsonProperty("rank")] public int Rank; + [JsonProperty("approval")] + public BeatmapApproval Approval; + [JsonProperty("count")] public int Count; @@ -59,10 +62,13 @@ namespace osu.Game.Online.API.Requests [JsonProperty("beatmap")] public RecentActivityBeatmap Beatmap; + [JsonProperty("beatmapset")] + public RecentActivityBeatmap Beatmapset; + [JsonProperty("user")] public RecentActivityUser User; - [JsonProperty("achivementName")] + [JsonProperty("achievementName")] public string AchivementName; public class RecentActivityBeatmap @@ -104,4 +110,11 @@ namespace osu.Game.Online.API.Requests UserSupportGift, UsernameChange, } + + public enum BeatmapApproval + { + Ranked, + Approved, + Qualified, + } } diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index 901791d340..012418967f 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -21,6 +21,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent private readonly RecentActivity activity; private readonly string userLinkTemplate; private readonly string beatmapLinkTemplate; + private readonly string beatmapsetLinkTemplate; private LinkFlowContainer content; @@ -30,6 +31,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent userLinkTemplate = $"[{urlToAbsolute(activity.User?.Url)} {activity.User?.Username}]"; beatmapLinkTemplate = $"[{urlToAbsolute(activity.Beatmap?.Url)} {activity.Beatmap?.Title}]"; + beatmapsetLinkTemplate = $"[{urlToAbsolute(activity.Beatmapset?.Url)} {activity.Beatmapset?.Title}]"; } [BackgroundDependencyLoader] @@ -70,6 +72,8 @@ namespace osu.Game.Overlays.Profile.Sections.Recent FillMode = FillMode.Fit, }; + case RecentActivityType.Medal: + // TODO: add medal visual default: return new Container { @@ -92,26 +96,29 @@ namespace osu.Game.Overlays.Profile.Sections.Recent case RecentActivityType.BeatmapPlaycount: return $"{beatmapLinkTemplate} has been played {activity.Count} times!"; + case RecentActivityType.BeatmapsetApprove: + return $"{beatmapsetLinkTemplate} has been {activity.Approval.ToString().ToLowerInvariant()}!"; + case RecentActivityType.BeatmapsetDelete: - return $"{beatmapLinkTemplate} has been deleted."; + return $"{beatmapsetLinkTemplate} has been deleted."; case RecentActivityType.BeatmapsetRevive: - return $"{beatmapLinkTemplate} has been revived from eternal slumber by ${userLinkTemplate}"; + return $"{beatmapsetLinkTemplate} has been revived from eternal slumber by {userLinkTemplate}."; case RecentActivityType.BeatmapsetUpdate: - return $"{userLinkTemplate} has updated the beatmap ${beatmapLinkTemplate}"; + return $"{userLinkTemplate} has updated the beatmap {beatmapsetLinkTemplate}!"; case RecentActivityType.BeatmapsetUpload: - return $"{userLinkTemplate} has submitted a new beatmap ${beatmapLinkTemplate}"; + return $"{userLinkTemplate} has submitted a new beatmap {beatmapsetLinkTemplate}!"; case RecentActivityType.Medal: return $"{userLinkTemplate} has unlocked the {activity.AchivementName} medal!"; case RecentActivityType.Rank: - return $"{userLinkTemplate} achieved rank #{activity.Rank} on {beatmapLinkTemplate}"; + return $"{userLinkTemplate} achieved rank #{activity.Rank} on {beatmapLinkTemplate} ({activity.Mode}!)"; case RecentActivityType.RankLost: - return $"{userLinkTemplate} has lost first place on {beatmapLinkTemplate}!"; + return $"{userLinkTemplate} has lost first place on {beatmapLinkTemplate} ({activity.Mode}!)"; case RecentActivityType.UserSupportAgain: return $"{userLinkTemplate} has once again chosen to support osu! - thanks for your generosity!"; @@ -119,12 +126,12 @@ namespace osu.Game.Overlays.Profile.Sections.Recent case RecentActivityType.UserSupportFirst: return $"{userLinkTemplate} has become an osu! supporter - thanks for your generosity!"; - case RecentActivityType.UsernameChange: - return $"{activity.User.PreviousUsername} has changed their username to {userLinkTemplate}"; - case RecentActivityType.UserSupportGift: return $"{userLinkTemplate} has received the gift of osu! supporter!"; + case RecentActivityType.UsernameChange: + return $"{activity.User.PreviousUsername} has changed their username to {userLinkTemplate}!"; + default: return string.Empty; } From a77d1eedae0b2756e5ad7cb6ac96d87eb7c8d129 Mon Sep 17 00:00:00 2001 From: naoey Date: Mon, 26 Feb 2018 13:08:12 +0530 Subject: [PATCH 08/14] Fix achievements parsing and add badges to recent activity. --- .../GetUserRecentActivitiesRequest.cs | 14 ++++++- .../Sections/Recent/DrawableRecentActivity.cs | 15 ++++++-- .../Profile/Sections/Recent/MedalIcon.cs | 38 +++++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 4 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs diff --git a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs index 7926bd9d34..d1685b01f3 100644 --- a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs @@ -68,8 +68,8 @@ namespace osu.Game.Online.API.Requests [JsonProperty("user")] public RecentActivityUser User; - [JsonProperty("achievementName")] - public string AchivementName; + [JsonProperty("achievement")] + public RecentActivityAchievement Achievement; public class RecentActivityBeatmap { @@ -91,6 +91,16 @@ namespace osu.Game.Online.API.Requests [JsonProperty("previousUsername")] public string PreviousUsername; } + + public class RecentActivityAchievement + { + [JsonProperty("slug")] + public string Slug; + + [JsonProperty("name")] + public string Name; + } + } public enum RecentActivityType diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index 012418967f..282b2e242a 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -72,8 +72,14 @@ namespace osu.Game.Overlays.Profile.Sections.Recent FillMode = FillMode.Fit, }; - case RecentActivityType.Medal: - // TODO: add medal visual + case RecentActivityType.Achievement: + return new MedalIcon(activity.Achievement.Slug) + { + RelativeSizeAxes = Axes.Y, + Width = 60, + FillMode = FillMode.Fit, + }; + default: return new Container { @@ -91,7 +97,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent switch (activity.Type) { case RecentActivityType.Achievement: - return $"{userLinkTemplate} unlocked the {activity.AchivementName} achievement!"; + return $"{userLinkTemplate} unlocked the {activity.Achievement.Name} medal!"; case RecentActivityType.BeatmapPlaycount: return $"{beatmapLinkTemplate} has been played {activity.Count} times!"; @@ -112,7 +118,8 @@ namespace osu.Game.Overlays.Profile.Sections.Recent return $"{userLinkTemplate} has submitted a new beatmap {beatmapsetLinkTemplate}!"; case RecentActivityType.Medal: - return $"{userLinkTemplate} has unlocked the {activity.AchivementName} 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) + return string.Empty; case RecentActivityType.Rank: return $"{userLinkTemplate} achieved rank #{activity.Rank} on {beatmapLinkTemplate} ({activity.Mode}!)"; diff --git a/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs new file mode 100644 index 0000000000..9ef2b89269 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs @@ -0,0 +1,38 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; + +namespace osu.Game.Overlays.Profile.Sections.Recent +{ + internal class MedalIcon : Container + { + private readonly string slug; + private readonly Sprite sprite; + + private string url => $@"https://s.ppy.sh/images/medals-client/{slug}@2x.png"; + + public MedalIcon(string slug) + { + this.slug = slug; + + Child = sprite = new Sprite + { + Height = 40, + Width = 40, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + } + + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + sprite.Texture = textures.Get(url); + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index cd40b42365..e420ec6b71 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -301,6 +301,7 @@ + From 62913163e02ca776174bcb1f01388ce6b2c95f53 Mon Sep 17 00:00:00 2001 From: naoey Date: Tue, 27 Feb 2018 21:21:53 +0530 Subject: [PATCH 09/14] Fix long recent activity text overlapping timestamp. - Also remove unnecessary fallback from absolute URL helper --- .../Sections/Recent/DrawableRecentActivity.cs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index 282b2e242a..4785b1e8d3 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -19,19 +19,16 @@ namespace osu.Game.Overlays.Profile.Sections.Recent private APIAccess api; private readonly RecentActivity activity; - private readonly string userLinkTemplate; - private readonly string beatmapLinkTemplate; - private readonly string beatmapsetLinkTemplate; + + private string userLinkTemplate; + private string beatmapLinkTemplate; + private string beatmapsetLinkTemplate; private LinkFlowContainer content; public DrawableRecentActivity(RecentActivity activity) { this.activity = activity; - - userLinkTemplate = $"[{urlToAbsolute(activity.User?.Url)} {activity.User?.Username}]"; - beatmapLinkTemplate = $"[{urlToAbsolute(activity.Beatmap?.Url)} {activity.Beatmap?.Title}]"; - beatmapsetLinkTemplate = $"[{urlToAbsolute(activity.Beatmapset?.Url)} {activity.Beatmapset?.Title}]"; } [BackgroundDependencyLoader] @@ -39,6 +36,12 @@ namespace osu.Game.Overlays.Profile.Sections.Recent { this.api = api; + userLinkTemplate = $"[{toAbsoluteUrl(activity.User?.Url)} {activity.User?.Username}]"; + beatmapLinkTemplate = $"[{toAbsoluteUrl(activity.Beatmap?.Url)} {activity.Beatmap?.Title}]"; + beatmapsetLinkTemplate = $"[{toAbsoluteUrl(activity.Beatmapset?.Url)} {activity.Beatmapset?.Title}]"; + + LeftFlowContainer.Padding = new MarginPadding { Left = 10, Right = 160 }; + LeftFlowContainer.Add(content = new LinkFlowContainer { AutoSizeAxes = Axes.Y, @@ -90,7 +93,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent } } - private string urlToAbsolute(string url) => $"{api?.Endpoint ?? @"https://osu.ppy.sh"}{url}"; + private string toAbsoluteUrl(string url) => $"{api.Endpoint}{url}"; private string activityToString() { From 2e535afb845bb1b6719d6df5611a771879c0d7de Mon Sep 17 00:00:00 2001 From: naoey Date: Wed, 28 Feb 2018 15:19:27 +0530 Subject: [PATCH 10/14] Remove redundant subsection title. - Also handle opening UserProfile in LinkFlowContainer similar to how beatmaps and channels are handled --- osu.Game/Graphics/Containers/LinkFlowContainer.cs | 6 ++---- osu.Game/OsuGame.cs | 6 ++++++ osu.Game/Overlays/Profile/Sections/RecentSection.cs | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index c16ccbce86..1d231ada23 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -23,16 +23,14 @@ namespace osu.Game.Graphics.Containers public override bool HandleMouseInput => true; private OsuGame game; - private UserProfileOverlay userProfile; private Action showNotImplementedError; [BackgroundDependencyLoader(true)] - private void load(OsuGame game, NotificationOverlay notifications, UserProfileOverlay userProfile) + private void load(OsuGame game, NotificationOverlay notifications) { // will be null in tests this.game = game; - this.userProfile = userProfile; showNotImplementedError = () => notifications?.Post(new SimpleNotification { @@ -94,7 +92,7 @@ namespace osu.Game.Graphics.Containers break; case LinkAction.OpenUserProfile: if (long.TryParse(linkArgument, out long userId)) - userProfile?.ShowUser(userId); + game?.ShowUser(userId); break; default: throw new NotImplementedException($"This {nameof(LinkAction)} ({linkType.ToString()}) is missing an associated action."); diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 95eb88c5c8..cff7007fd5 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -154,6 +154,12 @@ namespace osu.Game /// The set to display. public void ShowBeatmapSet(int setId) => beatmapSetOverlay.ShowBeatmapSet(setId); + /// + /// Show a user's profile as an overlay. + /// + /// The user to display. + public void ShowUser(long userId) => userProfile.ShowUser(userId); + protected void LoadScore(Score s) { scoreLoad?.Cancel(); diff --git a/osu.Game/Overlays/Profile/Sections/RecentSection.cs b/osu.Game/Overlays/Profile/Sections/RecentSection.cs index db97dca440..84a941aa1a 100644 --- a/osu.Game/Overlays/Profile/Sections/RecentSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RecentSection.cs @@ -15,7 +15,7 @@ namespace osu.Game.Overlays.Profile.Sections { Children = new[] { - new PaginatedRecentActivityContainer(User, @"Recent", @"This user hasn't done anything notable recently!"), + new PaginatedRecentActivityContainer(User, null, @"This user hasn't done anything notable recently!"), }; } } From 9669c5aee3fa3770bb9639fe3d600087fb0b90c0 Mon Sep 17 00:00:00 2001 From: naoey Date: Sun, 4 Mar 2018 00:01:47 +0530 Subject: [PATCH 11/14] Make locally used things local and rename method. --- .../Sections/Recent/DrawableRecentActivity.cs | 65 ++++++++++++------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index 4785b1e8d3..2dde8a3d54 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -20,10 +20,6 @@ namespace osu.Game.Overlays.Profile.Sections.Recent private readonly RecentActivity activity; - private string userLinkTemplate; - private string beatmapLinkTemplate; - private string beatmapsetLinkTemplate; - private LinkFlowContainer content; public DrawableRecentActivity(RecentActivity activity) @@ -36,10 +32,6 @@ namespace osu.Game.Overlays.Profile.Sections.Recent { this.api = api; - userLinkTemplate = $"[{toAbsoluteUrl(activity.User?.Url)} {activity.User?.Username}]"; - beatmapLinkTemplate = $"[{toAbsoluteUrl(activity.Beatmap?.Url)} {activity.Beatmap?.Title}]"; - beatmapsetLinkTemplate = $"[{toAbsoluteUrl(activity.Beatmapset?.Url)} {activity.Beatmapset?.Title}]"; - LeftFlowContainer.Padding = new MarginPadding { Left = 10, Right = 160 }; LeftFlowContainer.Add(content = new LinkFlowContainer @@ -58,7 +50,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent Colour = OsuColour.Gray(0xAA), }); - var formatted = MessageFormatter.FormatText(activityToString()); + var formatted = createMessage(); content.AddLinks(formatted.Text, formatted.Links); } @@ -95,56 +87,79 @@ namespace osu.Game.Overlays.Profile.Sections.Recent private string toAbsoluteUrl(string url) => $"{api.Endpoint}{url}"; - private string activityToString() + private MessageFormatter.MessageFormatterResult 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: - return $"{userLinkTemplate} unlocked the {activity.Achievement.Name} medal!"; + message = $"{userLinkTemplate()} unlocked the {activity.Achievement.Name} medal!"; + break; case RecentActivityType.BeatmapPlaycount: - return $"{beatmapLinkTemplate} has been played {activity.Count} times!"; + message = $"{beatmapLinkTemplate()} has been played {activity.Count} times!"; + break; case RecentActivityType.BeatmapsetApprove: - return $"{beatmapsetLinkTemplate} has been {activity.Approval.ToString().ToLowerInvariant()}!"; + message = $"{beatmapsetLinkTemplate()} has been {activity.Approval.ToString().ToLowerInvariant()}!"; + break; case RecentActivityType.BeatmapsetDelete: - return $"{beatmapsetLinkTemplate} has been deleted."; + message = $"{beatmapsetLinkTemplate()} has been deleted."; + break; case RecentActivityType.BeatmapsetRevive: - return $"{beatmapsetLinkTemplate} has been revived from eternal slumber by {userLinkTemplate}."; + message = $"{beatmapsetLinkTemplate()} has been revived from eternal slumber by {userLinkTemplate()}."; + break; case RecentActivityType.BeatmapsetUpdate: - return $"{userLinkTemplate} has updated the beatmap {beatmapsetLinkTemplate}!"; + message = $"{userLinkTemplate()} has updated the beatmap {beatmapsetLinkTemplate()}!"; + break; case RecentActivityType.BeatmapsetUpload: - return $"{userLinkTemplate} has submitted a new beatmap {beatmapsetLinkTemplate}!"; + message = $"{userLinkTemplate()} has submitted a new beatmap {beatmapsetLinkTemplate()}!"; + 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) - return string.Empty; + message = string.Empty; + break; case RecentActivityType.Rank: - return $"{userLinkTemplate} achieved rank #{activity.Rank} on {beatmapLinkTemplate} ({activity.Mode}!)"; + message = $"{userLinkTemplate()} achieved rank #{activity.Rank} on {beatmapLinkTemplate()} ({activity.Mode}!)"; + break; case RecentActivityType.RankLost: - return $"{userLinkTemplate} has lost first place on {beatmapLinkTemplate} ({activity.Mode}!)"; + message = $"{userLinkTemplate()} has lost first place on {beatmapLinkTemplate()} ({activity.Mode}!)"; + break; case RecentActivityType.UserSupportAgain: - return $"{userLinkTemplate} has once again chosen to support osu! - thanks for your generosity!"; + message = $"{userLinkTemplate()} has once again chosen to support osu! - thanks for your generosity!"; + break; case RecentActivityType.UserSupportFirst: - return $"{userLinkTemplate} has become an osu! supporter - thanks for your generosity!"; + message = $"{userLinkTemplate()} has become an osu! supporter - thanks for your generosity!"; + break; case RecentActivityType.UserSupportGift: - return $"{userLinkTemplate} has received the gift of osu! supporter!"; + message = $"{userLinkTemplate()} has received the gift of osu! supporter!"; + break; case RecentActivityType.UsernameChange: - return $"{activity.User.PreviousUsername} has changed their username to {userLinkTemplate}!"; + message = $"{activity.User?.PreviousUsername} has changed their username to {userLinkTemplate()}!"; + break; default: - return string.Empty; + message = string.Empty; + break; } + + return MessageFormatter.FormatText(message); } } } From 3731cbe5eba7c729209d10bf38e272b51a9769bc Mon Sep 17 00:00:00 2001 From: pdrapoport Date: Wed, 7 Mar 2018 14:20:59 +0100 Subject: [PATCH 12/14] Removing "mouse wheel disabled" checkbox from visual settings gameplay menu --- osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs index 1a7b80ec9a..6c4d929c71 100644 --- a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs @@ -15,7 +15,6 @@ namespace osu.Game.Screens.Play.PlayerSettings private readonly PlayerSliderBar dimSliderBar; private readonly PlayerSliderBar blurSliderBar; private readonly PlayerCheckbox showStoryboardToggle; - private readonly PlayerCheckbox mouseWheelDisabledToggle; public VisualSettings() { @@ -35,8 +34,7 @@ namespace osu.Game.Screens.Play.PlayerSettings { Text = "Toggles:" }, - showStoryboardToggle = new PlayerCheckbox { LabelText = "Storyboards" }, - mouseWheelDisabledToggle = new PlayerCheckbox { LabelText = "Disable mouse wheel" } + showStoryboardToggle = new PlayerCheckbox { LabelText = "Storyboards" } }; } @@ -46,7 +44,6 @@ namespace osu.Game.Screens.Play.PlayerSettings dimSliderBar.Bindable = config.GetBindable(OsuSetting.DimLevel); blurSliderBar.Bindable = config.GetBindable(OsuSetting.BlurLevel); showStoryboardToggle.Bindable = config.GetBindable(OsuSetting.ShowStoryboard); - mouseWheelDisabledToggle.Bindable = config.GetBindable(OsuSetting.MouseDisableWheel); } } } From 983cefbe40b651961a9566a4fc22a651e611e6fa Mon Sep 17 00:00:00 2001 From: naoey Date: Wed, 7 Mar 2018 17:33:21 +0530 Subject: [PATCH 13/14] Add VisualTest. --- .../TestCaseUserProfileRecentSection.cs | 162 ++++++++++++++++++ osu.Game.Tests/osu.Game.Tests.csproj | 1 + .../Profile/Sections/Recent/MedalIcon.cs | 2 +- .../PaginatedRecentActivityContainer.cs | 2 +- 4 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCaseUserProfileRecentSection.cs diff --git a/osu.Game.Tests/Visual/TestCaseUserProfileRecentSection.cs b/osu.Game.Tests/Visual/TestCaseUserProfileRecentSection.cs new file mode 100644 index 0000000000..23eb7f68f9 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseUserProfileRecentSection.cs @@ -0,0 +1,162 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Online.API.Requests; +using osu.Game.Overlays.Profile.Sections; +using osu.Game.Overlays.Profile.Sections.Recent; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace osu.Game.Tests.Visual +{ + [TestFixture] + public class TestCaseUserProfileRecentSection : OsuTestCase + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(RecentSection), + typeof(DrawableRecentActivity), + typeof(PaginatedRecentActivityContainer), + typeof(MedalIcon) + }; + + public TestCaseUserProfileRecentSection() + { + var flow = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + }; + + flow.AddRange(createDummyActivities().Select(a => new DrawableRecentActivity(a))); + + Add(new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.Gray(0.2f) + }); + + Add(new ScrollContainer + { + RelativeSizeAxes = Axes.Both, + Child = flow, + }); + } + + private IEnumerable createDummyActivities() + { + var dummyBeatmap = new RecentActivity.RecentActivityBeatmap + { + Title = @"Dummy beatmap", + Url = "/b/1337", + }; + + var dummyUser = new RecentActivity.RecentActivityUser + { + Username = "DummyReborn", + Url = "/u/666", + PreviousUsername = "Dummy", + }; + + return new[] + { + new RecentActivity + { + User = dummyUser, + Type = RecentActivityType.Achievement, + Achievement = new RecentActivity.RecentActivityAchievement + { + Name = @"Feelin' It", + Slug = @"all-secret-feelinit", + }, + }, + new RecentActivity + { + User = dummyUser, + Type = RecentActivityType.BeatmapPlaycount, + Count = 1337, + Beatmap = dummyBeatmap, + }, + new RecentActivity + { + User = dummyUser, + Type = RecentActivityType.BeatmapsetApprove, + Approval = BeatmapApproval.Qualified, + Beatmapset = dummyBeatmap, + }, + new RecentActivity + { + User = dummyUser, + Type = RecentActivityType.BeatmapsetDelete, + Beatmapset = dummyBeatmap, + }, + new RecentActivity + { + User = dummyUser, + Type = RecentActivityType.BeatmapsetRevive, + Beatmapset = dummyBeatmap, + }, + new RecentActivity + { + User = dummyUser, + Type = RecentActivityType.BeatmapsetRevive, + Beatmapset = dummyBeatmap, + }, + new RecentActivity + { + User = dummyUser, + Type = RecentActivityType.BeatmapsetUpdate, + Beatmapset = dummyBeatmap, + }, + new RecentActivity + { + User = dummyUser, + Type = RecentActivityType.BeatmapsetUpload, + Beatmapset = dummyBeatmap, + }, + new RecentActivity + { + User = dummyUser, + Type = RecentActivityType.Rank, + Rank = 1, + Mode = "osu!", + Beatmap = dummyBeatmap, + }, + new RecentActivity + { + User = dummyUser, + Type = RecentActivityType.RankLost, + Mode = "osu!", + Beatmap = dummyBeatmap, + }, + new RecentActivity + { + User = dummyUser, + Type = RecentActivityType.UsernameChange, + }, + new RecentActivity + { + User = dummyUser, + Type = RecentActivityType.UserSupportAgain, + }, + new RecentActivity + { + User = dummyUser, + Type = RecentActivityType.UserSupportFirst, + }, + new RecentActivity + { + User = dummyUser, + Type = RecentActivityType.UserSupportGift, + }, + }; + } + } +} diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 8cbeb6aab6..1cfa7bc111 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -173,6 +173,7 @@ + diff --git a/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs index 9ef2b89269..6ffbe7193f 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs @@ -9,7 +9,7 @@ using osu.Framework.Graphics.Textures; namespace osu.Game.Overlays.Profile.Sections.Recent { - internal class MedalIcon : Container + public class MedalIcon : Container { private readonly string slug; private readonly Sprite sprite; diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs index 3de005cf9b..d479627cde 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs @@ -9,7 +9,7 @@ using System.Linq; namespace osu.Game.Overlays.Profile.Sections.Recent { - internal class PaginatedRecentActivityContainer : PaginatedContainer + public class PaginatedRecentActivityContainer : PaginatedContainer { public PaginatedRecentActivityContainer(Bindable user, string header, string missing) : base(user, header, missing) From e55a503f79735df4abd83d867fb5db21db18fccb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Mar 2018 00:58:16 +0900 Subject: [PATCH 14/14] Tidy up test case --- .../TestCaseUserProfileRecentSection.cs | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseUserProfileRecentSection.cs b/osu.Game.Tests/Visual/TestCaseUserProfileRecentSection.cs index 23eb7f68f9..1f7a7e7165 100644 --- a/osu.Game.Tests/Visual/TestCaseUserProfileRecentSection.cs +++ b/osu.Game.Tests/Visual/TestCaseUserProfileRecentSection.cs @@ -28,26 +28,25 @@ namespace osu.Game.Tests.Visual public TestCaseUserProfileRecentSection() { - var flow = new FillFlowContainer + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.Gray(0.2f) + }, + new ScrollContainer + { + RelativeSizeAxes = Axes.Both, + Child = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + ChildrenEnumerable = createDummyActivities().Select(a => new DrawableRecentActivity(a)) + }, + } }; - - flow.AddRange(createDummyActivities().Select(a => new DrawableRecentActivity(a))); - - Add(new Box - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.Gray(0.2f) - }); - - Add(new ScrollContainer - { - RelativeSizeAxes = Axes.Both, - Child = flow, - }); } private IEnumerable createDummyActivities()