1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-13 08:32:57 +08:00

Merge branch 'master' into change-default-hover-click-sample

This commit is contained in:
Dean Herbert 2021-06-11 23:03:23 +09:00
commit 9c6c1dd237
20 changed files with 584 additions and 93 deletions

View File

@ -33,13 +33,13 @@ namespace osu.Game.Rulesets.Catch.Mods
private class MouseInputHelper : Drawable, IKeyBindingHandler<CatchAction>, IRequireHighFrequencyMousePosition
{
private readonly Catcher catcher;
private readonly CatcherArea catcherArea;
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
public MouseInputHelper(CatchPlayfield playfield)
{
catcher = playfield.CatcherArea.MovableCatcher;
catcherArea = playfield.CatcherArea;
RelativeSizeAxes = Axes.Both;
}
@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Catch.Mods
protected override bool OnMouseMove(MouseMoveEvent e)
{
catcher.UpdatePosition(e.MousePosition.X / DrawSize.X * CatchPlayfield.WIDTH);
catcherArea.SetCatcherPosition(e.MousePosition.X / DrawSize.X * CatchPlayfield.WIDTH);
return base.OnMouseMove(e);
}
}

View File

@ -10,7 +10,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Pooling;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Bindings;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
@ -26,7 +25,7 @@ using osuTK.Graphics;
namespace osu.Game.Rulesets.Catch.UI
{
public class Catcher : SkinReloadableDrawable, IKeyBindingHandler<CatchAction>
public class Catcher : SkinReloadableDrawable
{
/// <summary>
/// The default colour used to tint hyper-dash fruit, along with the moving catcher, its trail
@ -54,6 +53,11 @@ namespace osu.Game.Rulesets.Catch.UI
/// </summary>
public const double BASE_SPEED = 1.0;
/// <summary>
/// The current speed of the catcher.
/// </summary>
public double Speed => (Dashing ? 1 : 0.5) * BASE_SPEED * hyperDashModifier;
/// <summary>
/// The amount by which caught fruit should be offset from the plate surface to make them look visually "caught".
/// </summary>
@ -96,7 +100,7 @@ namespace osu.Game.Rulesets.Catch.UI
public bool Dashing
{
get => dashing;
protected set
set
{
if (value == dashing) return;
@ -106,6 +110,12 @@ namespace osu.Game.Rulesets.Catch.UI
}
}
public Direction VisualDirection
{
get => Scale.X > 0 ? Direction.Right : Direction.Left;
set => Scale = new Vector2((value == Direction.Right ? 1 : -1) * Math.Abs(Scale.X), Scale.Y);
}
/// <summary>
/// Width of the area that can be used to attempt catches during gameplay.
/// </summary>
@ -116,8 +126,6 @@ namespace osu.Game.Rulesets.Catch.UI
private Color4 hyperDashColour = DEFAULT_HYPER_DASH_COLOUR;
private Color4 hyperDashEndGlowColour = DEFAULT_HYPER_DASH_COLOUR;
private int currentDirection;
private double hyperDashModifier = 1;
private int hyperDashDirection;
private float hyperDashTargetPosition;
@ -315,55 +323,6 @@ namespace osu.Game.Rulesets.Catch.UI
}
}
public void UpdatePosition(float position)
{
position = Math.Clamp(position, 0, CatchPlayfield.WIDTH);
if (position == X)
return;
Scale = new Vector2(Math.Abs(Scale.X) * (position > X ? 1 : -1), Scale.Y);
X = position;
}
public bool OnPressed(CatchAction action)
{
switch (action)
{
case CatchAction.MoveLeft:
currentDirection--;
return true;
case CatchAction.MoveRight:
currentDirection++;
return true;
case CatchAction.Dash:
Dashing = true;
return true;
}
return false;
}
public void OnReleased(CatchAction action)
{
switch (action)
{
case CatchAction.MoveLeft:
currentDirection++;
break;
case CatchAction.MoveRight:
currentDirection--;
break;
case CatchAction.Dash:
Dashing = false;
break;
}
}
/// <summary>
/// Drop any fruit off the plate.
/// </summary>
@ -405,15 +364,6 @@ namespace osu.Game.Rulesets.Catch.UI
{
base.Update();
if (currentDirection == 0) return;
var direction = Math.Sign(currentDirection);
var dashModifier = Dashing ? 1 : 0.5;
var speed = BASE_SPEED * dashModifier * hyperDashModifier;
UpdatePosition((float)(X + direction * Clock.ElapsedFrameTime * speed));
// Correct overshooting.
if ((hyperDashDirection > 0 && hyperDashTargetPosition < X) ||
(hyperDashDirection < 0 && hyperDashTargetPosition > X))

View File

@ -1,8 +1,10 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Bindings;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects.Drawables;
@ -14,13 +16,20 @@ using osuTK;
namespace osu.Game.Rulesets.Catch.UI
{
public class CatcherArea : Container
public class CatcherArea : Container, IKeyBindingHandler<CatchAction>
{
public const float CATCHER_SIZE = 106.75f;
public readonly Catcher MovableCatcher;
private readonly CatchComboDisplay comboDisplay;
/// <summary>
/// <c>-1</c> when only left button is pressed.
/// <c>1</c> when only right button is pressed.
/// <c>0</c> when none or both left and right buttons are pressed.
/// </summary>
private int currentDirection;
public CatcherArea(Container<CaughtObject> droppedObjectContainer, BeatmapDifficulty difficulty = null)
{
Size = new Vector2(CatchPlayfield.WIDTH, CATCHER_SIZE);
@ -63,16 +72,73 @@ namespace osu.Game.Rulesets.Catch.UI
MovableCatcher.OnRevertResult(hitObject, result);
}
protected override void Update()
{
base.Update();
var replayState = (GetContainingInputManager().CurrentState as RulesetInputManagerInputState<CatchAction>)?.LastReplayState as CatchFramedReplayInputHandler.CatchReplayState;
SetCatcherPosition(
replayState?.CatcherX ??
(float)(MovableCatcher.X + MovableCatcher.Speed * currentDirection * Clock.ElapsedFrameTime));
}
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
var state = (GetContainingInputManager().CurrentState as RulesetInputManagerInputState<CatchAction>)?.LastReplayState as CatchFramedReplayInputHandler.CatchReplayState;
if (state?.CatcherX != null)
MovableCatcher.X = state.CatcherX.Value;
comboDisplay.X = MovableCatcher.X;
}
public void SetCatcherPosition(float X)
{
float lastPosition = MovableCatcher.X;
float newPosition = Math.Clamp(X, 0, CatchPlayfield.WIDTH);
MovableCatcher.X = newPosition;
if (lastPosition < newPosition)
MovableCatcher.VisualDirection = Direction.Right;
else if (lastPosition > newPosition)
MovableCatcher.VisualDirection = Direction.Left;
}
public bool OnPressed(CatchAction action)
{
switch (action)
{
case CatchAction.MoveLeft:
currentDirection--;
return true;
case CatchAction.MoveRight:
currentDirection++;
return true;
case CatchAction.Dash:
MovableCatcher.Dashing = true;
return true;
}
return false;
}
public void OnReleased(CatchAction action)
{
switch (action)
{
case CatchAction.MoveLeft:
currentDirection++;
break;
case CatchAction.MoveRight:
currentDirection--;
break;
case CatchAction.Dash:
MovableCatcher.Dashing = false;
break;
}
}
}
}

View File

@ -0,0 +1,11 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
namespace osu.Game.Rulesets.Catch.UI
{
public enum Direction
{
Right = 1,
Left = -1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 B

View File

@ -0,0 +1,240 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Chat;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
using osu.Game.Users;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Online
{
public class TestSceneMessageNotifier : OsuManualInputManagerTestScene
{
private User friend;
private Channel publicChannel;
private Channel privateMessageChannel;
private TestContainer testContainer;
private int messageIdCounter;
[SetUp]
public void Setup()
{
if (API is DummyAPIAccess daa)
{
daa.HandleRequest = dummyAPIHandleRequest;
}
friend = new User { Id = 0, Username = "Friend" };
publicChannel = new Channel { Id = 1, Name = "osu" };
privateMessageChannel = new Channel(friend) { Id = 2, Name = friend.Username, Type = ChannelType.PM };
Schedule(() =>
{
Child = testContainer = new TestContainer(new[] { publicChannel, privateMessageChannel })
{
RelativeSizeAxes = Axes.Both,
};
testContainer.ChatOverlay.Show();
});
}
private bool dummyAPIHandleRequest(APIRequest request)
{
switch (request)
{
case GetMessagesRequest messagesRequest:
messagesRequest.TriggerSuccess(new List<Message>(0));
return true;
case CreateChannelRequest createChannelRequest:
var apiChatChannel = new APIChatChannel
{
RecentMessages = new List<Message>(0),
ChannelID = (int)createChannelRequest.Channel.Id
};
createChannelRequest.TriggerSuccess(apiChatChannel);
return true;
case ListChannelsRequest listChannelsRequest:
listChannelsRequest.TriggerSuccess(new List<Channel>(1) { publicChannel });
return true;
case GetUpdatesRequest updatesRequest:
updatesRequest.TriggerSuccess(new GetUpdatesResponse
{
Messages = new List<Message>(0),
Presence = new List<Channel>(0)
});
return true;
case JoinChannelRequest joinChannelRequest:
joinChannelRequest.TriggerSuccess();
return true;
default:
return false;
}
}
[Test]
public void TestPublicChannelMention()
{
AddStep("switch to PMs", () => testContainer.ChannelManager.CurrentChannel.Value = privateMessageChannel);
AddStep("receive public message", () => receiveMessage(friend, publicChannel, "Hello everyone"));
AddAssert("no notifications fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 0);
AddStep("receive message containing mention", () => receiveMessage(friend, publicChannel, $"Hello {API.LocalUser.Value.Username.ToLowerInvariant()}!"));
AddAssert("1 notification fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 1);
AddStep("open notification overlay", () => testContainer.NotificationOverlay.Show());
AddStep("click notification", clickNotification<MessageNotifier.MentionNotification>);
AddAssert("chat overlay is open", () => testContainer.ChatOverlay.State.Value == Visibility.Visible);
AddAssert("public channel is selected", () => testContainer.ChannelManager.CurrentChannel.Value == publicChannel);
}
[Test]
public void TestPrivateMessageNotification()
{
AddStep("switch to public channel", () => testContainer.ChannelManager.CurrentChannel.Value = publicChannel);
AddStep("receive PM", () => receiveMessage(friend, privateMessageChannel, $"Hello {API.LocalUser.Value.Username}"));
AddAssert("1 notification fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 1);
AddStep("open notification overlay", () => testContainer.NotificationOverlay.Show());
AddStep("click notification", clickNotification<MessageNotifier.PrivateMessageNotification>);
AddAssert("chat overlay is open", () => testContainer.ChatOverlay.State.Value == Visibility.Visible);
AddAssert("PM channel is selected", () => testContainer.ChannelManager.CurrentChannel.Value == privateMessageChannel);
}
[Test]
public void TestNoNotificationWhenPMChannelOpen()
{
AddStep("switch to PMs", () => testContainer.ChannelManager.CurrentChannel.Value = privateMessageChannel);
AddStep("receive PM", () => receiveMessage(friend, privateMessageChannel, "you're reading this, right?"));
AddAssert("no notifications fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 0);
}
[Test]
public void TestNoNotificationWhenMentionedInOpenPublicChannel()
{
AddStep("switch to public channel", () => testContainer.ChannelManager.CurrentChannel.Value = publicChannel);
AddStep("receive mention", () => receiveMessage(friend, publicChannel, $"{API.LocalUser.Value.Username.ToUpperInvariant()} has been reading this"));
AddAssert("no notifications fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 0);
}
[Test]
public void TestNoNotificationOnSelfMention()
{
AddStep("switch to PM channel", () => testContainer.ChannelManager.CurrentChannel.Value = privateMessageChannel);
AddStep("receive self-mention", () => receiveMessage(API.LocalUser.Value, publicChannel, $"my name is {API.LocalUser.Value.Username}"));
AddAssert("no notifications fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 0);
}
[Test]
public void TestNoNotificationOnPMFromSelf()
{
AddStep("switch to public channel", () => testContainer.ChannelManager.CurrentChannel.Value = publicChannel);
AddStep("receive PM from self", () => receiveMessage(API.LocalUser.Value, privateMessageChannel, "hey hey"));
AddAssert("no notifications fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 0);
}
[Test]
public void TestNotificationsNotFiredTwice()
{
AddStep("switch to public channel", () => testContainer.ChannelManager.CurrentChannel.Value = publicChannel);
AddStep("receive same PM twice", () =>
{
var message = createMessage(friend, privateMessageChannel, "hey hey");
privateMessageChannel.AddNewMessages(message, message);
});
AddStep("open notification overlay", () => testContainer.NotificationOverlay.Show());
AddAssert("1 notification fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 1);
}
private void receiveMessage(User sender, Channel channel, string content) => channel.AddNewMessages(createMessage(sender, channel, content));
private Message createMessage(User sender, Channel channel, string content) => new Message(messageIdCounter++)
{
Content = content,
Sender = sender,
ChannelId = channel.Id
};
private void clickNotification<T>() where T : Notification
{
var notification = testContainer.NotificationOverlay.ChildrenOfType<T>().Single();
InputManager.MoveMouseTo(notification);
InputManager.Click(MouseButton.Left);
}
private class TestContainer : Container
{
[Cached]
public ChannelManager ChannelManager { get; } = new ChannelManager();
[Cached]
public NotificationOverlay NotificationOverlay { get; } = new NotificationOverlay
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
};
[Cached]
public ChatOverlay ChatOverlay { get; } = new ChatOverlay();
private readonly MessageNotifier messageNotifier = new MessageNotifier();
private readonly Channel[] channels;
public TestContainer(Channel[] channels)
{
this.channels = channels;
}
[BackgroundDependencyLoader]
private void load()
{
Children = new Drawable[]
{
ChannelManager,
ChatOverlay,
NotificationOverlay,
messageNotifier,
};
((BindableList<Channel>)ChannelManager.AvailableChannels).AddRange(channels);
foreach (var channel in channels)
ChannelManager.JoinChannel(channel);
}
}
}
}

View File

@ -61,6 +61,9 @@ namespace osu.Game.Configuration
SetDefault(OsuSetting.ShowOnlineExplicitContent, false);
SetDefault(OsuSetting.NotifyOnUsernameMentioned, true);
SetDefault(OsuSetting.NotifyOnPrivateMessage, true);
// Audio
SetDefault(OsuSetting.VolumeInactive, 0.25, 0, 1, 0.01);
@ -259,6 +262,8 @@ namespace osu.Game.Configuration
ScalingSizeY,
UIScale,
IntroSequence,
NotifyOnUsernameMentioned,
NotifyOnPrivateMessage,
UIHoldActivationDelay,
HitLighting,
MenuBackgroundSource,

View File

@ -11,11 +11,11 @@ namespace osu.Game.Online.API.Requests
{
public class CreateChannelRequest : APIRequest<APIChatChannel>
{
private readonly Channel channel;
public readonly Channel Channel;
public CreateChannelRequest(Channel channel)
{
this.channel = channel;
Channel = channel;
}
protected override WebRequest CreateWebRequest()
@ -24,7 +24,7 @@ namespace osu.Game.Online.API.Requests
req.Method = HttpMethod.Post;
req.AddParameter("type", $"{ChannelType.PM}");
req.AddParameter("target_id", $"{channel.Users.First().Id}");
req.AddParameter("target_id", $"{Channel.Users.First().Id}");
return req;
}

View File

@ -63,5 +63,7 @@ namespace osu.Game.Online.Chat
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
public override int GetHashCode() => Id.GetHashCode();
public override string ToString() => $"[{ChannelId}] ({Id}) {Sender}: {Content}";
}
}

View File

@ -0,0 +1,181 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. 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.Collections.Specialized;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Online.API;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
using osu.Game.Users;
namespace osu.Game.Online.Chat
{
/// <summary>
/// Component that handles creating and posting notifications for incoming messages.
/// </summary>
public class MessageNotifier : Component
{
[Resolved]
private NotificationOverlay notifications { get; set; }
[Resolved]
private ChatOverlay chatOverlay { get; set; }
[Resolved]
private ChannelManager channelManager { get; set; }
private Bindable<bool> notifyOnUsername;
private Bindable<bool> notifyOnPrivateMessage;
private readonly IBindable<User> localUser = new Bindable<User>();
private readonly IBindableList<Channel> joinedChannels = new BindableList<Channel>();
[BackgroundDependencyLoader]
private void load(OsuConfigManager config, IAPIProvider api)
{
notifyOnUsername = config.GetBindable<bool>(OsuSetting.NotifyOnUsernameMentioned);
notifyOnPrivateMessage = config.GetBindable<bool>(OsuSetting.NotifyOnPrivateMessage);
localUser.BindTo(api.LocalUser);
joinedChannels.BindTo(channelManager.JoinedChannels);
}
protected override void LoadComplete()
{
base.LoadComplete();
joinedChannels.BindCollectionChanged(channelsChanged, true);
}
private void channelsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (var channel in e.NewItems.Cast<Channel>())
channel.NewMessagesArrived += checkNewMessages;
break;
case NotifyCollectionChangedAction.Remove:
foreach (var channel in e.OldItems.Cast<Channel>())
channel.NewMessagesArrived -= checkNewMessages;
break;
}
}
private void checkNewMessages(IEnumerable<Message> messages)
{
if (!messages.Any())
return;
var channel = channelManager.JoinedChannels.SingleOrDefault(c => c.Id == messages.First().ChannelId);
if (channel == null)
return;
// Only send notifications, if ChatOverlay and the target channel aren't visible.
if (chatOverlay.IsPresent && channelManager.CurrentChannel.Value == channel)
return;
foreach (var message in messages.OrderByDescending(m => m.Id))
{
// ignore messages that already have been read
if (message.Id <= channel.LastReadId)
return;
if (message.Sender.Id == localUser.Value.Id)
continue;
// check for private messages first to avoid both posting two notifications about the same message
if (checkForPMs(channel, message))
continue;
checkForMentions(channel, message);
}
}
/// <summary>
/// Checks whether the user enabled private message notifications and whether specified <paramref name="message"/> is a direct message.
/// </summary>
/// <param name="channel">The channel associated to the <paramref name="message"/></param>
/// <param name="message">The message to be checked</param>
/// <returns>Whether a notification was fired.</returns>
private bool checkForPMs(Channel channel, Message message)
{
if (!notifyOnPrivateMessage.Value || channel.Type != ChannelType.PM)
return false;
notifications.Post(new PrivateMessageNotification(message.Sender.Username, channel));
return true;
}
private void checkForMentions(Channel channel, Message message)
{
if (!notifyOnUsername.Value || !checkContainsUsername(message.Content, localUser.Value.Username)) return;
notifications.Post(new MentionNotification(message.Sender.Username, channel));
}
/// <summary>
/// Checks if <paramref name="message"/> contains <paramref name="username"/>.
/// This will match against the case where underscores are used instead of spaces (which is how osu-stable handles usernames with spaces).
/// </summary>
private static bool checkContainsUsername(string message, string username) => message.Contains(username, StringComparison.OrdinalIgnoreCase) || message.Contains(username.Replace(' ', '_'), StringComparison.OrdinalIgnoreCase);
public class PrivateMessageNotification : OpenChannelNotification
{
public PrivateMessageNotification(string username, Channel channel)
: base(channel)
{
Icon = FontAwesome.Solid.Envelope;
Text = $"You received a private message from '{username}'. Click to read it!";
}
}
public class MentionNotification : OpenChannelNotification
{
public MentionNotification(string username, Channel channel)
: base(channel)
{
Icon = FontAwesome.Solid.At;
Text = $"Your name was mentioned in chat by '{username}'. Click to find out why!";
}
}
public abstract class OpenChannelNotification : SimpleNotification
{
protected OpenChannelNotification(Channel channel)
{
this.channel = channel;
}
private readonly Channel channel;
public override bool IsImportant => false;
[BackgroundDependencyLoader]
private void load(OsuColour colours, ChatOverlay chatOverlay, NotificationOverlay notificationOverlay, ChannelManager channelManager)
{
IconBackgound.Colour = colours.PurpleDark;
Activated = delegate
{
notificationOverlay.Hide();
chatOverlay.Show();
channelManager.CurrentChannel.Value = channel;
return true;
};
}
}
}
}

View File

@ -728,6 +728,7 @@ namespace osu.Game
var rankingsOverlay = loadComponentSingleFile(new RankingsOverlay(), overlayContent.Add, true);
loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal, true);
loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true);
loadComponentSingleFile(new MessageNotifier(), AddInternal, true);
loadComponentSingleFile(Settings = new SettingsOverlay { GetToolbarHeight = () => ToolbarOffset }, leftFloatingOverlayContent.Add, true);
var changelogOverlay = loadComponentSingleFile(new ChangelogOverlay(), overlayContent.Add, true);
loadComponentSingleFile(userProfile = new UserProfileOverlay(), overlayContent.Add, true);

View File

@ -6,18 +6,18 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osuTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Cursor;
using osu.Game.Online.Chat;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Utils;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Cursor;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.Chat;
using osuTK.Graphics;
namespace osu.Game.Overlays.Chat
{

View File

@ -0,0 +1,32 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Configuration;
namespace osu.Game.Overlays.Settings.Sections.Online
{
public class AlertsAndPrivacySettings : SettingsSubsection
{
protected override string Header => "Alerts and Privacy";
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
Children = new Drawable[]
{
new SettingsCheckbox
{
LabelText = "Show a notification when someone mentions your name",
Current = config.GetBindable<bool>(OsuSetting.NotifyOnUsernameMentioned)
},
new SettingsCheckbox
{
LabelText = "Show a notification when you receive a private message",
Current = config.GetBindable<bool>(OsuSetting.NotifyOnPrivateMessage)
},
};
}
}
}

View File

@ -21,6 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections
Children = new Drawable[]
{
new WebSettings(),
new AlertsAndPrivacySettings(),
new IntegrationSettings()
};
}

View File

@ -148,9 +148,9 @@ namespace osu.Game.Skinning
}
}
internal class LegacyOldStyleFill : LegacyHealthPiece
internal abstract class LegacyFill : LegacyHealthPiece
{
public LegacyOldStyleFill(ISkin skin)
protected LegacyFill(ISkin skin)
{
// required for sizing correctly..
var firstFrame = getTexture(skin, "colour-0");
@ -162,27 +162,29 @@ namespace osu.Game.Skinning
}
else
{
InternalChild = skin.GetAnimation("scorebar-colour", true, true, startAtCurrentTime: false, applyConfigFrameRate: true) ?? Drawable.Empty();
InternalChild = skin.GetAnimation("scorebar-colour", true, true, startAtCurrentTime: false, applyConfigFrameRate: true) ?? Empty();
Size = new Vector2(firstFrame.DisplayWidth, firstFrame.DisplayHeight);
}
Position = new Vector2(3, 10) * 1.6f;
Masking = true;
}
}
internal class LegacyNewStyleFill : LegacyHealthPiece
internal class LegacyOldStyleFill : LegacyFill
{
public LegacyOldStyleFill(ISkin skin)
: base(skin)
{
Position = new Vector2(3, 10) * 1.6f;
}
}
internal class LegacyNewStyleFill : LegacyFill
{
public LegacyNewStyleFill(ISkin skin)
: base(skin)
{
InternalChild = new Sprite
{
Texture = getTexture(skin, "colour"),
};
Size = InternalChild.Size;
Position = new Vector2(7.5f, 7.8f) * 1.6f;
Masking = true;
}
protected override void Update()