mirror of
https://github.com/osukey/osukey.git
synced 2025-08-07 16:43:52 +09:00
Merge branch 'master' into refactor-scrolling-hoc-1
This commit is contained in:
@ -33,7 +33,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"ppy.localisationanalyser.tools": {
|
"ppy.localisationanalyser.tools": {
|
||||||
"version": "2021.524.0",
|
"version": "2021.608.0",
|
||||||
"commands": [
|
"commands": [
|
||||||
"localisation"
|
"localisation"
|
||||||
]
|
]
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
<Reference Include="Java.Interop" />
|
<Reference Include="Java.Interop" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.604.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.611.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.609.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.614.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
BIN
osu.Game.Tests/Resources/special-skin/scorebar-bg.png
Normal file
BIN
osu.Game.Tests/Resources/special-skin/scorebar-bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 250 B |
BIN
osu.Game.Tests/Resources/special-skin/scorebar-colour-0.png
Normal file
BIN
osu.Game.Tests/Resources/special-skin/scorebar-colour-0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
osu.Game.Tests/Resources/special-skin/scorebar-colour-1.png
Normal file
BIN
osu.Game.Tests/Resources/special-skin/scorebar-colour-1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
osu.Game.Tests/Resources/special-skin/scorebar-colour-2.png
Normal file
BIN
osu.Game.Tests/Resources/special-skin/scorebar-colour-2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
osu.Game.Tests/Resources/special-skin/scorebar-colour-3.png
Normal file
BIN
osu.Game.Tests/Resources/special-skin/scorebar-colour-3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
osu.Game.Tests/Resources/special-skin/scorebar-marker.png
Normal file
BIN
osu.Game.Tests/Resources/special-skin/scorebar-marker.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 126 B |
240
osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs
Normal file
240
osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,15 +2,22 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Platform;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Online.Leaderboards;
|
using osu.Game.Online.Leaderboards;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens.Select.Leaderboards;
|
using osu.Game.Screens.Select.Leaderboards;
|
||||||
|
using osu.Game.Tests.Resources;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -23,32 +30,98 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
[Cached]
|
[Cached]
|
||||||
private readonly DialogOverlay dialogOverlay;
|
private readonly DialogOverlay dialogOverlay;
|
||||||
|
|
||||||
|
private ScoreManager scoreManager;
|
||||||
|
|
||||||
|
private RulesetStore rulesetStore;
|
||||||
|
private BeatmapManager beatmapManager;
|
||||||
|
|
||||||
|
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||||
|
{
|
||||||
|
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||||
|
|
||||||
|
dependencies.Cache(rulesetStore = new RulesetStore(ContextFactory));
|
||||||
|
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get<AudioManager>(), Resources, dependencies.Get<GameHost>(), Beatmap.Default));
|
||||||
|
dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, null, ContextFactory));
|
||||||
|
|
||||||
|
return dependencies;
|
||||||
|
}
|
||||||
|
|
||||||
public TestSceneBeatmapLeaderboard()
|
public TestSceneBeatmapLeaderboard()
|
||||||
{
|
{
|
||||||
Add(dialogOverlay = new DialogOverlay
|
AddRange(new Drawable[]
|
||||||
|
{
|
||||||
|
dialogOverlay = new DialogOverlay
|
||||||
{
|
{
|
||||||
Depth = -1
|
Depth = -1
|
||||||
});
|
},
|
||||||
|
leaderboard = new FailableLeaderboard
|
||||||
Add(leaderboard = new FailableLeaderboard
|
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Size = new Vector2(550f, 450f),
|
Size = new Vector2(550f, 450f),
|
||||||
Scope = BeatmapLeaderboardScope.Global,
|
Scope = BeatmapLeaderboardScope.Global,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestLocalScoresDisplay()
|
||||||
|
{
|
||||||
|
BeatmapInfo beatmapInfo = null;
|
||||||
|
|
||||||
|
AddStep(@"Set scope", () => leaderboard.Scope = BeatmapLeaderboardScope.Local);
|
||||||
|
|
||||||
|
AddStep(@"Set beatmap", () =>
|
||||||
|
{
|
||||||
|
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
|
||||||
|
beatmapInfo = beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First();
|
||||||
|
|
||||||
|
leaderboard.Beatmap = beatmapInfo;
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep(@"New Scores", newScores);
|
clearScores();
|
||||||
|
checkCount(0);
|
||||||
|
|
||||||
|
loadMoreScores(() => beatmapInfo);
|
||||||
|
checkCount(10);
|
||||||
|
|
||||||
|
loadMoreScores(() => beatmapInfo);
|
||||||
|
checkCount(20);
|
||||||
|
|
||||||
|
clearScores();
|
||||||
|
checkCount(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGlobalScoresDisplay()
|
||||||
|
{
|
||||||
|
AddStep(@"Set scope", () => leaderboard.Scope = BeatmapLeaderboardScope.Global);
|
||||||
|
AddStep(@"New Scores", () => leaderboard.Scores = generateSampleScores(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPersonalBest()
|
||||||
|
{
|
||||||
AddStep(@"Show personal best", showPersonalBest);
|
AddStep(@"Show personal best", showPersonalBest);
|
||||||
|
AddStep("null personal best position", showPersonalBestWithNullPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPlaceholderStates()
|
||||||
|
{
|
||||||
AddStep(@"Empty Scores", () => leaderboard.SetRetrievalState(PlaceholderState.NoScores));
|
AddStep(@"Empty Scores", () => leaderboard.SetRetrievalState(PlaceholderState.NoScores));
|
||||||
AddStep(@"Network failure", () => leaderboard.SetRetrievalState(PlaceholderState.NetworkFailure));
|
AddStep(@"Network failure", () => leaderboard.SetRetrievalState(PlaceholderState.NetworkFailure));
|
||||||
AddStep(@"No supporter", () => leaderboard.SetRetrievalState(PlaceholderState.NotSupporter));
|
AddStep(@"No supporter", () => leaderboard.SetRetrievalState(PlaceholderState.NotSupporter));
|
||||||
AddStep(@"Not logged in", () => leaderboard.SetRetrievalState(PlaceholderState.NotLoggedIn));
|
AddStep(@"Not logged in", () => leaderboard.SetRetrievalState(PlaceholderState.NotLoggedIn));
|
||||||
AddStep(@"Unavailable", () => leaderboard.SetRetrievalState(PlaceholderState.Unavailable));
|
AddStep(@"Unavailable", () => leaderboard.SetRetrievalState(PlaceholderState.Unavailable));
|
||||||
AddStep(@"None selected", () => leaderboard.SetRetrievalState(PlaceholderState.NoneSelected));
|
AddStep(@"None selected", () => leaderboard.SetRetrievalState(PlaceholderState.NoneSelected));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBeatmapStates()
|
||||||
|
{
|
||||||
foreach (BeatmapSetOnlineStatus status in Enum.GetValues(typeof(BeatmapSetOnlineStatus)))
|
foreach (BeatmapSetOnlineStatus status in Enum.GetValues(typeof(BeatmapSetOnlineStatus)))
|
||||||
AddStep($"{status} beatmap", () => showBeatmapWithStatus(status));
|
AddStep($"{status} beatmap", () => showBeatmapWithStatus(status));
|
||||||
AddStep("null personal best position", showPersonalBestWithNullPosition);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showPersonalBestWithNullPosition()
|
private void showPersonalBestWithNullPosition()
|
||||||
@ -96,9 +169,26 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void newScores()
|
private void loadMoreScores(Func<BeatmapInfo> beatmapInfo)
|
||||||
{
|
{
|
||||||
var scores = new[]
|
AddStep(@"Load new scores via manager", () =>
|
||||||
|
{
|
||||||
|
foreach (var score in generateSampleScores(beatmapInfo()))
|
||||||
|
scoreManager.Import(score).Wait();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearScores()
|
||||||
|
{
|
||||||
|
AddStep("Clear all scores", () => scoreManager.Delete(scoreManager.GetAllUsableScores()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkCount(int expected) =>
|
||||||
|
AddUntilStep("Correct count displayed", () => leaderboard.ChildrenOfType<LeaderboardScore>().Count() == expected);
|
||||||
|
|
||||||
|
private static ScoreInfo[] generateSampleScores(BeatmapInfo beatmap)
|
||||||
|
{
|
||||||
|
return new[]
|
||||||
{
|
{
|
||||||
new ScoreInfo
|
new ScoreInfo
|
||||||
{
|
{
|
||||||
@ -107,6 +197,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
|
Beatmap = beatmap,
|
||||||
User = new User
|
User = new User
|
||||||
{
|
{
|
||||||
Id = 6602580,
|
Id = 6602580,
|
||||||
@ -125,6 +216,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
|
Beatmap = beatmap,
|
||||||
User = new User
|
User = new User
|
||||||
{
|
{
|
||||||
Id = 4608074,
|
Id = 4608074,
|
||||||
@ -143,6 +235,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
|
Beatmap = beatmap,
|
||||||
User = new User
|
User = new User
|
||||||
{
|
{
|
||||||
Id = 1014222,
|
Id = 1014222,
|
||||||
@ -161,6 +254,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
|
Beatmap = beatmap,
|
||||||
User = new User
|
User = new User
|
||||||
{
|
{
|
||||||
Id = 1541390,
|
Id = 1541390,
|
||||||
@ -179,6 +273,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
|
Beatmap = beatmap,
|
||||||
User = new User
|
User = new User
|
||||||
{
|
{
|
||||||
Id = 2243452,
|
Id = 2243452,
|
||||||
@ -197,6 +292,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
|
Beatmap = beatmap,
|
||||||
User = new User
|
User = new User
|
||||||
{
|
{
|
||||||
Id = 2705430,
|
Id = 2705430,
|
||||||
@ -215,6 +311,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
|
Beatmap = beatmap,
|
||||||
User = new User
|
User = new User
|
||||||
{
|
{
|
||||||
Id = 7151382,
|
Id = 7151382,
|
||||||
@ -233,6 +330,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
|
Beatmap = beatmap,
|
||||||
User = new User
|
User = new User
|
||||||
{
|
{
|
||||||
Id = 2051389,
|
Id = 2051389,
|
||||||
@ -251,6 +349,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
|
Beatmap = beatmap,
|
||||||
User = new User
|
User = new User
|
||||||
{
|
{
|
||||||
Id = 6169483,
|
Id = 6169483,
|
||||||
@ -269,6 +368,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
|
Beatmap = beatmap,
|
||||||
User = new User
|
User = new User
|
||||||
{
|
{
|
||||||
Id = 6702666,
|
Id = 6702666,
|
||||||
@ -281,8 +381,6 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
leaderboard.Scores = scores;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showBeatmapWithStatus(BeatmapSetOnlineStatus status)
|
private void showBeatmapWithStatus(BeatmapSetOnlineStatus status)
|
||||||
|
@ -61,6 +61,9 @@ namespace osu.Game.Configuration
|
|||||||
|
|
||||||
SetDefault(OsuSetting.ShowOnlineExplicitContent, false);
|
SetDefault(OsuSetting.ShowOnlineExplicitContent, false);
|
||||||
|
|
||||||
|
SetDefault(OsuSetting.NotifyOnUsernameMentioned, true);
|
||||||
|
SetDefault(OsuSetting.NotifyOnPrivateMessage, true);
|
||||||
|
|
||||||
// Audio
|
// Audio
|
||||||
SetDefault(OsuSetting.VolumeInactive, 0.25, 0, 1, 0.01);
|
SetDefault(OsuSetting.VolumeInactive, 0.25, 0, 1, 0.01);
|
||||||
|
|
||||||
@ -259,6 +262,8 @@ namespace osu.Game.Configuration
|
|||||||
ScalingSizeY,
|
ScalingSizeY,
|
||||||
UIScale,
|
UIScale,
|
||||||
IntroSequence,
|
IntroSequence,
|
||||||
|
NotifyOnUsernameMentioned,
|
||||||
|
NotifyOnPrivateMessage,
|
||||||
UIHoldActivationDelay,
|
UIHoldActivationDelay,
|
||||||
HitLighting,
|
HitLighting,
|
||||||
MenuBackgroundSource,
|
MenuBackgroundSource,
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
// 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.ComponentModel;
|
|
||||||
|
|
||||||
namespace osu.Game.Configuration
|
|
||||||
{
|
|
||||||
public enum RankingType
|
|
||||||
{
|
|
||||||
Local,
|
|
||||||
|
|
||||||
[Description("Global")]
|
|
||||||
Top,
|
|
||||||
|
|
||||||
[Description("Selected Mods")]
|
|
||||||
SelectedMod,
|
|
||||||
Friends,
|
|
||||||
Country
|
|
||||||
}
|
|
||||||
}
|
|
@ -19,7 +19,7 @@ namespace osu.Game.Graphics.Containers
|
|||||||
|
|
||||||
protected virtual HoverClickSounds CreateHoverClickSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet);
|
protected virtual HoverClickSounds CreateHoverClickSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet);
|
||||||
|
|
||||||
public OsuClickableContainer(HoverSampleSet sampleSet = HoverSampleSet.Normal)
|
public OsuClickableContainer(HoverSampleSet sampleSet = HoverSampleSet.Default)
|
||||||
{
|
{
|
||||||
this.sampleSet = sampleSet;
|
this.sampleSet = sampleSet;
|
||||||
}
|
}
|
||||||
|
@ -107,10 +107,10 @@ namespace osu.Game.Graphics.Containers
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool playedPopInSound;
|
|
||||||
|
|
||||||
protected override void UpdateState(ValueChangedEvent<Visibility> state)
|
protected override void UpdateState(ValueChangedEvent<Visibility> state)
|
||||||
{
|
{
|
||||||
|
bool didChange = state.NewValue != state.OldValue;
|
||||||
|
|
||||||
switch (state.NewValue)
|
switch (state.NewValue)
|
||||||
{
|
{
|
||||||
case Visibility.Visible:
|
case Visibility.Visible:
|
||||||
@ -121,18 +121,15 @@ namespace osu.Game.Graphics.Containers
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (didChange)
|
||||||
samplePopIn?.Play();
|
samplePopIn?.Play();
|
||||||
playedPopInSound = true;
|
|
||||||
|
|
||||||
if (BlockScreenWideMouse && DimMainContent) game?.AddBlockingOverlay(this);
|
if (BlockScreenWideMouse && DimMainContent) game?.AddBlockingOverlay(this);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Visibility.Hidden:
|
case Visibility.Hidden:
|
||||||
if (playedPopInSound)
|
if (didChange)
|
||||||
{
|
|
||||||
samplePopOut?.Play();
|
samplePopOut?.Play();
|
||||||
playedPopInSound = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BlockScreenWideMouse) game?.RemoveBlockingOverlay(this);
|
if (BlockScreenWideMouse) game?.RemoveBlockingOverlay(this);
|
||||||
break;
|
break;
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Sample;
|
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -23,9 +22,6 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
private const int text_size = 17;
|
private const int text_size = 17;
|
||||||
private const int transition_length = 80;
|
private const int transition_length = 80;
|
||||||
|
|
||||||
private Sample sampleClick;
|
|
||||||
private Sample sampleHover;
|
|
||||||
|
|
||||||
private TextContainer text;
|
private TextContainer text;
|
||||||
|
|
||||||
public DrawableOsuMenuItem(MenuItem item)
|
public DrawableOsuMenuItem(MenuItem item)
|
||||||
@ -36,12 +32,11 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(AudioManager audio)
|
private void load(AudioManager audio)
|
||||||
{
|
{
|
||||||
sampleHover = audio.Samples.Get(@"UI/generic-hover");
|
|
||||||
sampleClick = audio.Samples.Get(@"UI/generic-select");
|
|
||||||
|
|
||||||
BackgroundColour = Color4.Transparent;
|
BackgroundColour = Color4.Transparent;
|
||||||
BackgroundColourHover = Color4Extensions.FromHex(@"172023");
|
BackgroundColourHover = Color4Extensions.FromHex(@"172023");
|
||||||
|
|
||||||
|
AddInternal(new HoverClickSounds());
|
||||||
|
|
||||||
updateTextColour();
|
updateTextColour();
|
||||||
|
|
||||||
Item.Action.BindDisabledChanged(_ => updateState(), true);
|
Item.Action.BindDisabledChanged(_ => updateState(), true);
|
||||||
@ -84,7 +79,6 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
if (IsHovered && !Item.Action.Disabled)
|
if (IsHovered && !Item.Action.Disabled)
|
||||||
{
|
{
|
||||||
sampleHover.Play();
|
|
||||||
text.BoldText.FadeIn(transition_length, Easing.OutQuint);
|
text.BoldText.FadeIn(transition_length, Easing.OutQuint);
|
||||||
text.NormalText.FadeOut(transition_length, Easing.OutQuint);
|
text.NormalText.FadeOut(transition_length, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
@ -95,12 +89,6 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnClick(ClickEvent e)
|
|
||||||
{
|
|
||||||
sampleClick.Play();
|
|
||||||
return base.OnClick(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected sealed override Drawable CreateContent() => text = CreateTextContainer();
|
protected sealed override Drawable CreateContent() => text = CreateTextContainer();
|
||||||
protected virtual TextContainer CreateTextContainer() => new TextContainer();
|
protected virtual TextContainer CreateTextContainer() => new TextContainer();
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
/// Array of button codes which should trigger the click sound.
|
/// Array of button codes which should trigger the click sound.
|
||||||
/// If this optional parameter is omitted or set to <code>null</code>, the click sound will only be played on left click.
|
/// If this optional parameter is omitted or set to <code>null</code>, the click sound will only be played on left click.
|
||||||
/// </param>
|
/// </param>
|
||||||
public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal, MouseButton[] buttons = null)
|
public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Default, MouseButton[] buttons = null)
|
||||||
: base(sampleSet)
|
: base(sampleSet)
|
||||||
{
|
{
|
||||||
this.buttons = buttons ?? new[] { MouseButton.Left };
|
this.buttons = buttons ?? new[] { MouseButton.Left };
|
||||||
@ -45,7 +45,8 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(AudioManager audio)
|
private void load(AudioManager audio)
|
||||||
{
|
{
|
||||||
sampleClick = audio.Samples.Get($@"UI/generic-select{SampleSet.GetDescription()}");
|
sampleClick = audio.Samples.Get($@"UI/{SampleSet.GetDescription()}-select")
|
||||||
|
?? audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
25
osu.Game/Graphics/UserInterface/HoverSampleSet.cs
Normal file
25
osu.Game/Graphics/UserInterface/HoverSampleSet.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// 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.ComponentModel;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.UserInterface
|
||||||
|
{
|
||||||
|
public enum HoverSampleSet
|
||||||
|
{
|
||||||
|
[Description("default")]
|
||||||
|
Default,
|
||||||
|
|
||||||
|
[Description("button")]
|
||||||
|
Button,
|
||||||
|
|
||||||
|
[Description("softer")]
|
||||||
|
Soft,
|
||||||
|
|
||||||
|
[Description("toolbar")]
|
||||||
|
Toolbar,
|
||||||
|
|
||||||
|
[Description("songselect")]
|
||||||
|
SongSelect
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.ComponentModel;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
@ -22,7 +21,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
protected readonly HoverSampleSet SampleSet;
|
protected readonly HoverSampleSet SampleSet;
|
||||||
|
|
||||||
public HoverSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal)
|
public HoverSounds(HoverSampleSet sampleSet = HoverSampleSet.Default)
|
||||||
{
|
{
|
||||||
SampleSet = sampleSet;
|
SampleSet = sampleSet;
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
@ -31,7 +30,8 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(AudioManager audio, SessionStatics statics)
|
private void load(AudioManager audio, SessionStatics statics)
|
||||||
{
|
{
|
||||||
sampleHover = audio.Samples.Get($@"UI/generic-hover{SampleSet.GetDescription()}");
|
sampleHover = audio.Samples.Get($@"UI/{SampleSet.GetDescription()}-hover")
|
||||||
|
?? audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-hover");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PlayHoverSample()
|
public override void PlayHoverSample()
|
||||||
@ -40,22 +40,4 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
sampleHover.Play();
|
sampleHover.Play();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum HoverSampleSet
|
|
||||||
{
|
|
||||||
[Description("")]
|
|
||||||
Loud,
|
|
||||||
|
|
||||||
[Description("-soft")]
|
|
||||||
Normal,
|
|
||||||
|
|
||||||
[Description("-softer")]
|
|
||||||
Soft,
|
|
||||||
|
|
||||||
[Description("-toolbar")]
|
|
||||||
Toolbar,
|
|
||||||
|
|
||||||
[Description("-songselect")]
|
|
||||||
SongSelect
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
private readonly Box hover;
|
private readonly Box hover;
|
||||||
|
|
||||||
public OsuAnimatedButton()
|
public OsuAnimatedButton()
|
||||||
|
: base(HoverSampleSet.Button)
|
||||||
{
|
{
|
||||||
base.Content.Add(content = new Container
|
base.Content.Add(content = new Container
|
||||||
{
|
{
|
||||||
|
@ -49,7 +49,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
protected Box Background;
|
protected Box Background;
|
||||||
protected SpriteText SpriteText;
|
protected SpriteText SpriteText;
|
||||||
|
|
||||||
public OsuButton(HoverSampleSet? hoverSounds = HoverSampleSet.Loud)
|
public OsuButton(HoverSampleSet? hoverSounds = HoverSampleSet.Button)
|
||||||
{
|
{
|
||||||
Height = 40;
|
Height = 40;
|
||||||
|
|
||||||
|
@ -7,17 +7,17 @@ namespace osu.Game.Localisation
|
|||||||
{
|
{
|
||||||
public static class ChatStrings
|
public static class ChatStrings
|
||||||
{
|
{
|
||||||
private const string prefix = "osu.Game.Localisation.Chat";
|
private const string prefix = @"osu.Game.Localisation.Chat";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "chat"
|
/// "chat"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "chat");
|
public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"chat");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "join the real-time discussion"
|
/// "join the real-time discussion"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "join the real-time discussion");
|
public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"join the real-time discussion");
|
||||||
|
|
||||||
private static string getKey(string key) => $"{prefix}:{key}";
|
private static string getKey(string key) => $"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,12 @@ namespace osu.Game.Localisation
|
|||||||
{
|
{
|
||||||
public static class CommonStrings
|
public static class CommonStrings
|
||||||
{
|
{
|
||||||
private const string prefix = "osu.Game.Localisation.Common";
|
private const string prefix = @"osu.Game.Localisation.Common";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Cancel"
|
/// "Cancel"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString Cancel => new TranslatableString(getKey("cancel"), "Cancel");
|
public static LocalisableString Cancel => new TranslatableString(getKey(@"cancel"), @"Cancel");
|
||||||
|
|
||||||
private static string getKey(string key) => $"{prefix}:{key}";
|
private static string getKey(string key) => $"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,10 @@ namespace osu.Game.Localisation
|
|||||||
{
|
{
|
||||||
public enum Language
|
public enum Language
|
||||||
{
|
{
|
||||||
[Description("English")]
|
[Description(@"English")]
|
||||||
en,
|
en,
|
||||||
|
|
||||||
[Description("日本語")]
|
[Description(@"日本語")]
|
||||||
ja
|
ja
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,17 +7,17 @@ namespace osu.Game.Localisation
|
|||||||
{
|
{
|
||||||
public static class NotificationsStrings
|
public static class NotificationsStrings
|
||||||
{
|
{
|
||||||
private const string prefix = "osu.Game.Localisation.Notifications";
|
private const string prefix = @"osu.Game.Localisation.Notifications";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "notifications"
|
/// "notifications"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "notifications");
|
public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"notifications");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "waiting for 'ya"
|
/// "waiting for 'ya"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "waiting for 'ya");
|
public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"waiting for 'ya");
|
||||||
|
|
||||||
private static string getKey(string key) => $"{prefix}:{key}";
|
private static string getKey(string key) => $"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
|
@ -7,17 +7,17 @@ namespace osu.Game.Localisation
|
|||||||
{
|
{
|
||||||
public static class NowPlayingStrings
|
public static class NowPlayingStrings
|
||||||
{
|
{
|
||||||
private const string prefix = "osu.Game.Localisation.NowPlaying";
|
private const string prefix = @"osu.Game.Localisation.NowPlaying";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "now playing"
|
/// "now playing"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "now playing");
|
public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"now playing");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "manage the currently playing track"
|
/// "manage the currently playing track"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "manage the currently playing track");
|
public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"manage the currently playing track");
|
||||||
|
|
||||||
private static string getKey(string key) => $"{prefix}:{key}";
|
private static string getKey(string key) => $"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Resources;
|
using System.Resources;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
@ -34,7 +35,29 @@ namespace osu.Game.Localisation
|
|||||||
lock (resourceManagers)
|
lock (resourceManagers)
|
||||||
{
|
{
|
||||||
if (!resourceManagers.TryGetValue(ns, out var manager))
|
if (!resourceManagers.TryGetValue(ns, out var manager))
|
||||||
resourceManagers[ns] = manager = new ResourceManager(ns, GetType().Assembly);
|
{
|
||||||
|
var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||||
|
|
||||||
|
// Traverse backwards through periods in the namespace to find a matching assembly.
|
||||||
|
string assemblyName = ns;
|
||||||
|
|
||||||
|
while (!string.IsNullOrEmpty(assemblyName))
|
||||||
|
{
|
||||||
|
var matchingAssembly = loadedAssemblies.FirstOrDefault(asm => asm.GetName().Name == assemblyName);
|
||||||
|
|
||||||
|
if (matchingAssembly != null)
|
||||||
|
{
|
||||||
|
resourceManagers[ns] = manager = new ResourceManager(ns, matchingAssembly);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lastIndex = Math.Max(0, assemblyName.LastIndexOf('.'));
|
||||||
|
assemblyName = assemblyName.Substring(0, lastIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (manager == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -7,17 +7,17 @@ namespace osu.Game.Localisation
|
|||||||
{
|
{
|
||||||
public static class SettingsStrings
|
public static class SettingsStrings
|
||||||
{
|
{
|
||||||
private const string prefix = "osu.Game.Localisation.Settings";
|
private const string prefix = @"osu.Game.Localisation.Settings";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "settings"
|
/// "settings"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "settings");
|
public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"settings");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "change the way osu! behaves"
|
/// "change the way osu! behaves"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "change the way osu! behaves");
|
public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"change the way osu! behaves");
|
||||||
|
|
||||||
private static string getKey(string key) => $"{prefix}:{key}";
|
private static string getKey(string key) => $"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
|
@ -11,11 +11,11 @@ namespace osu.Game.Online.API.Requests
|
|||||||
{
|
{
|
||||||
public class CreateChannelRequest : APIRequest<APIChatChannel>
|
public class CreateChannelRequest : APIRequest<APIChatChannel>
|
||||||
{
|
{
|
||||||
private readonly Channel channel;
|
public readonly Channel Channel;
|
||||||
|
|
||||||
public CreateChannelRequest(Channel channel)
|
public CreateChannelRequest(Channel channel)
|
||||||
{
|
{
|
||||||
this.channel = channel;
|
Channel = channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override WebRequest CreateWebRequest()
|
protected override WebRequest CreateWebRequest()
|
||||||
@ -24,7 +24,7 @@ namespace osu.Game.Online.API.Requests
|
|||||||
req.Method = HttpMethod.Post;
|
req.Method = HttpMethod.Post;
|
||||||
|
|
||||||
req.AddParameter("type", $"{ChannelType.PM}");
|
req.AddParameter("type", $"{ChannelType.PM}");
|
||||||
req.AddParameter("target_id", $"{channel.Users.First().Id}");
|
req.AddParameter("target_id", $"{Channel.Users.First().Id}");
|
||||||
|
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
@ -63,5 +63,7 @@ namespace osu.Game.Online.Chat
|
|||||||
|
|
||||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||||
public override int GetHashCode() => Id.GetHashCode();
|
public override int GetHashCode() => Id.GetHashCode();
|
||||||
|
|
||||||
|
public override string ToString() => $"[{ChannelId}] ({Id}) {Sender}: {Content}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
181
osu.Game/Online/Chat/MessageNotifier.cs
Normal file
181
osu.Game/Online/Chat/MessageNotifier.cs
Normal 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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -44,9 +44,9 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
|
|
||||||
protected override Container<Drawable> Content => content;
|
protected override Container<Drawable> Content => content;
|
||||||
|
|
||||||
private IEnumerable<TScoreInfo> scores;
|
private ICollection<TScoreInfo> scores;
|
||||||
|
|
||||||
public IEnumerable<TScoreInfo> Scores
|
public ICollection<TScoreInfo> Scores
|
||||||
{
|
{
|
||||||
get => scores;
|
get => scores;
|
||||||
set
|
set
|
||||||
@ -126,7 +126,7 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
scope = value;
|
scope = value;
|
||||||
UpdateScores();
|
RefreshScores();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +154,7 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
case PlaceholderState.NetworkFailure:
|
case PlaceholderState.NetworkFailure:
|
||||||
replacePlaceholder(new ClickablePlaceholder(@"Couldn't fetch scores!", FontAwesome.Solid.Sync)
|
replacePlaceholder(new ClickablePlaceholder(@"Couldn't fetch scores!", FontAwesome.Solid.Sync)
|
||||||
{
|
{
|
||||||
Action = UpdateScores,
|
Action = RefreshScores
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -254,8 +254,6 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
apiState.BindValueChanged(onlineStateChanged, true);
|
apiState.BindValueChanged(onlineStateChanged, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RefreshScores() => UpdateScores();
|
|
||||||
|
|
||||||
private APIRequest getScoresRequest;
|
private APIRequest getScoresRequest;
|
||||||
|
|
||||||
protected abstract bool IsOnlineScope { get; }
|
protected abstract bool IsOnlineScope { get; }
|
||||||
@ -267,12 +265,14 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
case APIState.Online:
|
case APIState.Online:
|
||||||
case APIState.Offline:
|
case APIState.Offline:
|
||||||
if (IsOnlineScope)
|
if (IsOnlineScope)
|
||||||
UpdateScores();
|
RefreshScores();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
public void RefreshScores() => Scheduler.AddOnce(UpdateScores);
|
||||||
|
|
||||||
protected void UpdateScores()
|
protected void UpdateScores()
|
||||||
{
|
{
|
||||||
// don't display any scores or placeholder until the first Scores_Set has been called.
|
// don't display any scores or placeholder until the first Scores_Set has been called.
|
||||||
@ -290,7 +290,7 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
|
|
||||||
getScoresRequest = FetchScores(scores => Schedule(() =>
|
getScoresRequest = FetchScores(scores => Schedule(() =>
|
||||||
{
|
{
|
||||||
Scores = scores;
|
Scores = scores.ToArray();
|
||||||
PlaceholderState = Scores.Any() ? PlaceholderState.Successful : PlaceholderState.NoScores;
|
PlaceholderState = Scores.Any() ? PlaceholderState.Successful : PlaceholderState.NoScores;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -728,6 +728,7 @@ namespace osu.Game
|
|||||||
var rankingsOverlay = loadComponentSingleFile(new RankingsOverlay(), overlayContent.Add, true);
|
var rankingsOverlay = loadComponentSingleFile(new RankingsOverlay(), overlayContent.Add, true);
|
||||||
loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal, true);
|
loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal, true);
|
||||||
loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true);
|
loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true);
|
||||||
|
loadComponentSingleFile(new MessageNotifier(), AddInternal, true);
|
||||||
loadComponentSingleFile(Settings = new SettingsOverlay { GetToolbarHeight = () => ToolbarOffset }, leftFloatingOverlayContent.Add, true);
|
loadComponentSingleFile(Settings = new SettingsOverlay { GetToolbarHeight = () => ToolbarOffset }, leftFloatingOverlayContent.Add, true);
|
||||||
var changelogOverlay = loadComponentSingleFile(new ChangelogOverlay(), overlayContent.Add, true);
|
var changelogOverlay = loadComponentSingleFile(new ChangelogOverlay(), overlayContent.Add, true);
|
||||||
loadComponentSingleFile(userProfile = new UserProfileOverlay(), overlayContent.Add, true);
|
loadComponentSingleFile(userProfile = new UserProfileOverlay(), overlayContent.Add, true);
|
||||||
|
@ -8,7 +8,6 @@ using System.Threading.Tasks;
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Sample;
|
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
@ -25,8 +24,6 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
public readonly Bindable<APIChangelogBuild> Current = new Bindable<APIChangelogBuild>();
|
public readonly Bindable<APIChangelogBuild> Current = new Bindable<APIChangelogBuild>();
|
||||||
|
|
||||||
private Sample sampleBack;
|
|
||||||
|
|
||||||
private List<APIChangelogBuild> builds;
|
private List<APIChangelogBuild> builds;
|
||||||
|
|
||||||
protected List<APIUpdateStream> Streams;
|
protected List<APIUpdateStream> Streams;
|
||||||
@ -41,8 +38,6 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
Header.Build.BindTarget = Current;
|
Header.Build.BindTarget = Current;
|
||||||
|
|
||||||
sampleBack = audio.Samples.Get(@"UI/generic-select-soft");
|
|
||||||
|
|
||||||
Current.BindValueChanged(e =>
|
Current.BindValueChanged(e =>
|
||||||
{
|
{
|
||||||
if (e.NewValue != null)
|
if (e.NewValue != null)
|
||||||
@ -108,7 +103,6 @@ namespace osu.Game.Overlays
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Current.Value = null;
|
Current.Value = null;
|
||||||
sampleBack?.Play();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -6,18 +6,18 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osuTK.Graphics;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
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.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Utils;
|
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.Graphics.Sprites;
|
||||||
|
using osu.Game.Online.Chat;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Chat
|
namespace osu.Game.Overlays.Chat
|
||||||
{
|
{
|
||||||
|
@ -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)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new WebSettings(),
|
new WebSettings(),
|
||||||
|
new AlertsAndPrivacySettings(),
|
||||||
new IntegrationSettings()
|
new IntegrationSettings()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,8 @@ namespace osu.Game.Screens.Select.Leaderboards
|
|||||||
|
|
||||||
private IBindable<WeakReference<ScoreInfo>> itemRemoved;
|
private IBindable<WeakReference<ScoreInfo>> itemRemoved;
|
||||||
|
|
||||||
|
private IBindable<WeakReference<ScoreInfo>> itemAdded;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether to apply the game's currently selected mods as a filter when retrieving scores.
|
/// Whether to apply the game's currently selected mods as a filter when retrieving scores.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -85,6 +87,9 @@ namespace osu.Game.Screens.Select.Leaderboards
|
|||||||
|
|
||||||
itemRemoved = scoreManager.ItemRemoved.GetBoundCopy();
|
itemRemoved = scoreManager.ItemRemoved.GetBoundCopy();
|
||||||
itemRemoved.BindValueChanged(onScoreRemoved);
|
itemRemoved.BindValueChanged(onScoreRemoved);
|
||||||
|
|
||||||
|
itemAdded = scoreManager.ItemUpdated.GetBoundCopy();
|
||||||
|
itemAdded.BindValueChanged(onScoreAdded);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Reset()
|
protected override void Reset()
|
||||||
@ -93,7 +98,25 @@ namespace osu.Game.Screens.Select.Leaderboards
|
|||||||
TopScore = null;
|
TopScore = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onScoreRemoved(ValueChangedEvent<WeakReference<ScoreInfo>> score) => Schedule(RefreshScores);
|
private void onScoreRemoved(ValueChangedEvent<WeakReference<ScoreInfo>> score) =>
|
||||||
|
scoreStoreChanged(score);
|
||||||
|
|
||||||
|
private void onScoreAdded(ValueChangedEvent<WeakReference<ScoreInfo>> score) =>
|
||||||
|
scoreStoreChanged(score);
|
||||||
|
|
||||||
|
private void scoreStoreChanged(ValueChangedEvent<WeakReference<ScoreInfo>> score)
|
||||||
|
{
|
||||||
|
if (Scope != BeatmapLeaderboardScope.Local)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (score.NewValue.TryGetTarget(out var scoreInfo))
|
||||||
|
{
|
||||||
|
if (Beatmap?.ID != scoreInfo.BeatmapInfoID)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefreshScores();
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool IsOnlineScope => Scope != BeatmapLeaderboardScope.Local;
|
protected override bool IsOnlineScope => Scope != BeatmapLeaderboardScope.Local;
|
||||||
|
|
||||||
|
@ -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..
|
// required for sizing correctly..
|
||||||
var firstFrame = getTexture(skin, "colour-0");
|
var firstFrame = getTexture(skin, "colour-0");
|
||||||
@ -162,27 +162,29 @@ namespace osu.Game.Skinning
|
|||||||
}
|
}
|
||||||
else
|
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);
|
Size = new Vector2(firstFrame.DisplayWidth, firstFrame.DisplayHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
Position = new Vector2(3, 10) * 1.6f;
|
|
||||||
Masking = true;
|
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)
|
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;
|
Position = new Vector2(7.5f, 7.8f) * 1.6f;
|
||||||
Masking = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input;
|
|
||||||
using osu.Framework.Testing.Input;
|
using osu.Framework.Testing.Input;
|
||||||
using osu.Game.Graphics.Cursor;
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
@ -49,7 +48,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
InputManager = new ManualInputManager
|
InputManager = new ManualInputManager
|
||||||
{
|
{
|
||||||
UseParentInput = true,
|
UseParentInput = true,
|
||||||
Child = new PlatformActionContainer().WithChild(mainContent)
|
Child = mainContent
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
|
@ -30,12 +30,12 @@
|
|||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
||||||
<PackageReference Include="Microsoft.NETCore.Targets" Version="3.1.0" />
|
<PackageReference Include="Microsoft.NETCore.Targets" Version="3.1.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="ppy.LocalisationAnalyser" Version="2021.525.0">
|
<PackageReference Include="ppy.LocalisationAnalyser" Version="2021.608.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2021.609.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2021.614.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.604.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.611.0" />
|
||||||
<PackageReference Include="Sentry" Version="3.4.0" />
|
<PackageReference Include="Sentry" Version="3.4.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.28.2" />
|
<PackageReference Include="SharpCompress" Version="0.28.2" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
|
@ -70,8 +70,8 @@
|
|||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.609.0" />
|
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.614.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.604.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.611.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
@ -93,7 +93,7 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2021.609.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2021.614.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.28.2" />
|
<PackageReference Include="SharpCompress" Version="0.28.2" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||||
|
Reference in New Issue
Block a user