Path: blob/master/osu.Game/Overlays/Chat/DrawableChatUsername.cs
2264 views
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Framework.Screens; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Online.Multiplayer; using osu.Game.Resources.Localisation.Web; using osu.Game.Screens; using osu.Game.Screens.Play; using osu.Game.Users; using osuTK; using osuTK.Graphics; using ChatStrings = osu.Game.Localisation.ChatStrings; namespace osu.Game.Overlays.Chat { public partial class DrawableChatUsername : OsuClickableContainer, IHasContextMenu { public Action? ReportRequested; /// <summary> /// The primary colour to use for the username. /// </summary> public Color4 AccentColour { get; init; } /// <summary> /// If set to <see langword="false"/>, the username will be drawn as plain text in <see cref="AccentColour"/>. /// If set to <see langword="true"/>, the username will be drawn as black text inside a rounded rectangle in <see cref="AccentColour"/>. /// </summary> public bool Inverted { get; init; } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => colouredDrawable.ReceivePositionalInputAt(screenSpacePos); public float FontSize { set => drawableText.Font = OsuFont.GetFont(size: value, weight: FontWeight.Bold, italics: true); } public LocalisableString Text { set => drawableText.Text = value; } public override float Width { get => base.Width; set => base.Width = drawableText.MaxWidth = value; } [Resolved] private IAPIProvider api { get; set; } = null!; [Resolved] private OsuColour colours { get; set; } = null!; [Resolved] private MultiplayerClient? multiplayerClient { get; set; } [Resolved] private IPerformFromScreenRunner? performer { get; set; } [Resolved(canBeNull: true)] private ChannelManager? chatManager { get; set; } [Resolved(canBeNull: true)] private ChatOverlay? chatOverlay { get; set; } [Resolved(canBeNull: true)] private UserProfileOverlay? profileOverlay { get; set; } [Resolved] private Bindable<Channel?>? currentChannel { get; set; } [Resolved] private IDialogOverlay? dialogOverlay { get; set; } private readonly APIUser user; private readonly OsuSpriteText drawableText; private Drawable colouredDrawable = null!; public DrawableChatUsername(APIUser user) { this.user = user; Action = openUserProfile; drawableText = new TruncatingSpriteText { Shadow = false, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, }; } [BackgroundDependencyLoader] private void load() { if (!Inverted) { Add(colouredDrawable = drawableText); } else { Add(new Container { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, AutoSizeAxes = Axes.Both, Masking = true, CornerRadius = 4, EdgeEffect = new EdgeEffectParameters { Roundness = 1, Radius = 1, Colour = Color4.Black.Opacity(0.3f), Offset = new Vector2(0, 1), Type = EdgeEffectType.Shadow, }, Child = new Container { AutoSizeAxes = Axes.Both, Masking = true, CornerRadius = 4, Children = new[] { colouredDrawable = new Box { RelativeSizeAxes = Axes.Both, }, new Container { AutoSizeAxes = Axes.Both, Padding = new MarginPadding { Left = 4, Right = 4, Bottom = 1, Top = -2 }, Child = drawableText, } } } }); } } protected override void LoadComplete() { base.LoadComplete(); drawableText.Colour = colours.ChatBlue; colouredDrawable.Colour = AccentColour; } public MenuItem[] ContextMenuItems { get { if (user.Equals(APIUser.SYSTEM_USER)) return Array.Empty<MenuItem>(); if (user.Equals(api.LocalUser.Value)) return Array.Empty<MenuItem>(); List<MenuItem> items = new List<MenuItem>(); if (currentChannel?.Value != null) { items.Add(new OsuMenuItem(ChatStrings.MentionUser, MenuItemType.Standard, () => { currentChannel.Value.TextBoxMessage.Value += $"@{user.Username} "; })); } items.Add(new OsuMenuItem(ContextMenuStrings.ViewProfile, MenuItemType.Highlighted, openUserProfile)); items.Add(new OsuMenuItem(UsersStrings.CardSendMessage, MenuItemType.Standard, openUserChannel)); // We should probably be checking against an online state here. // But we can't use MetadataClient.GetPresence because we may not be requesting/receiving presences. // This isn't really too bad – worst case scenario the client will open spectator view and show the user as "offline". { items.Add(new OsuMenuItemSpacer()); items.Add(new OsuMenuItem(ContextMenuStrings.SpectatePlayer, MenuItemType.Standard, () => { performer?.PerformFromScreen(s => s.Push(new SoloSpectatorScreen(user))); })); if (multiplayerClient?.Room?.Users.All(u => u.UserID != user.Id) == true) { items.Add(new OsuMenuItem(ContextMenuStrings.InvitePlayer, MenuItemType.Standard, () => multiplayerClient.InvitePlayer(user.Id))); } } items.Add(new OsuMenuItemSpacer()); items.Add(new OsuMenuItem(UsersStrings.ReportButtonText, MenuItemType.Destructive, ReportRequested)); items.Add(api.Blocks.Any(b => b.TargetID == user.OnlineID) ? new OsuMenuItem(UsersStrings.BlocksButtonUnblock, MenuItemType.Standard, () => dialogOverlay?.Push(ConfirmBlockActionDialog.Unblock(user))) : new OsuMenuItem(UsersStrings.BlocksButtonBlock, MenuItemType.Destructive, () => dialogOverlay?.Push(ConfirmBlockActionDialog.Block(user)))); return items.ToArray(); } } private void openUserChannel() { chatManager?.OpenPrivateChannel(user); chatOverlay?.Show(); } private void openUserProfile() { profileOverlay?.ShowUser(user); } protected override bool OnHover(HoverEvent e) { colouredDrawable.FadeColour(AccentColour.Lighten(0.6f), 30, Easing.OutQuint); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { base.OnHoverLost(e); colouredDrawable.FadeColour(AccentColour, 800, Easing.OutQuint); } } }