mirror of
https://github.com/ppy/osu
synced 2025-01-30 01:42:54 +00:00
Changed chat link implementation according to review
This commit is contained in:
parent
d66d741af2
commit
e7721d71f3
@ -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<ChatLink>().All(sprite => sprite.Font == @"Exo2.0-MediumItalic");
|
||||
bool isItalic(ChatFlowContainer c) => c.Cast<ChatLink>().All(sprite => sprite.Font == @"Exo2.0-MediumItalic");
|
||||
|
||||
bool isShowingLinks(OsuTextFlowContainer c) => c.Cast<ChatLink>().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<ChatLink>()
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
|
61
osu.Game/Graphics/Containers/ChatFlowContainer.cs
Normal file
61
osu.Game/Graphics/Containers/ChatFlowContainer.cs
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// 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<ChatLink> defaultCreationParameters;
|
||||
private ColourInfo urlColour;
|
||||
|
||||
public ChatFlowContainer(Action<ChatLink> 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<ChatLink> 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// 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<OsuSpriteLink>
|
||||
{
|
||||
public OsuLinkFlowContainer(Action<SpriteText> defaultCreationParameters = null)
|
||||
: base(defaultCreationParameters)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class OsuLinkFlowContainer<T> : OsuTextFlowContainer
|
||||
where T : OsuSpriteLink, new()
|
||||
{
|
||||
public override bool HandleInput => true;
|
||||
|
||||
public OsuLinkFlowContainer(Action<SpriteText> defaultCreationParameters = null)
|
||||
: base(defaultCreationParameters)
|
||||
{
|
||||
}
|
||||
|
||||
protected override SpriteText CreateSpriteText() => new T();
|
||||
|
||||
/// <summary>
|
||||
/// The colour for text (links override this). Will only be used for new text elements.
|
||||
/// </summary>
|
||||
public ColourInfo TextColour = Color4.White;
|
||||
|
||||
public IEnumerable<SpriteText> AddLink(string text, string url, Action<SpriteText> 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<SpriteText> AddText(string text, Action<SpriteText> creationParameters = null)
|
||||
{
|
||||
return base.AddText(text, sprite =>
|
||||
{
|
||||
((OsuSpriteLink)sprite).TextColour = TextColour;
|
||||
creationParameters?.Invoke(sprite);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -12,6 +12,8 @@ namespace osu.Game.Graphics.Sprites
|
||||
{
|
||||
public class OsuSpriteLink : OsuSpriteText
|
||||
{
|
||||
public override bool HandleInput => !string.IsNullOrEmpty(Url);
|
||||
|
||||
protected override IEnumerable<Drawable> FlowingChildren => Children;
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// 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<BeatmapInfo>
|
||||
{
|
||||
private readonly int beatmapId;
|
||||
|
||||
public GetBeatmapRequest(int beatmapId)
|
||||
{
|
||||
this.beatmapId = beatmapId;
|
||||
}
|
||||
|
||||
protected override string Target => $@"beatmaps/{beatmapId}";
|
||||
}
|
||||
}
|
@ -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);
|
||||
/// <summary>
|
||||
/// The type of action executed on clicking this link.
|
||||
/// </summary>
|
||||
public LinkAction LinkAction { get; set; }
|
||||
|
||||
// 'protocol' -> 'https', 'http', 'osu', 'osump' etc.
|
||||
// 'content' -> everything after '<protocol>://'
|
||||
private Match getUrlMatch() => Regex.Match(Url, @"^(?<protocol>osu(?:mp)?|https?):\/\/(?<content>.*)");
|
||||
/// <summary>
|
||||
/// The argument necessary for the action specified by <see cref="LinkAction"/> to execute.
|
||||
/// <para>Usually a part of the URL.</para>
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ namespace osu.Game.Online.Chat
|
||||
{
|
||||
}
|
||||
|
||||
public List<MessageFormatter.Link> Links;
|
||||
public List<Link> Links;
|
||||
|
||||
public Message(long? id)
|
||||
{
|
||||
|
@ -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<Link>
|
||||
public enum LinkAction
|
||||
{
|
||||
External,
|
||||
OpenBeatmap,
|
||||
OpenBeatmapSet,
|
||||
OpenChannel,
|
||||
OpenEditorTimestamp,
|
||||
JoinMultiplayerMatch,
|
||||
Spectate,
|
||||
}
|
||||
|
||||
public class Link : IComparable<Link>
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ namespace osu.Game
|
||||
});
|
||||
}
|
||||
|
||||
internal void LoadMultiplayerLobby(int lobbyId)
|
||||
internal void JoinMultiplayerMatch(int matchId)
|
||||
{
|
||||
notifications.Post(new SimpleNotification
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -83,13 +83,13 @@ namespace osu.Game.Overlays.Chat
|
||||
|
||||
private Message message;
|
||||
private OsuSpriteText username;
|
||||
private OsuLinkFlowContainer<ChatLink> 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<ChatLink>(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<MessageFormatter.Link> linksToRemove = new List<MessageFormatter.Link>();
|
||||
List<Link> linksToRemove = new List<Link>();
|
||||
|
||||
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];
|
||||
|
@ -41,11 +41,6 @@ namespace osu.Game.Overlays
|
||||
|
||||
private readonly FocusedTextBox textbox;
|
||||
|
||||
/// <summary>
|
||||
/// The current OsuGame instance. Will be null for Tests.
|
||||
/// </summary>
|
||||
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);
|
||||
|
||||
|
@ -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<SpriteText> 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<SpriteText> 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";
|
||||
|
@ -268,9 +268,10 @@
|
||||
<Compile Include="Beatmaps\Formats\LegacyStoryboardDecoder.cs" />
|
||||
<Compile Include="Database\DatabaseContextFactory.cs" />
|
||||
<Compile Include="Database\IHasPrimaryKey.cs" />
|
||||
<Compile Include="Graphics\Containers\ChatFlowContainer.cs" />
|
||||
<Compile Include="Online\API\Requests\GetUserRequest.cs" />
|
||||
<Compile Include="Overlays\Profile\SupporterIcon.cs" />
|
||||
<Compile Include="Overlays\Settings\DangerousSettingsButton.cs" />
|
||||
<Compile Include="Graphics\Containers\OsuLinkFlowContainer.cs" />
|
||||
<Compile Include="Graphics\Sprites\OsuSpriteLink.cs" />
|
||||
<Compile Include="Graphics\UserInterface\HoverClickSounds.cs" />
|
||||
<Compile Include="Graphics\UserInterface\HoverSounds.cs" />
|
||||
@ -293,7 +294,6 @@
|
||||
<DependentUpon>20171209034410_AddRulesetInfoShortName.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Migrations\OsuDbContextModelSnapshot.cs" />
|
||||
<Compile Include="Online\API\Requests\GetBeatmapRequest.cs" />
|
||||
<Compile Include="Online\API\Requests\GetBeatmapSetRequest.cs" />
|
||||
<Compile Include="Online\Chat\ChatLink.cs" />
|
||||
<Compile Include="Online\Chat\MessageFormatter.cs" />
|
||||
@ -441,7 +441,6 @@
|
||||
<Compile Include="Online\API\Requests\SearchBeatmapSetsRequest.cs" />
|
||||
<Compile Include="Online\API\Requests\GetMessagesRequest.cs" />
|
||||
<Compile Include="Online\API\Requests\GetScoresRequest.cs" />
|
||||
<Compile Include="Online\API\Requests\GetUserRequest.cs" />
|
||||
<Compile Include="Online\API\Requests\GetUsersRequest.cs" />
|
||||
<Compile Include="Online\API\Requests\ListChannelsRequest.cs" />
|
||||
<Compile Include="Online\API\Requests\PostMessageRequest.cs" />
|
||||
|
Loading…
Reference in New Issue
Block a user