diff --git a/osu.Game.Tests/Visual/TestCaseChatLink.cs b/osu.Game.Tests/Visual/TestCaseChatLink.cs index 1ad297d1f9..9f8c3ce146 100644 --- a/osu.Game.Tests/Visual/TestCaseChatLink.cs +++ b/osu.Game.Tests/Visual/TestCaseChatLink.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Online.Chat; using osu.Game.Overlays; @@ -47,19 +48,32 @@ namespace osu.Game.Tests.Visual private void clear() => AddStep("clear messages", textContainer.Clear); - private void addMessageWithChecks(string text, int linkAmount = 0, bool isAction = false) + private void addMessageWithChecks(string text, int linkAmount = 0, bool isAction = false, bool isImportant = false) { - var newLine = new ChatLine(new DummyMessage(text, isAction)); + var newLine = new ChatLine(new DummyMessage(text, isAction, isImportant)); textContainer.Add(newLine); AddAssert($"msg #{textContainer.Count} has {linkAmount} link(s)", () => newLine.Message.Links.Count == linkAmount); AddAssert($"msg #{textContainer.Count} is " + (isAction ? "italic" : "not italic"), () => newLine.ContentFlow.Any() && isAction == isItalic(newLine.ContentFlow)); - AddAssert($"msg #{textContainer.Count} shows link(s)", () => isShowingLinks(newLine.ContentFlow)); + AddAssert($"msg #{textContainer.Count} shows link(s)", isShowingLinks); - bool isItalic(OsuTextFlowContainer c) => c.Cast().All(sprite => sprite.Font == @"Exo2.0-MediumItalic"); + bool isItalic(ChatFlowContainer c) => c.Cast().All(sprite => sprite.Font == @"Exo2.0-MediumItalic"); - bool isShowingLinks(OsuTextFlowContainer c) => c.Cast().All(sprite => sprite.HandleInput && !sprite.TextColour.Equals((SRGBColour)Color4.White) - || !sprite.HandleInput && sprite.TextColour.Equals((SRGBColour)Color4.White)); + bool isShowingLinks() + { + SRGBColour textColour = Color4.White; + bool hasBackground = !string.IsNullOrEmpty(newLine.Message.Sender.Colour); + + if (isAction && hasBackground) + textColour = OsuColour.FromHex(newLine.Message.Sender.Colour); + + return newLine.ContentFlow + .Cast() + .All(sprite => sprite.HandleInput && !sprite.TextColour.Equals(textColour) + || !sprite.HandleInput && sprite.TextColour.Equals(textColour) + // if someone with a background uses /me with a link, the usual link colour is overridden + || isAction && hasBackground && sprite.HandleInput && !sprite.TextColour.Equals((ColourInfo)Color4.White)); + } } private void testLinksGeneral() @@ -77,6 +91,9 @@ namespace osu.Game.Tests.Visual addMessageWithChecks("Let's (try)[https://osu.ppy.sh/home] [https://osu.ppy.sh/home multiple links] https://osu.ppy.sh/home", 3); // note that there's 0 links here (they get removed if a channel is not found) addMessageWithChecks("#lobby or #osu would be blue (and work) in the ChatDisplay test (when a proper ChatOverlay is present)."); + addMessageWithChecks("I am important!", 0, false, true); + addMessageWithChecks("feels important", 0, true, true); + addMessageWithChecks("likes to post this [https://osu.ppy.sh/home link].", 1, true, true); } private void testAddingLinks() @@ -132,37 +149,27 @@ namespace osu.Game.Tests.Visual private class DummyMessage : Message { private static long messageCounter; + internal static readonly User TEST_SENDER_BACKGROUND = new User + { + Username = @"i-am-important", + Id = 42, + Colour = "#250cc9", + }; + internal static readonly User TEST_SENDER = new User { Username = @"Somebody", Id = 1, - Country = new Country { FullName = @"Alien" }, - CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c1.jpg", - JoinDate = DateTimeOffset.Now.AddDays(-1), - LastVisit = DateTimeOffset.Now, - Age = 1, - ProfileOrder = new[] { "me" }, - CountryRank = 1, - Statistics = new UserStatistics - { - Rank = 2148, - PP = 4567.89m - }, - RankHistory = new User.RankHistoryData - { - Mode = @"osu", - Data = Enumerable.Range(2345, 45).Concat(Enumerable.Range(2109, 40)).ToArray(), - } }; public new DateTimeOffset Timestamp = DateTimeOffset.Now; - public DummyMessage(string text, bool isAction = false) + public DummyMessage(string text, bool isAction = false, bool isImportant = false) : base(messageCounter++) { Content = text; IsAction = isAction; - Sender = TEST_SENDER; + Sender = isImportant ? TEST_SENDER_BACKGROUND : TEST_SENDER; } } diff --git a/osu.Game/Graphics/Containers/ChatFlowContainer.cs b/osu.Game/Graphics/Containers/ChatFlowContainer.cs new file mode 100644 index 0000000000..6fd06aef7c --- /dev/null +++ b/osu.Game/Graphics/Containers/ChatFlowContainer.cs @@ -0,0 +1,61 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics.Colour; +using osu.Game.Online.Chat; +using System; + +namespace osu.Game.Graphics.Containers +{ + public class ChatFlowContainer : OsuTextFlowContainer + { + private readonly Action defaultCreationParameters; + private ColourInfo urlColour; + + public ChatFlowContainer(Action defaultCreationParameters = null) + { + this.defaultCreationParameters = defaultCreationParameters; + } + + public override bool HandleInput => true; + + public void AddLink(string text, string url, LinkAction linkType, string linkArgument) + { + var chatSprite = new ChatLink + { + Text = text, + Url = url, + TextColour = urlColour, + LinkAction = linkType, + LinkArgument = linkArgument, + }; + + defaultCreationParameters?.Invoke(chatSprite); + + AddInternal(chatSprite); + } + + public void AddText(string text, Action creationParameters = null) + { + foreach (var word in SplitWords(text)) + { + if (string.IsNullOrEmpty(word)) + continue; + + var chatSprite = new ChatLink { Text = word }; + + defaultCreationParameters?.Invoke(chatSprite); + creationParameters?.Invoke(chatSprite); + + AddInternal(chatSprite); + } + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + urlColour = colours.Blue; + } + } +} diff --git a/osu.Game/Graphics/Containers/OsuLinkFlowContainer.cs b/osu.Game/Graphics/Containers/OsuLinkFlowContainer.cs deleted file mode 100644 index 48910a04ca..0000000000 --- a/osu.Game/Graphics/Containers/OsuLinkFlowContainer.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using OpenTK.Graphics; -using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics.Sprites; -using System; -using System.Collections.Generic; - -namespace osu.Game.Graphics.Containers -{ - public class OsuLinkFlowContainer : OsuLinkFlowContainer - { - public OsuLinkFlowContainer(Action defaultCreationParameters = null) - : base(defaultCreationParameters) - { - } - } - - public class OsuLinkFlowContainer : OsuTextFlowContainer - where T : OsuSpriteLink, new() - { - public override bool HandleInput => true; - - public OsuLinkFlowContainer(Action defaultCreationParameters = null) - : base(defaultCreationParameters) - { - } - - protected override SpriteText CreateSpriteText() => new T(); - - /// - /// The colour for text (links override this). Will only be used for new text elements. - /// - public ColourInfo TextColour = Color4.White; - - public IEnumerable AddLink(string text, string url, Action creationParameters = null) - { - // TODO: Remove this and get word wrapping working - text = text.Replace(' ', '_'); - - return AddText(text, link => - { - ((OsuSpriteLink)link).Url = url; - creationParameters?.Invoke(link); - }); - } - - public new IEnumerable AddText(string text, Action creationParameters = null) - { - return base.AddText(text, sprite => - { - ((OsuSpriteLink)sprite).TextColour = TextColour; - creationParameters?.Invoke(sprite); - }); - } - } -} diff --git a/osu.Game/Graphics/Sprites/OsuSpriteLink.cs b/osu.Game/Graphics/Sprites/OsuSpriteLink.cs index 1c2a219b53..9fc24651db 100644 --- a/osu.Game/Graphics/Sprites/OsuSpriteLink.cs +++ b/osu.Game/Graphics/Sprites/OsuSpriteLink.cs @@ -12,6 +12,8 @@ namespace osu.Game.Graphics.Sprites { public class OsuSpriteLink : OsuSpriteText { + public override bool HandleInput => !string.IsNullOrEmpty(Url); + protected override IEnumerable FlowingChildren => Children; protected override Container Content => content; diff --git a/osu.Game/Online/API/Requests/GetBeatmapRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapRequest.cs deleted file mode 100644 index 76d67e7afc..0000000000 --- a/osu.Game/Online/API/Requests/GetBeatmapRequest.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Game.Beatmaps; - -namespace osu.Game.Online.API.Requests -{ - public class GetBeatmapRequest : APIRequest - { - private readonly int beatmapId; - - public GetBeatmapRequest(int beatmapId) - { - this.beatmapId = beatmapId; - } - - protected override string Target => $@"beatmaps/{beatmapId}"; - } -} diff --git a/osu.Game/Online/Chat/ChatLink.cs b/osu.Game/Online/Chat/ChatLink.cs index aa5a0e100b..f38eade682 100644 --- a/osu.Game/Online/Chat/ChatLink.cs +++ b/osu.Game/Online/Chat/ChatLink.cs @@ -4,123 +4,57 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Cursor; using osu.Game.Graphics.Sprites; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests; using osu.Game.Overlays; using System; -using System.Text.RegularExpressions; namespace osu.Game.Online.Chat { public class ChatLink : OsuSpriteLink, IHasTooltip { - private APIAccess api; private BeatmapSetOverlay beatmapSetOverlay; private ChatOverlay chat; + private OsuGame game; - public override bool HandleInput => !string.IsNullOrEmpty(Url); + /// + /// The type of action executed on clicking this link. + /// + public LinkAction LinkAction { get; set; } - // 'protocol' -> 'https', 'http', 'osu', 'osump' etc. - // 'content' -> everything after '://' - private Match getUrlMatch() => Regex.Match(Url, @"^(?osu(?:mp)?|https?):\/\/(?.*)"); + /// + /// The argument necessary for the action specified by to execute. + /// Usually a part of the URL. + /// + public string LinkArgument { get; set; } protected override void OnLinkClicked() { - var urlMatch = getUrlMatch(); - if (urlMatch.Success) + switch (LinkAction) { - var args = urlMatch.Groups["content"].Value.Split('/'); - - switch (urlMatch.Groups["protocol"].Value) - { - case "osu": - if (args.Length == 1) - { - base.OnLinkClicked(); - break; - } - - switch (args[0]) - { - case "chan": - var foundChannel = chat.AvailableChannels.Find(channel => channel.Name == args[1]); - - // links should be filtered out by now if a channel doesn't exist - chat.OpenChannel(foundChannel ?? throw new ArgumentException($"Unknown channel name ({args[1]}).")); - break; - case "edit": - chat.Game?.LoadEditorTimestamp(); - break; - case "b": - if (args.Length > 1 && int.TryParse(args[1], out int mapId)) - beatmapSetOverlay.ShowBeatmap(mapId); - - break; - case "s": - case "dl": - if (args.Length > 1 && int.TryParse(args[1], out int mapSetId)) - beatmapSetOverlay.ShowBeatmapSet(mapSetId); - - break; - case "spectate": - GetUserRequest req; - if (int.TryParse(args[1], out int userId)) - req = new GetUserRequest(userId); - else - return; - - req.Success += user => - { - chat.Game?.LoadSpectatorScreen(); - }; - api.Queue(req); - - break; - default: - throw new ArgumentException($"Unknown osu:// link at {nameof(ChatLink)} ({urlMatch.Groups["content"].Value})."); - } - - break; - case "osump": - if (args.Length > 1 && int.TryParse(args[1], out int multiId)) - chat.Game?.LoadMultiplayerLobby(multiId); - - break; - case "http": - case "https": - if (args[0] == "osu.ppy.sh" && args.Length > 2) - { - switch (args[1]) - { - case "b": - case "beatmaps": - beatmapSetOverlay.ShowBeatmap(getId(args[2])); - break; - case "s": - case "beatmapsets": - case "d": - beatmapSetOverlay.ShowBeatmapSet(getId(args[2])); - break; - default: - base.OnLinkClicked(); - break; - } - } - else - base.OnLinkClicked(); - break; - default: - base.OnLinkClicked(); - break; - } - } - else - base.OnLinkClicked(); - - int getId(string input) - { - var index = input.IndexOf('#'); - return int.Parse(index > 0 ? input.Remove(index) : input); + case LinkAction.OpenBeatmap: + // todo: implement this when overlay.ShowBeatmap(id) exists + break; + case LinkAction.OpenBeatmapSet: + if (int.TryParse(LinkArgument, out int setId)) + beatmapSetOverlay.ShowBeatmapSet(setId); + break; + case LinkAction.OpenChannel: + chat.OpenChannel(chat.AvailableChannels.Find(c => c.Name == LinkArgument)); + break; + case LinkAction.OpenEditorTimestamp: + game?.LoadEditorTimestamp(); + break; + case LinkAction.JoinMultiplayerMatch: + if (int.TryParse(LinkArgument, out int matchId)) + game?.JoinMultiplayerMatch(matchId); + break; + case LinkAction.Spectate: + // todo: implement this when spectating exists + break; + case LinkAction.External: + base.OnLinkClicked(); + break; + default: + throw new NotImplementedException($"This {nameof(Chat.LinkAction)} ({LinkAction.ToString()}) is missing an associated action."); } } @@ -131,30 +65,25 @@ namespace osu.Game.Online.Chat if (Url == Text) return null; - var urlMatch = getUrlMatch(); - if (urlMatch.Success && urlMatch.Groups["protocol"].Value == "osu") + switch (LinkAction) { - var args = urlMatch.Groups["content"].Value.Split('/'); - - if (args.Length < 2) + case LinkAction.OpenChannel: + return "Switch to channel " + LinkArgument; + case LinkAction.OpenEditorTimestamp: + return "Go to " + LinkArgument; + default: return Url; - - if (args[0] == "chan") - return "Switch to channel " + args[1]; - if (args[0] == "edit") - return "Go to " + args[1]; } - - return Url; } } - [BackgroundDependencyLoader] - private void load(APIAccess api, BeatmapSetOverlay beatmapSetOverlay, ChatOverlay chat) + [BackgroundDependencyLoader(true)] + private void load(BeatmapSetOverlay beatmapSetOverlay, ChatOverlay chat, OsuGame game) { - this.api = api; this.beatmapSetOverlay = beatmapSetOverlay; this.chat = chat; + // this will be null in tests + this.game = game; } } } diff --git a/osu.Game/Online/Chat/Message.cs b/osu.Game/Online/Chat/Message.cs index ac14d3a88f..cda55ad269 100644 --- a/osu.Game/Online/Chat/Message.cs +++ b/osu.Game/Online/Chat/Message.cs @@ -41,7 +41,7 @@ namespace osu.Game.Online.Chat { } - public List Links; + public List Links; public Message(long? id) { diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs index 81551b08f4..eadab8840f 100644 --- a/osu.Game/Online/Chat/MessageFormatter.cs +++ b/osu.Game/Online/Chat/MessageFormatter.cs @@ -39,7 +39,7 @@ namespace osu.Game.Online.Chat // Unicode emojis private static readonly Regex emoji_regex = new Regex(@"(\uD83D[\uDC00-\uDE4F])"); - private static void handleMatches(Regex regex, string display, string link, MessageFormatterResult result, int startIndex = 0) + private static void handleMatches(Regex regex, string display, string link, MessageFormatterResult result, int startIndex = 0, LinkAction? linkActionOverride = null) { int captureOffset = 0; foreach (Match m in regex.Matches(result.Text, startIndex)) @@ -66,7 +66,8 @@ namespace osu.Game.Online.Chat //since we just changed the line display text, offset any already processed links. result.Links.ForEach(l => l.Index -= l.Index > index ? m.Length - displayText.Length : 0); - result.Links.Add(new Link(linkText, index, displayText.Length)); + var details = getLinkDetails(link); + result.Links.Add(new Link(linkText, index, displayText.Length, linkActionOverride ?? details.linkType, details.linkArgument)); //adjust the offset for processing the current matches group. captureOffset += m.Length - displayText.Length; @@ -93,7 +94,70 @@ namespace osu.Game.Online.Chat } } - result.Links.Add(new Link(link, index, indexLength)); + var details = getLinkDetails(link); + result.Links.Add(new Link(link, index, indexLength, details.linkType, details.linkArgument)); + } + } + + private static (LinkAction linkType, string linkArgument) getLinkDetails(string url) + { + var args = url.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + args[0] = args[0].TrimEnd(':'); + + switch (args[0]) + { + case "http": + case "https": + // length > 3 since all these links need another argument to work + if (args.Length > 3 && (args[1] == "osu.ppy.sh" || args[1] == "new.ppy.sh")) + { + switch (args[2]) + { + case "b": + case "beatmaps": + return (LinkAction.OpenBeatmap, args[3]); + case "s": + case "beatmapsets": + case "d": + return (LinkAction.External, args[3]); + } + } + + return (LinkAction.External, null); + case "osu": + // every internal link also needs some kind of argument + if (args.Length < 3) + return (LinkAction.External, null); + + LinkAction linkType; + switch (args[1]) + { + case "chan": + linkType = LinkAction.OpenChannel; + break; + case "edit": + linkType = LinkAction.OpenEditorTimestamp; + break; + case "b": + linkType = LinkAction.OpenBeatmap; + break; + case "s": + case "dl": + linkType = LinkAction.OpenBeatmapSet; + break; + case "spectate": + linkType = LinkAction.Spectate; + break; + default: + linkType = LinkAction.External; + break; + } + + return (linkType, args[2]); + case "osump": + return (LinkAction.JoinMultiplayerMatch, args[1]); + default: + return (LinkAction.External, null); } } @@ -114,10 +178,10 @@ namespace osu.Game.Online.Chat handleAdvanced(advanced_link_regex, result, startIndex); // handle editor times - handleMatches(time_regex, "{0}", "osu://edit/{0}", result, startIndex); + handleMatches(time_regex, "{0}", "osu://edit/{0}", result, startIndex, LinkAction.OpenEditorTimestamp); // handle channels - handleMatches(channel_regex, "{0}", "osu://chan/{0}", result, startIndex); + handleMatches(channel_regex, "{0}", "osu://chan/{0}", result, startIndex, LinkAction.OpenChannel); var empty = ""; while (space-- > 0) @@ -151,21 +215,36 @@ namespace osu.Game.Online.Chat OriginalText = Text = text; } } + } - public class Link : IComparable + public enum LinkAction + { + External, + OpenBeatmap, + OpenBeatmapSet, + OpenChannel, + OpenEditorTimestamp, + JoinMultiplayerMatch, + Spectate, + } + + public class Link : IComparable + { + public string Url; + public int Index; + public int Length; + public LinkAction Action; + public string Argument; + + public Link(string url, int startIndex, int length, LinkAction action, string argument) { - public string Url; - public int Index; - public int Length; - - public Link(string url, int startIndex, int length) - { - Url = url; - Index = startIndex; - Length = length; - } - - public int CompareTo(Link otherLink) => Index > otherLink.Index ? 1 : -1; + Url = url; + Index = startIndex; + Length = length; + Action = action; + Argument = argument; } + + public int CompareTo(Link otherLink) => Index > otherLink.Index ? 1 : -1; } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 66d2347f47..5c26e3acab 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -134,7 +134,7 @@ namespace osu.Game }); } - internal void LoadMultiplayerLobby(int lobbyId) + internal void JoinMultiplayerMatch(int matchId) { notifications.Post(new SimpleNotification { diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 1481523bc9..0a88f586b5 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -139,20 +139,6 @@ namespace osu.Game.Overlays return true; } - public void ShowBeatmap(int beatmapId) - { - var req = new GetBeatmapRequest(beatmapId); - req.Success += res => - { - if (!res.OnlineBeatmapSetID.HasValue) - return; - - ShowBeatmapSet(res.OnlineBeatmapSetID.Value); - }; - - api.Queue(req); - } - public void ShowBeatmapSet(int beatmapSetId) { // todo: display the overlay while we are loading here. we need to support setting BeatmapSet to null for this to work. diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index ebfdadd553..8d2c1895bb 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -83,13 +83,13 @@ namespace osu.Game.Overlays.Chat private Message message; private OsuSpriteText username; - private OsuLinkFlowContainer contentFlow; + private ChatFlowContainer contentFlow; - public OsuTextFlowContainer ContentFlow => contentFlow; + public ChatFlowContainer ContentFlow => contentFlow; public Message Message { - get { return message; } + get => message; set { if (message == value) return; @@ -107,7 +107,6 @@ namespace osu.Game.Overlays.Chat private void load(OsuColour colours, ChatOverlay chat) { this.chat = chat; - urlColour = colours.Blue; customUsernameColour = colours.ChatBlue; } @@ -192,10 +191,16 @@ namespace osu.Game.Overlays.Chat Padding = new MarginPadding { Left = message_padding + padding }, Children = new Drawable[] { - contentFlow = new OsuLinkFlowContainer(t => + contentFlow = new ChatFlowContainer(t => { if (Message.IsAction) + { t.Font = @"Exo2.0-MediumItalic"; + + if (senderHasBackground) + t.TextColour = OsuColour.FromHex(message.Sender.Colour); + } + t.TextSize = text_size; }) { @@ -205,15 +210,12 @@ namespace osu.Game.Overlays.Chat } } }; - if (message.IsAction && senderHasBackground) - contentFlow.TextColour = OsuColour.FromHex(message.Sender.Colour); updateMessageContent(); FinishTransforms(true); } private ChatOverlay chat; - private Color4 urlColour; private void updateMessageContent() { @@ -230,7 +232,7 @@ namespace osu.Game.Overlays.Chat else { int lastLinkEndIndex = 0; - List linksToRemove = new List(); + List linksToRemove = new List(); foreach (var link in message.Links) { @@ -250,10 +252,7 @@ namespace osu.Game.Overlays.Chat } } - contentFlow.AddLink(message.Content.Substring(link.Index, link.Length), link.Url, sprite => - { - ((ChatLink)sprite).TextColour = urlColour; - }); + contentFlow.AddLink(message.Content.Substring(link.Index, link.Length), link.Url, link.Action, link.Argument); } var lastLink = message.Links[message.Links.Count - 1]; diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 61e37b6e2f..86e4cba9bd 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -41,11 +41,6 @@ namespace osu.Game.Overlays private readonly FocusedTextBox textbox; - /// - /// The current OsuGame instance. Will be null for Tests. - /// - public OsuGame Game; - private APIAccess api; private const int transition_length = 500; @@ -275,11 +270,9 @@ namespace osu.Game.Overlays base.PopOut(); } - [BackgroundDependencyLoader(true)] - private void load(APIAccess api, OsuConfigManager config, OsuColour colours, OsuGame game) + [BackgroundDependencyLoader] + private void load(APIAccess api, OsuConfigManager config, OsuColour colours) { - // game will be null in testing, so some links will not work - Game = game; this.api = api; api.Register(this); diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index f1efbbc54a..a931df78af 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -23,7 +23,7 @@ namespace osu.Game.Overlays.Profile public class ProfileHeader : Container { private readonly OsuTextFlowContainer infoTextLeft; - private readonly OsuLinkFlowContainer infoTextRight; + private readonly LinkFlowContainer infoTextRight; private readonly FillFlowContainer scoreText, scoreNumberText; private readonly RankGraph rankGraph; @@ -142,7 +142,7 @@ namespace osu.Game.Overlays.Profile ParagraphSpacing = 0.8f, LineSpacing = 0.2f }, - infoTextRight = new OsuLinkFlowContainer(t => + infoTextRight = new LinkFlowContainer(t => { t.TextSize = 14; t.Font = @"Exo2.0-RegularItalic"; @@ -473,6 +473,20 @@ namespace osu.Game.Overlays.Profile } } + private class LinkFlowContainer : OsuTextFlowContainer + { + public override bool HandleInput => true; + + public LinkFlowContainer(Action defaultCreationParameters = null) + : base(defaultCreationParameters) + { + } + + protected override SpriteText CreateSpriteText() => new OsuSpriteLink(); + + public void AddLink(string text, string url) => AddText(text, sprite => ((OsuSpriteLink)sprite).Url = url); + } + private class ProfileLink : OsuSpriteLink, IHasTooltip { public string TooltipText => "View Profile in Browser"; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index d32c458ccf..37f94cf4f7 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -268,9 +268,10 @@ + + - @@ -293,7 +294,6 @@ 20171209034410_AddRulesetInfoShortName.cs - @@ -441,7 +441,6 @@ -