mirror of
https://github.com/osukey/osukey.git
synced 2025-08-02 22:26:41 +09:00
Merge branch 'master' into skin-editor-closest-anchor
This commit is contained in:
@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Lists;
|
||||
@ -66,6 +67,7 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
/// </summary>
|
||||
/// <param name="time">The time to find the difficulty control point at.</param>
|
||||
/// <returns>The difficulty control point.</returns>
|
||||
[NotNull]
|
||||
public DifficultyControlPoint DifficultyPointAt(double time) => binarySearchWithFallback(DifficultyPoints, time, DifficultyControlPoint.DEFAULT);
|
||||
|
||||
/// <summary>
|
||||
@ -73,6 +75,7 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
/// </summary>
|
||||
/// <param name="time">The time to find the effect control point at.</param>
|
||||
/// <returns>The effect control point.</returns>
|
||||
[NotNull]
|
||||
public EffectControlPoint EffectPointAt(double time) => binarySearchWithFallback(EffectPoints, time, EffectControlPoint.DEFAULT);
|
||||
|
||||
/// <summary>
|
||||
@ -80,6 +83,7 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
/// </summary>
|
||||
/// <param name="time">The time to find the sound control point at.</param>
|
||||
/// <returns>The sound control point.</returns>
|
||||
[NotNull]
|
||||
public SampleControlPoint SamplePointAt(double time) => binarySearchWithFallback(SamplePoints, time, SamplePoints.Count > 0 ? SamplePoints[0] : SampleControlPoint.DEFAULT);
|
||||
|
||||
/// <summary>
|
||||
@ -87,6 +91,7 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
/// </summary>
|
||||
/// <param name="time">The time to find the timing control point at.</param>
|
||||
/// <returns>The timing control point.</returns>
|
||||
[NotNull]
|
||||
public TimingControlPoint TimingPointAt(double time) => binarySearchWithFallback(TimingPoints, time, TimingPoints.Count > 0 ? TimingPoints[0] : TimingControlPoint.DEFAULT);
|
||||
|
||||
/// <summary>
|
||||
|
@ -101,10 +101,20 @@ namespace osu.Game.Beatmaps
|
||||
/// Rulesets ordered descending by their respective recommended difficulties.
|
||||
/// The currently selected ruleset will always be first.
|
||||
/// </returns>
|
||||
private IEnumerable<RulesetInfo> orderedRulesets =>
|
||||
recommendedDifficultyMapping
|
||||
.OrderByDescending(pair => pair.Value).Select(pair => pair.Key).Where(r => !r.Equals(ruleset.Value))
|
||||
.Prepend(ruleset.Value);
|
||||
private IEnumerable<RulesetInfo> orderedRulesets
|
||||
{
|
||||
get
|
||||
{
|
||||
if (LoadState < LoadState.Ready || ruleset.Value == null)
|
||||
return Enumerable.Empty<RulesetInfo>();
|
||||
|
||||
return recommendedDifficultyMapping
|
||||
.OrderByDescending(pair => pair.Value)
|
||||
.Select(pair => pair.Key)
|
||||
.Where(r => !r.Equals(ruleset.Value))
|
||||
.Prepend(ruleset.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void onlineStateChanged(ValueChangedEvent<APIState> state) => Schedule(() =>
|
||||
{
|
||||
|
47
osu.Game/Beatmaps/MetadataUtils.cs
Normal file
47
osu.Game/Beatmaps/MetadataUtils.cs
Normal file
@ -0,0 +1,47 @@
|
||||
// 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.
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
/// <summary>
|
||||
/// Groups utility methods used to handle beatmap metadata.
|
||||
/// </summary>
|
||||
public static class MetadataUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns <see langword="true"/> if the character <paramref name="c"/> can be used in <see cref="BeatmapMetadata.Artist"/> and <see cref="BeatmapMetadata.Title"/> fields.
|
||||
/// Characters not matched by this method can be placed in <see cref="BeatmapMetadata.ArtistUnicode"/> and <see cref="BeatmapMetadata.TitleUnicode"/>.
|
||||
/// </summary>
|
||||
public static bool IsRomanised(char c) => c <= 0xFF;
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true"/> if the string <paramref name="str"/> can be used in <see cref="BeatmapMetadata.Artist"/> and <see cref="BeatmapMetadata.Title"/> fields.
|
||||
/// Strings not matched by this method can be placed in <see cref="BeatmapMetadata.ArtistUnicode"/> and <see cref="BeatmapMetadata.TitleUnicode"/>.
|
||||
/// </summary>
|
||||
public static bool IsRomanised(string? str) => string.IsNullOrEmpty(str) || str.All(IsRomanised);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of <paramref name="str"/> with all characters that do not match <see cref="IsRomanised(char)"/> removed.
|
||||
/// </summary>
|
||||
public static string StripNonRomanisedCharacters(string? str)
|
||||
{
|
||||
if (string.IsNullOrEmpty(str))
|
||||
return string.Empty;
|
||||
|
||||
var stringBuilder = new StringBuilder(str.Length);
|
||||
|
||||
foreach (var c in str)
|
||||
{
|
||||
if (IsRomanised(c))
|
||||
stringBuilder.Append(c);
|
||||
}
|
||||
|
||||
return stringBuilder.ToString().Trim();
|
||||
}
|
||||
}
|
||||
}
|
@ -325,6 +325,7 @@ namespace osu.Game.Beatmaps
|
||||
public ISkin Skin => skin.Value;
|
||||
|
||||
protected abstract ISkin GetSkin();
|
||||
|
||||
private readonly RecyclableLazy<ISkin> skin;
|
||||
|
||||
public abstract Stream GetStream(string storagePath);
|
||||
|
@ -264,14 +264,18 @@ namespace osu.Game.Collections
|
||||
using (var sw = new SerializationWriter(storage.GetStream(database_name, FileAccess.Write)))
|
||||
{
|
||||
sw.Write(database_version);
|
||||
sw.Write(Collections.Count);
|
||||
|
||||
foreach (var c in Collections)
|
||||
var collectionsCopy = Collections.ToArray();
|
||||
sw.Write(collectionsCopy.Length);
|
||||
|
||||
foreach (var c in collectionsCopy)
|
||||
{
|
||||
sw.Write(c.Name.Value);
|
||||
sw.Write(c.Beatmaps.Count);
|
||||
|
||||
foreach (var b in c.Beatmaps)
|
||||
var beatmapsCopy = c.Beatmaps.ToArray();
|
||||
sw.Write(beatmapsCopy.Length);
|
||||
|
||||
foreach (var b in beatmapsCopy)
|
||||
sw.Write(b.MD5Hash);
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
}
|
33
osu.Game/Extensions/LanguageExtensions.cs
Normal file
33
osu.Game/Extensions/LanguageExtensions.cs
Normal file
@ -0,0 +1,33 @@
|
||||
// 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.Globalization;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Conversion utilities for the <see cref="Language"/> enum.
|
||||
/// </summary>
|
||||
public static class LanguageExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the culture code of the <see cref="CultureInfo"/> that corresponds to the supplied <paramref name="language"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is required as enum member names are not allowed to contain hyphens.
|
||||
/// </remarks>
|
||||
public static string ToCultureCode(this Language language)
|
||||
=> language.ToString().Replace("_", "-");
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to parse the supplied <paramref name="cultureCode"/> to a <see cref="Language"/> value.
|
||||
/// </summary>
|
||||
/// <param name="cultureCode">The code of the culture to parse.</param>
|
||||
/// <param name="language">The parsed <see cref="Language"/>. Valid only if the return value of the method is <see langword="true" />.</param>
|
||||
/// <returns>Whether the parsing succeeded.</returns>
|
||||
public static bool TryParseCultureCode(string cultureCode, out Language language)
|
||||
=> Enum.TryParse(cultureCode.Replace("-", "_"), out language);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
// 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.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -14,7 +15,7 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
/// <summary>
|
||||
/// A background which offers blurring via a <see cref="BufferedContainer"/> on demand.
|
||||
/// </summary>
|
||||
public class Background : CompositeDrawable
|
||||
public class Background : CompositeDrawable, IEquatable<Background>
|
||||
{
|
||||
private const float blur_scale = 0.5f;
|
||||
|
||||
@ -71,5 +72,14 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
|
||||
bufferedContainer?.BlurTo(newBlurSigma * blur_scale, duration, easing);
|
||||
}
|
||||
|
||||
public virtual bool Equals(Background other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
|
||||
return other.GetType() == GetType()
|
||||
&& other.textureName == textureName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,5 +24,14 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
{
|
||||
Sprite.Texture = Beatmap?.Background ?? textures.Get(fallbackTextureName);
|
||||
}
|
||||
|
||||
public override bool Equals(Background other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
|
||||
return other.GetType() == GetType()
|
||||
&& ((BeatmapBackground)other).Beatmap == Beatmap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -99,5 +99,14 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
// ensure we're not loading in without a transition.
|
||||
this.FadeInFromZero(200, Easing.InOutSine);
|
||||
}
|
||||
|
||||
public override bool Equals(Background other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
|
||||
return other.GetType() == GetType()
|
||||
&& ((SeasonalBackground)other).url == url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
34
osu.Game/Graphics/Backgrounds/SkinBackground.cs
Normal file
34
osu.Game/Graphics/Backgrounds/SkinBackground.cs
Normal file
@ -0,0 +1,34 @@
|
||||
// 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.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Graphics.Backgrounds
|
||||
{
|
||||
internal class SkinBackground : Background
|
||||
{
|
||||
private readonly Skin skin;
|
||||
|
||||
public SkinBackground(Skin skin, string fallbackTextureName)
|
||||
: base(fallbackTextureName)
|
||||
{
|
||||
this.skin = skin;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Sprite.Texture = skin.GetTexture("menu-background") ?? Sprite.Texture;
|
||||
}
|
||||
|
||||
public override bool Equals(Background other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
|
||||
return other.GetType() == GetType()
|
||||
&& ((SkinBackground)other).skin.SkinInfo.Equals(skin.SkinInfo);
|
||||
}
|
||||
}
|
||||
}
|
@ -57,12 +57,6 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether we want to expire triangles as they exit our draw area completely.
|
||||
/// </summary>
|
||||
[Obsolete("Unused.")] // Can be removed 20210518
|
||||
protected virtual bool ExpireOffScreenTriangles => true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether we should create new triangles as others expire.
|
||||
/// </summary>
|
||||
|
@ -30,9 +30,12 @@ namespace osu.Game.Graphics.Containers.Markdown
|
||||
break;
|
||||
|
||||
case ListItemBlock listItemBlock:
|
||||
var isOrdered = ((ListBlock)listItemBlock.Parent).IsOrdered;
|
||||
var childContainer = CreateListItem(listItemBlock, level, isOrdered);
|
||||
bool isOrdered = ((ListBlock)listItemBlock.Parent)?.IsOrdered == true;
|
||||
|
||||
OsuMarkdownListItem childContainer = CreateListItem(listItemBlock, level, isOrdered);
|
||||
|
||||
container.Add(childContainer);
|
||||
|
||||
foreach (var single in listItemBlock)
|
||||
base.AddMarkdownComponent(single, childContainer.Content, level);
|
||||
break;
|
||||
|
20
osu.Game/Graphics/Containers/Markdown/OsuMarkdownImage.cs
Normal file
20
osu.Game/Graphics/Containers/Markdown/OsuMarkdownImage.cs
Normal file
@ -0,0 +1,20 @@
|
||||
// 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 Markdig.Syntax.Inlines;
|
||||
using osu.Framework.Graphics.Containers.Markdown;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
|
||||
namespace osu.Game.Graphics.Containers.Markdown
|
||||
{
|
||||
public class OsuMarkdownImage : MarkdownImage, IHasTooltip
|
||||
{
|
||||
public string TooltipText { get; }
|
||||
|
||||
public OsuMarkdownImage(LinkInline linkInline)
|
||||
: base(linkInline.Url)
|
||||
{
|
||||
TooltipText = linkInline.Title;
|
||||
}
|
||||
}
|
||||
}
|
@ -17,6 +17,8 @@ namespace osu.Game.Graphics.Containers.Markdown
|
||||
protected override void AddLinkText(string text, LinkInline linkInline)
|
||||
=> AddDrawable(new OsuMarkdownLinkText(text, linkInline));
|
||||
|
||||
protected override void AddImage(LinkInline linkInline) => AddDrawable(new OsuMarkdownImage(linkInline));
|
||||
|
||||
// TODO : Change font to monospace
|
||||
protected override void AddCodeInLine(CodeInline codeInline) => AddDrawable(new OsuMarkdownInlineCode
|
||||
{
|
||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Graphics.Containers
|
||||
|
||||
protected virtual HoverClickSounds CreateHoverClickSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet);
|
||||
|
||||
public OsuClickableContainer(HoverSampleSet sampleSet = HoverSampleSet.Normal)
|
||||
public OsuClickableContainer(HoverSampleSet sampleSet = HoverSampleSet.Default)
|
||||
{
|
||||
this.sampleSet = sampleSet;
|
||||
}
|
||||
|
@ -107,10 +107,10 @@ namespace osu.Game.Graphics.Containers
|
||||
{
|
||||
}
|
||||
|
||||
private bool playedPopInSound;
|
||||
|
||||
protected override void UpdateState(ValueChangedEvent<Visibility> state)
|
||||
{
|
||||
bool didChange = state.NewValue != state.OldValue;
|
||||
|
||||
switch (state.NewValue)
|
||||
{
|
||||
case Visibility.Visible:
|
||||
@ -121,18 +121,15 @@ namespace osu.Game.Graphics.Containers
|
||||
return;
|
||||
}
|
||||
|
||||
samplePopIn?.Play();
|
||||
playedPopInSound = true;
|
||||
if (didChange)
|
||||
samplePopIn?.Play();
|
||||
|
||||
if (BlockScreenWideMouse && DimMainContent) game?.AddBlockingOverlay(this);
|
||||
break;
|
||||
|
||||
case Visibility.Hidden:
|
||||
if (playedPopInSound)
|
||||
{
|
||||
if (didChange)
|
||||
samplePopOut?.Play();
|
||||
playedPopInSound = false;
|
||||
}
|
||||
|
||||
if (BlockScreenWideMouse) game?.RemoveBlockingOverlay(this);
|
||||
break;
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -23,9 +22,6 @@ namespace osu.Game.Graphics.UserInterface
|
||||
private const int text_size = 17;
|
||||
private const int transition_length = 80;
|
||||
|
||||
private Sample sampleClick;
|
||||
private Sample sampleHover;
|
||||
|
||||
private TextContainer text;
|
||||
|
||||
public DrawableOsuMenuItem(MenuItem item)
|
||||
@ -36,12 +32,11 @@ namespace osu.Game.Graphics.UserInterface
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
sampleHover = audio.Samples.Get(@"UI/generic-hover");
|
||||
sampleClick = audio.Samples.Get(@"UI/generic-select");
|
||||
|
||||
BackgroundColour = Color4.Transparent;
|
||||
BackgroundColourHover = Color4Extensions.FromHex(@"172023");
|
||||
|
||||
AddInternal(new HoverClickSounds());
|
||||
|
||||
updateTextColour();
|
||||
|
||||
Item.Action.BindDisabledChanged(_ => updateState(), true);
|
||||
@ -84,7 +79,6 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
if (IsHovered && !Item.Action.Disabled)
|
||||
{
|
||||
sampleHover.Play();
|
||||
text.BoldText.FadeIn(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 virtual TextContainer CreateTextContainer() => new TextContainer();
|
||||
|
||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
/// 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.
|
||||
/// </param>
|
||||
public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal, MouseButton[] buttons = null)
|
||||
public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Default, MouseButton[] buttons = null)
|
||||
: base(sampleSet)
|
||||
{
|
||||
this.buttons = buttons ?? new[] { MouseButton.Left };
|
||||
@ -45,7 +45,8 @@ namespace osu.Game.Graphics.UserInterface
|
||||
[BackgroundDependencyLoader]
|
||||
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.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.ComponentModel;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
@ -22,7 +21,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
protected readonly HoverSampleSet SampleSet;
|
||||
|
||||
public HoverSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal)
|
||||
public HoverSounds(HoverSampleSet sampleSet = HoverSampleSet.Default)
|
||||
{
|
||||
SampleSet = sampleSet;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
@ -31,7 +30,8 @@ namespace osu.Game.Graphics.UserInterface
|
||||
[BackgroundDependencyLoader]
|
||||
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()
|
||||
@ -40,22 +40,4 @@ namespace osu.Game.Graphics.UserInterface
|
||||
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;
|
||||
|
||||
public OsuAnimatedButton()
|
||||
: base(HoverSampleSet.Button)
|
||||
{
|
||||
base.Content.Add(content = new Container
|
||||
{
|
||||
|
@ -49,7 +49,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
protected Box Background;
|
||||
protected SpriteText SpriteText;
|
||||
|
||||
public OsuButton(HoverSampleSet? hoverSounds = HoverSampleSet.Loud)
|
||||
public OsuButton(HoverSampleSet? hoverSounds = HoverSampleSet.Button)
|
||||
{
|
||||
Height = 40;
|
||||
|
||||
|
@ -160,7 +160,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
Margin = new MarginPadding { Top = 5, Bottom = 5 },
|
||||
Origin = Anchor.BottomLeft,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Text = (value as IHasDescription)?.Description ?? (value as Enum)?.GetDescription() ?? value.ToString(),
|
||||
Text = (value as IHasDescription)?.Description ?? (value as Enum)?.GetLocalisableDescription() ?? value.ToString(),
|
||||
Font = OsuFont.GetFont(size: 14)
|
||||
},
|
||||
Bar = new Box
|
||||
|
@ -11,6 +11,7 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
@ -81,7 +82,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
Active.BindValueChanged(active => Text.Font = Text.Font.With(Typeface.Torus, weight: active.NewValue ? FontWeight.Bold : FontWeight.Medium), true);
|
||||
}
|
||||
|
||||
protected virtual string CreateText() => (Value as Enum)?.GetDescription() ?? Value.ToString();
|
||||
protected virtual LocalisableString CreateText() => (Value as Enum)?.GetLocalisableDescription() ?? Value.ToString();
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
|
@ -14,6 +14,27 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
public abstract class LabelledDrawable<T> : CompositeDrawable
|
||||
where T : Drawable
|
||||
{
|
||||
private float? fixedLabelWidth;
|
||||
|
||||
/// <summary>
|
||||
/// The fixed width of the label of this <see cref="LabelledDrawable{T}"/>.
|
||||
/// If <c>null</c>, the label portion will auto-size to its content.
|
||||
/// Can be used in layout scenarios where several labels must match in length for the components to be aligned properly.
|
||||
/// </summary>
|
||||
public float? FixedLabelWidth
|
||||
{
|
||||
get => fixedLabelWidth;
|
||||
set
|
||||
{
|
||||
if (fixedLabelWidth == value)
|
||||
return;
|
||||
|
||||
fixedLabelWidth = value;
|
||||
|
||||
updateLabelWidth();
|
||||
}
|
||||
}
|
||||
|
||||
protected const float CONTENT_PADDING_VERTICAL = 10;
|
||||
protected const float CONTENT_PADDING_HORIZONTAL = 15;
|
||||
protected const float CORNER_RADIUS = 15;
|
||||
@ -23,6 +44,7 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
/// </summary>
|
||||
protected readonly T Component;
|
||||
|
||||
private readonly GridContainer grid;
|
||||
private readonly OsuTextFlowContainer labelText;
|
||||
private readonly OsuTextFlowContainer descriptionText;
|
||||
|
||||
@ -56,7 +78,7 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
Spacing = new Vector2(0, 12),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new GridContainer
|
||||
grid = new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
@ -69,7 +91,13 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Right = 20 }
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Right = 20,
|
||||
// ensure that the label is always vertically padded even if the component itself isn't.
|
||||
// this may become an issue if the label is taller than the component.
|
||||
Vertical = padded ? 0 : CONTENT_PADDING_VERTICAL
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
@ -87,7 +115,6 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
},
|
||||
},
|
||||
RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
|
||||
ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }
|
||||
},
|
||||
descriptionText = new OsuTextFlowContainer(s => s.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold, italics: true))
|
||||
{
|
||||
@ -99,6 +126,24 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
updateLabelWidth();
|
||||
}
|
||||
|
||||
private void updateLabelWidth()
|
||||
{
|
||||
if (fixedLabelWidth == null)
|
||||
{
|
||||
grid.ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) };
|
||||
labelText.RelativeSizeAxes = Axes.None;
|
||||
labelText.AutoSizeAxes = Axes.Both;
|
||||
}
|
||||
else
|
||||
{
|
||||
grid.ColumnDimensions = new[] { new Dimension(GridSizeMode.Absolute, fixedLabelWidth.Value) };
|
||||
labelText.AutoSizeAxes = Axes.Y;
|
||||
labelText.RelativeSizeAxes = Axes.X;
|
||||
}
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
|
@ -21,6 +21,7 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
|
||||
public bool ReadOnly
|
||||
{
|
||||
get => Component.ReadOnly;
|
||||
set => Component.ReadOnly = value;
|
||||
}
|
||||
|
||||
@ -45,14 +46,7 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
Component.BorderColour = colours.Blue;
|
||||
}
|
||||
|
||||
protected virtual OsuTextBox CreateTextBox() => new OsuTextBox
|
||||
{
|
||||
CommitOnFocusLost = true,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
CornerRadius = CORNER_RADIUS,
|
||||
};
|
||||
protected virtual OsuTextBox CreateTextBox() => new OsuTextBox();
|
||||
|
||||
public override bool AcceptsFocus => true;
|
||||
|
||||
@ -64,6 +58,12 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
|
||||
protected override OsuTextBox CreateComponent() => CreateTextBox().With(t =>
|
||||
{
|
||||
t.CommitOnFocusLost = true;
|
||||
t.Anchor = Anchor.Centre;
|
||||
t.Origin = Anchor.Centre;
|
||||
t.RelativeSizeAxes = Axes.X;
|
||||
t.CornerRadius = CORNER_RADIUS;
|
||||
|
||||
t.OnCommit += (sender, newText) => OnCommit?.Invoke(sender, newText);
|
||||
});
|
||||
}
|
||||
|
@ -7,17 +7,17 @@ namespace osu.Game.Localisation
|
||||
{
|
||||
public static class ChatStrings
|
||||
{
|
||||
private const string prefix = "osu.Game.Localisation.Chat";
|
||||
private const string prefix = @"osu.Game.Localisation.Chat";
|
||||
|
||||
/// <summary>
|
||||
/// "chat"
|
||||
/// </summary>
|
||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "chat");
|
||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"chat");
|
||||
|
||||
/// <summary>
|
||||
/// "join the real-time discussion"
|
||||
/// </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}";
|
||||
}
|
||||
|
@ -7,12 +7,12 @@ namespace osu.Game.Localisation
|
||||
{
|
||||
public static class CommonStrings
|
||||
{
|
||||
private const string prefix = "osu.Game.Localisation.Common";
|
||||
private const string prefix = @"osu.Game.Localisation.Common";
|
||||
|
||||
/// <summary>
|
||||
/// "Cancel"
|
||||
/// </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}";
|
||||
}
|
||||
|
@ -7,10 +7,107 @@ namespace osu.Game.Localisation
|
||||
{
|
||||
public enum Language
|
||||
{
|
||||
[Description("English")]
|
||||
[Description(@"English")]
|
||||
en,
|
||||
|
||||
[Description("日本語")]
|
||||
ja
|
||||
// TODO: Requires Arabic glyphs to be added to resources (and possibly also RTL support).
|
||||
// [Description(@"اَلْعَرَبِيَّةُ")]
|
||||
// ar,
|
||||
|
||||
// TODO: Some accented glyphs are missing. Revisit when adding Inter.
|
||||
// [Description(@"Беларуская мова")]
|
||||
// be,
|
||||
|
||||
[Description(@"Български")]
|
||||
bg,
|
||||
|
||||
[Description(@"Česky")]
|
||||
cs,
|
||||
|
||||
[Description(@"Dansk")]
|
||||
da,
|
||||
|
||||
[Description(@"Deutsch")]
|
||||
de,
|
||||
|
||||
// TODO: Some accented glyphs are missing. Revisit when adding Inter.
|
||||
// [Description(@"Ελληνικά")]
|
||||
// el,
|
||||
|
||||
[Description(@"español")]
|
||||
es,
|
||||
|
||||
[Description(@"Suomi")]
|
||||
fi,
|
||||
|
||||
[Description(@"français")]
|
||||
fr,
|
||||
|
||||
[Description(@"Magyar")]
|
||||
hu,
|
||||
|
||||
[Description(@"Bahasa Indonesia")]
|
||||
id,
|
||||
|
||||
[Description(@"Italiano")]
|
||||
it,
|
||||
|
||||
[Description(@"日本語")]
|
||||
ja,
|
||||
|
||||
[Description(@"한국어")]
|
||||
ko,
|
||||
|
||||
[Description(@"Nederlands")]
|
||||
nl,
|
||||
|
||||
[Description(@"Norsk")]
|
||||
no,
|
||||
|
||||
[Description(@"polski")]
|
||||
pl,
|
||||
|
||||
[Description(@"Português")]
|
||||
pt,
|
||||
|
||||
[Description(@"Português (Brasil)")]
|
||||
pt_br,
|
||||
|
||||
[Description(@"Română")]
|
||||
ro,
|
||||
|
||||
[Description(@"Русский")]
|
||||
ru,
|
||||
|
||||
[Description(@"Slovenčina")]
|
||||
sk,
|
||||
|
||||
[Description(@"Svenska")]
|
||||
sv,
|
||||
|
||||
[Description(@"ไทย")]
|
||||
th,
|
||||
|
||||
[Description(@"Tagalog")]
|
||||
tl,
|
||||
|
||||
[Description(@"Türkçe")]
|
||||
tr,
|
||||
|
||||
// TODO: Some accented glyphs are missing. Revisit when adding Inter.
|
||||
// [Description(@"Українська мова")]
|
||||
// uk,
|
||||
|
||||
[Description(@"Tiếng Việt")]
|
||||
vi,
|
||||
|
||||
[Description(@"简体中文")]
|
||||
zh,
|
||||
|
||||
[Description(@"繁體中文(香港)")]
|
||||
zh_hk,
|
||||
|
||||
[Description(@"繁體中文(台灣)")]
|
||||
zh_tw
|
||||
}
|
||||
}
|
||||
|
@ -7,17 +7,17 @@ namespace osu.Game.Localisation
|
||||
{
|
||||
public static class NotificationsStrings
|
||||
{
|
||||
private const string prefix = "osu.Game.Localisation.Notifications";
|
||||
private const string prefix = @"osu.Game.Localisation.Notifications";
|
||||
|
||||
/// <summary>
|
||||
/// "notifications"
|
||||
/// </summary>
|
||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "notifications");
|
||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"notifications");
|
||||
|
||||
/// <summary>
|
||||
/// "waiting for 'ya"
|
||||
/// </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}";
|
||||
}
|
||||
|
@ -7,17 +7,17 @@ namespace osu.Game.Localisation
|
||||
{
|
||||
public static class NowPlayingStrings
|
||||
{
|
||||
private const string prefix = "osu.Game.Localisation.NowPlaying";
|
||||
private const string prefix = @"osu.Game.Localisation.NowPlaying";
|
||||
|
||||
/// <summary>
|
||||
/// "now playing"
|
||||
/// </summary>
|
||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "now playing");
|
||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"now playing");
|
||||
|
||||
/// <summary>
|
||||
/// "manage the currently playing track"
|
||||
/// </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}";
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Resources;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Localisation;
|
||||
@ -34,7 +35,29 @@ namespace osu.Game.Localisation
|
||||
lock (resourceManagers)
|
||||
{
|
||||
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
|
||||
{
|
||||
|
@ -7,17 +7,17 @@ namespace osu.Game.Localisation
|
||||
{
|
||||
public static class SettingsStrings
|
||||
{
|
||||
private const string prefix = "osu.Game.Localisation.Settings";
|
||||
private const string prefix = @"osu.Game.Localisation.Settings";
|
||||
|
||||
/// <summary>
|
||||
/// "settings"
|
||||
/// </summary>
|
||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "settings");
|
||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"settings");
|
||||
|
||||
/// <summary>
|
||||
/// "change the way osu! behaves"
|
||||
/// </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}";
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -21,7 +21,12 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
var ruleset = rulesets.GetRuleset(OnlineRulesetID);
|
||||
|
||||
var mods = Mods != null ? ruleset.CreateInstance().GetAllMods().Where(mod => Mods.Contains(mod.Acronym)).ToArray() : Array.Empty<Mod>();
|
||||
var rulesetInstance = ruleset.CreateInstance();
|
||||
|
||||
var mods = Mods != null ? rulesetInstance.GetAllMods().Where(mod => Mods.Contains(mod.Acronym)).ToArray() : Array.Empty<Mod>();
|
||||
|
||||
// all API scores provided by this class are considered to be legacy.
|
||||
mods = mods.Append(rulesetInstance.GetAllMods().OfType<ModClassic>().Single()).ToArray();
|
||||
|
||||
var scoreInfo = new ScoreInfo
|
||||
{
|
||||
@ -38,7 +43,6 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
Rank = Rank,
|
||||
Ruleset = ruleset,
|
||||
Mods = mods,
|
||||
IsLegacyScore = true
|
||||
};
|
||||
|
||||
if (Statistics != null)
|
||||
|
@ -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}";
|
||||
}
|
||||
}
|
||||
|
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;
|
||||
|
||||
private IEnumerable<TScoreInfo> scores;
|
||||
private ICollection<TScoreInfo> scores;
|
||||
|
||||
public IEnumerable<TScoreInfo> Scores
|
||||
public ICollection<TScoreInfo> Scores
|
||||
{
|
||||
get => scores;
|
||||
set
|
||||
@ -126,7 +126,7 @@ namespace osu.Game.Online.Leaderboards
|
||||
return;
|
||||
|
||||
scope = value;
|
||||
UpdateScores();
|
||||
RefreshScores();
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,7 +154,7 @@ namespace osu.Game.Online.Leaderboards
|
||||
case PlaceholderState.NetworkFailure:
|
||||
replacePlaceholder(new ClickablePlaceholder(@"Couldn't fetch scores!", FontAwesome.Solid.Sync)
|
||||
{
|
||||
Action = UpdateScores,
|
||||
Action = RefreshScores
|
||||
});
|
||||
break;
|
||||
|
||||
@ -254,8 +254,6 @@ namespace osu.Game.Online.Leaderboards
|
||||
apiState.BindValueChanged(onlineStateChanged, true);
|
||||
}
|
||||
|
||||
public void RefreshScores() => UpdateScores();
|
||||
|
||||
private APIRequest getScoresRequest;
|
||||
|
||||
protected abstract bool IsOnlineScope { get; }
|
||||
@ -267,12 +265,14 @@ namespace osu.Game.Online.Leaderboards
|
||||
case APIState.Online:
|
||||
case APIState.Offline:
|
||||
if (IsOnlineScope)
|
||||
UpdateScores();
|
||||
RefreshScores();
|
||||
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
public void RefreshScores() => Scheduler.AddOnce(UpdateScores);
|
||||
|
||||
protected void UpdateScores()
|
||||
{
|
||||
// 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(() =>
|
||||
{
|
||||
Scores = scores;
|
||||
Scores = scores.ToArray();
|
||||
PlaceholderState = Scores.Any() ? PlaceholderState.Successful : PlaceholderState.NoScores;
|
||||
}));
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using MessagePack;
|
||||
using osu.Game.Online.API;
|
||||
|
||||
@ -28,11 +27,9 @@ namespace osu.Game.Online.Multiplayer
|
||||
[Key(3)]
|
||||
public string Name { get; set; } = "Unnamed room";
|
||||
|
||||
[NotNull]
|
||||
[Key(4)]
|
||||
public IEnumerable<APIMod> RequiredMods { get; set; } = Enumerable.Empty<APIMod>();
|
||||
|
||||
[NotNull]
|
||||
[Key(5)]
|
||||
public IEnumerable<APIMod> AllowedMods { get; set; } = Enumerable.Empty<APIMod>();
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using MessagePack;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Online.API;
|
||||
@ -35,7 +34,6 @@ namespace osu.Game.Online.Multiplayer
|
||||
/// Any mods applicable only to the local user.
|
||||
/// </summary>
|
||||
[Key(3)]
|
||||
[NotNull]
|
||||
public IEnumerable<APIMod> Mods { get; set; } = Enumerable.Empty<APIMod>();
|
||||
|
||||
[IgnoreMember]
|
||||
|
@ -50,8 +50,10 @@ using osu.Game.Updater;
|
||||
using osu.Game.Utils;
|
||||
using LogLevel = osu.Framework.Logging.LogLevel;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.IO;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Performance;
|
||||
using osu.Game.Skinning.Editor;
|
||||
|
||||
namespace osu.Game
|
||||
@ -426,9 +428,12 @@ namespace osu.Game
|
||||
{
|
||||
// The given ScoreInfo may have missing properties if it was retrieved from online data. Re-retrieve it from the database
|
||||
// to ensure all the required data for presenting a replay are present.
|
||||
var databasedScoreInfo = score.OnlineScoreID != null
|
||||
? ScoreManager.Query(s => s.OnlineScoreID == score.OnlineScoreID)
|
||||
: ScoreManager.Query(s => s.Hash == score.Hash);
|
||||
ScoreInfo databasedScoreInfo = null;
|
||||
|
||||
if (score.OnlineScoreID != null)
|
||||
databasedScoreInfo = ScoreManager.Query(s => s.OnlineScoreID == score.OnlineScoreID);
|
||||
|
||||
databasedScoreInfo ??= ScoreManager.Query(s => s.Hash == score.Hash);
|
||||
|
||||
if (databasedScoreInfo == null)
|
||||
{
|
||||
@ -484,6 +489,8 @@ namespace osu.Game
|
||||
|
||||
protected virtual UpdateManager CreateUpdateManager() => new UpdateManager();
|
||||
|
||||
protected virtual HighPerformanceSession CreateHighPerformanceSession() => new HighPerformanceSession();
|
||||
|
||||
protected override Container CreateScalingContainer() => new ScalingContainer(ScalingMode.Everything);
|
||||
|
||||
#region Beatmap progression
|
||||
@ -577,7 +584,7 @@ namespace osu.Game
|
||||
|
||||
foreach (var language in Enum.GetValues(typeof(Language)).OfType<Language>())
|
||||
{
|
||||
var cultureCode = language.ToString();
|
||||
var cultureCode = language.ToCultureCode();
|
||||
Localisation.AddLanguage(cultureCode, new ResourceManagerLocalisationStore(cultureCode));
|
||||
}
|
||||
|
||||
@ -651,9 +658,10 @@ namespace osu.Game
|
||||
Origin = Anchor.BottomLeft,
|
||||
Action = () =>
|
||||
{
|
||||
var currentScreen = ScreenStack.CurrentScreen as IOsuScreen;
|
||||
if (!(ScreenStack.CurrentScreen is IOsuScreen currentScreen))
|
||||
return;
|
||||
|
||||
if (currentScreen?.AllowBackButton == true && !currentScreen.OnBackButton())
|
||||
if (!((Drawable)currentScreen).IsLoaded || (currentScreen.AllowBackButton && !currentScreen.OnBackButton()))
|
||||
ScreenStack.Exit();
|
||||
}
|
||||
},
|
||||
@ -711,7 +719,6 @@ namespace osu.Game
|
||||
PostNotification = n => notifications.Post(n),
|
||||
}, Add, true);
|
||||
|
||||
loadComponentSingleFile(difficultyRecommender, Add);
|
||||
loadComponentSingleFile(stableImportManager, Add);
|
||||
|
||||
loadComponentSingleFile(screenshotManager, Add);
|
||||
@ -727,6 +734,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);
|
||||
@ -751,8 +759,11 @@ namespace osu.Game
|
||||
loadComponentSingleFile(new AccountCreationOverlay(), topMostOverlayContent.Add, true);
|
||||
loadComponentSingleFile(new DialogOverlay(), topMostOverlayContent.Add, true);
|
||||
|
||||
loadComponentSingleFile(CreateHighPerformanceSession(), Add);
|
||||
|
||||
chatOverlay.State.ValueChanged += state => channelManager.HighPollRate.Value = state.NewValue == Visibility.Visible;
|
||||
|
||||
Add(difficultyRecommender);
|
||||
Add(externalLinkOpener = new ExternalLinkOpener());
|
||||
Add(new MusicKeyBindingHandler());
|
||||
|
||||
|
@ -14,6 +14,7 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
using osuTK.Graphics;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Scoring;
|
||||
@ -126,15 +127,15 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
Padding = new MarginPadding { Horizontal = 10 },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
generalFilter = new BeatmapSearchMultipleSelectionFilterRow<SearchGeneral>(@"General"),
|
||||
generalFilter = new BeatmapSearchMultipleSelectionFilterRow<SearchGeneral>(BeatmapsStrings.ListingSearchFiltersGeneral),
|
||||
modeFilter = new BeatmapSearchRulesetFilterRow(),
|
||||
categoryFilter = new BeatmapSearchFilterRow<SearchCategory>(@"Categories"),
|
||||
genreFilter = new BeatmapSearchFilterRow<SearchGenre>(@"Genre"),
|
||||
languageFilter = new BeatmapSearchFilterRow<SearchLanguage>(@"Language"),
|
||||
extraFilter = new BeatmapSearchMultipleSelectionFilterRow<SearchExtra>(@"Extra"),
|
||||
categoryFilter = new BeatmapSearchFilterRow<SearchCategory>(BeatmapsStrings.ListingSearchFiltersStatus),
|
||||
genreFilter = new BeatmapSearchFilterRow<SearchGenre>(BeatmapsStrings.ListingSearchFiltersGenre),
|
||||
languageFilter = new BeatmapSearchFilterRow<SearchLanguage>(BeatmapsStrings.ListingSearchFiltersLanguage),
|
||||
extraFilter = new BeatmapSearchMultipleSelectionFilterRow<SearchExtra>(BeatmapsStrings.ListingSearchFiltersExtra),
|
||||
ranksFilter = new BeatmapSearchScoreFilterRow(),
|
||||
playedFilter = new BeatmapSearchFilterRow<SearchPlayed>(@"Played"),
|
||||
explicitContentFilter = new BeatmapSearchFilterRow<SearchExplicit>(@"Explicit Content"),
|
||||
playedFilter = new BeatmapSearchFilterRow<SearchPlayed>(BeatmapsStrings.ListingSearchFiltersPlayed),
|
||||
explicitContentFilter = new BeatmapSearchFilterRow<SearchExplicit>(BeatmapsStrings.ListingSearchFiltersNsfw),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -172,7 +173,7 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
|
||||
public BeatmapSearchTextBox()
|
||||
{
|
||||
PlaceholderText = @"type in keywords...";
|
||||
PlaceholderText = BeatmapsStrings.ListingSearchPrompt;
|
||||
}
|
||||
|
||||
protected override bool OnKeyDown(KeyDownEvent e)
|
||||
|
@ -11,8 +11,8 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK;
|
||||
using Humanizer;
|
||||
using osu.Framework.Extensions.EnumExtensions;
|
||||
using osu.Framework.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing
|
||||
{
|
||||
@ -26,7 +26,7 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
set => current.Current = value;
|
||||
}
|
||||
|
||||
public BeatmapSearchFilterRow(string headerName)
|
||||
public BeatmapSearchFilterRow(LocalisableString header)
|
||||
{
|
||||
Drawable filter;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
@ -53,7 +53,7 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Font = OsuFont.GetFont(size: 13),
|
||||
Text = headerName.Titleize()
|
||||
Text = header
|
||||
},
|
||||
filter = CreateFilter()
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Localisation;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing
|
||||
@ -19,8 +20,8 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
|
||||
private MultipleSelectionFilter filter;
|
||||
|
||||
public BeatmapSearchMultipleSelectionFilterRow(string headerName)
|
||||
: base(headerName)
|
||||
public BeatmapSearchMultipleSelectionFilterRow(LocalisableString header)
|
||||
: base(header)
|
||||
{
|
||||
Current.BindTo(filter.Current);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing
|
||||
@ -10,7 +11,7 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
public class BeatmapSearchRulesetFilterRow : BeatmapSearchFilterRow<RulesetInfo>
|
||||
{
|
||||
public BeatmapSearchRulesetFilterRow()
|
||||
: base(@"Mode")
|
||||
: base(BeatmapsStrings.ListingSearchFiltersMode)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
using osu.Game.Scoring;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing
|
||||
@ -11,7 +13,7 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
public class BeatmapSearchScoreFilterRow : BeatmapSearchMultipleSelectionFilterRow<ScoreRank>
|
||||
{
|
||||
public BeatmapSearchScoreFilterRow()
|
||||
: base(@"Rank Achieved")
|
||||
: base(BeatmapsStrings.ListingSearchFiltersRank)
|
||||
{
|
||||
}
|
||||
|
||||
@ -31,20 +33,7 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
{
|
||||
}
|
||||
|
||||
protected override string LabelFor(ScoreRank value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case ScoreRank.XH:
|
||||
return @"Silver SS";
|
||||
|
||||
case ScoreRank.SH:
|
||||
return @"Silver S";
|
||||
|
||||
default:
|
||||
return value.GetDescription();
|
||||
}
|
||||
}
|
||||
protected override LocalisableString LabelFor(ScoreRank value) => value.GetLocalisableDescription();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
@ -66,7 +67,7 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
/// <summary>
|
||||
/// Returns the label text to be used for the supplied <paramref name="value"/>.
|
||||
/// </summary>
|
||||
protected virtual string LabelFor(T value) => (value as Enum)?.GetDescription() ?? value.ToString();
|
||||
protected virtual LocalisableString LabelFor(T value) => (value as Enum)?.GetLocalisableDescription() ?? value.ToString();
|
||||
|
||||
private void updateState()
|
||||
{
|
||||
|
@ -1,10 +1,14 @@
|
||||
// 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.ComponentModel;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing
|
||||
{
|
||||
[LocalisableEnum(typeof(SearchCategoryEnumLocalisationMapper))]
|
||||
public enum SearchCategory
|
||||
{
|
||||
Any,
|
||||
@ -23,4 +27,43 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
[Description("My Maps")]
|
||||
Mine,
|
||||
}
|
||||
|
||||
public class SearchCategoryEnumLocalisationMapper : EnumLocalisationMapper<SearchCategory>
|
||||
{
|
||||
public override LocalisableString Map(SearchCategory value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case SearchCategory.Any:
|
||||
return BeatmapsStrings.StatusAny;
|
||||
|
||||
case SearchCategory.Leaderboard:
|
||||
return BeatmapsStrings.StatusLeaderboard;
|
||||
|
||||
case SearchCategory.Ranked:
|
||||
return BeatmapsStrings.StatusRanked;
|
||||
|
||||
case SearchCategory.Qualified:
|
||||
return BeatmapsStrings.StatusQualified;
|
||||
|
||||
case SearchCategory.Loved:
|
||||
return BeatmapsStrings.StatusLoved;
|
||||
|
||||
case SearchCategory.Favourites:
|
||||
return BeatmapsStrings.StatusFavourites;
|
||||
|
||||
case SearchCategory.Pending:
|
||||
return BeatmapsStrings.StatusPending;
|
||||
|
||||
case SearchCategory.Graveyard:
|
||||
return BeatmapsStrings.StatusGraveyard;
|
||||
|
||||
case SearchCategory.Mine:
|
||||
return BeatmapsStrings.StatusMine;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(value), value, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,34 @@
|
||||
// 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.Localisation;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing
|
||||
{
|
||||
[LocalisableEnum(typeof(SearchExplicitEnumLocalisationMapper))]
|
||||
public enum SearchExplicit
|
||||
{
|
||||
Hide,
|
||||
Show
|
||||
}
|
||||
|
||||
public class SearchExplicitEnumLocalisationMapper : EnumLocalisationMapper<SearchExplicit>
|
||||
{
|
||||
public override LocalisableString Map(SearchExplicit value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case SearchExplicit.Hide:
|
||||
return BeatmapsStrings.NsfwExclude;
|
||||
|
||||
case SearchExplicit.Show:
|
||||
return BeatmapsStrings.NsfwInclude;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(value), value, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,14 @@
|
||||
// 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.ComponentModel;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing
|
||||
{
|
||||
[LocalisableEnum(typeof(SearchExtraEnumLocalisationMapper))]
|
||||
public enum SearchExtra
|
||||
{
|
||||
[Description("Has Video")]
|
||||
@ -13,4 +17,22 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
[Description("Has Storyboard")]
|
||||
Storyboard
|
||||
}
|
||||
|
||||
public class SearchExtraEnumLocalisationMapper : EnumLocalisationMapper<SearchExtra>
|
||||
{
|
||||
public override LocalisableString Map(SearchExtra value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case SearchExtra.Video:
|
||||
return BeatmapsStrings.ExtraVideo;
|
||||
|
||||
case SearchExtra.Storyboard:
|
||||
return BeatmapsStrings.ExtraStoryboard;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(value), value, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,14 @@
|
||||
// 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.ComponentModel;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing
|
||||
{
|
||||
[LocalisableEnum(typeof(SearchGeneralEnumLocalisationMapper))]
|
||||
public enum SearchGeneral
|
||||
{
|
||||
[Description("Recommended difficulty")]
|
||||
@ -16,4 +20,25 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
[Description("Subscribed mappers")]
|
||||
Follows
|
||||
}
|
||||
|
||||
public class SearchGeneralEnumLocalisationMapper : EnumLocalisationMapper<SearchGeneral>
|
||||
{
|
||||
public override LocalisableString Map(SearchGeneral value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case SearchGeneral.Recommended:
|
||||
return BeatmapsStrings.GeneralRecommended;
|
||||
|
||||
case SearchGeneral.Converts:
|
||||
return BeatmapsStrings.GeneralConverts;
|
||||
|
||||
case SearchGeneral.Follows:
|
||||
return BeatmapsStrings.GeneralFollows;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(value), value, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,14 @@
|
||||
// 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.ComponentModel;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing
|
||||
{
|
||||
[LocalisableEnum(typeof(SearchGenreEnumLocalisationMapper))]
|
||||
public enum SearchGenre
|
||||
{
|
||||
Any = 0,
|
||||
@ -26,4 +30,58 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
Folk = 13,
|
||||
Jazz = 14
|
||||
}
|
||||
|
||||
public class SearchGenreEnumLocalisationMapper : EnumLocalisationMapper<SearchGenre>
|
||||
{
|
||||
public override LocalisableString Map(SearchGenre value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case SearchGenre.Any:
|
||||
return BeatmapsStrings.GenreAny;
|
||||
|
||||
case SearchGenre.Unspecified:
|
||||
return BeatmapsStrings.GenreUnspecified;
|
||||
|
||||
case SearchGenre.VideoGame:
|
||||
return BeatmapsStrings.GenreVideoGame;
|
||||
|
||||
case SearchGenre.Anime:
|
||||
return BeatmapsStrings.GenreAnime;
|
||||
|
||||
case SearchGenre.Rock:
|
||||
return BeatmapsStrings.GenreRock;
|
||||
|
||||
case SearchGenre.Pop:
|
||||
return BeatmapsStrings.GenrePop;
|
||||
|
||||
case SearchGenre.Other:
|
||||
return BeatmapsStrings.GenreOther;
|
||||
|
||||
case SearchGenre.Novelty:
|
||||
return BeatmapsStrings.GenreNovelty;
|
||||
|
||||
case SearchGenre.HipHop:
|
||||
return BeatmapsStrings.GenreHipHop;
|
||||
|
||||
case SearchGenre.Electronic:
|
||||
return BeatmapsStrings.GenreElectronic;
|
||||
|
||||
case SearchGenre.Metal:
|
||||
return BeatmapsStrings.GenreMetal;
|
||||
|
||||
case SearchGenre.Classical:
|
||||
return BeatmapsStrings.GenreClassical;
|
||||
|
||||
case SearchGenre.Folk:
|
||||
return BeatmapsStrings.GenreFolk;
|
||||
|
||||
case SearchGenre.Jazz:
|
||||
return BeatmapsStrings.GenreJazz;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(value), value, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,14 @@
|
||||
// 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.Localisation;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing
|
||||
{
|
||||
[LocalisableEnum(typeof(SearchLanguageEnumLocalisationMapper))]
|
||||
[HasOrderedElements]
|
||||
public enum SearchLanguage
|
||||
{
|
||||
@ -53,4 +57,61 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
[Order(13)]
|
||||
Other
|
||||
}
|
||||
|
||||
public class SearchLanguageEnumLocalisationMapper : EnumLocalisationMapper<SearchLanguage>
|
||||
{
|
||||
public override LocalisableString Map(SearchLanguage value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case SearchLanguage.Any:
|
||||
return BeatmapsStrings.LanguageAny;
|
||||
|
||||
case SearchLanguage.Unspecified:
|
||||
return BeatmapsStrings.LanguageUnspecified;
|
||||
|
||||
case SearchLanguage.English:
|
||||
return BeatmapsStrings.LanguageEnglish;
|
||||
|
||||
case SearchLanguage.Japanese:
|
||||
return BeatmapsStrings.LanguageJapanese;
|
||||
|
||||
case SearchLanguage.Chinese:
|
||||
return BeatmapsStrings.LanguageChinese;
|
||||
|
||||
case SearchLanguage.Instrumental:
|
||||
return BeatmapsStrings.LanguageInstrumental;
|
||||
|
||||
case SearchLanguage.Korean:
|
||||
return BeatmapsStrings.LanguageKorean;
|
||||
|
||||
case SearchLanguage.French:
|
||||
return BeatmapsStrings.LanguageFrench;
|
||||
|
||||
case SearchLanguage.German:
|
||||
return BeatmapsStrings.LanguageGerman;
|
||||
|
||||
case SearchLanguage.Swedish:
|
||||
return BeatmapsStrings.LanguageSwedish;
|
||||
|
||||
case SearchLanguage.Spanish:
|
||||
return BeatmapsStrings.LanguageSpanish;
|
||||
|
||||
case SearchLanguage.Italian:
|
||||
return BeatmapsStrings.LanguageItalian;
|
||||
|
||||
case SearchLanguage.Russian:
|
||||
return BeatmapsStrings.LanguageRussian;
|
||||
|
||||
case SearchLanguage.Polish:
|
||||
return BeatmapsStrings.LanguagePolish;
|
||||
|
||||
case SearchLanguage.Other:
|
||||
return BeatmapsStrings.LanguageOther;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(value), value, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,38 @@
|
||||
// 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.Localisation;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing
|
||||
{
|
||||
[LocalisableEnum(typeof(SearchPlayedEnumLocalisationMapper))]
|
||||
public enum SearchPlayed
|
||||
{
|
||||
Any,
|
||||
Played,
|
||||
Unplayed
|
||||
}
|
||||
|
||||
public class SearchPlayedEnumLocalisationMapper : EnumLocalisationMapper<SearchPlayed>
|
||||
{
|
||||
public override LocalisableString Map(SearchPlayed value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case SearchPlayed.Any:
|
||||
return BeatmapsStrings.PlayedAny;
|
||||
|
||||
case SearchPlayed.Played:
|
||||
return BeatmapsStrings.PlayedPlayed;
|
||||
|
||||
case SearchPlayed.Unplayed:
|
||||
return BeatmapsStrings.PlayedUnplayed;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(value), value, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,13 @@
|
||||
// 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.Localisation;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing
|
||||
{
|
||||
[LocalisableEnum(typeof(SortCriteriaLocalisationMapper))]
|
||||
public enum SortCriteria
|
||||
{
|
||||
Title,
|
||||
@ -14,4 +19,40 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
Favourites,
|
||||
Relevance
|
||||
}
|
||||
|
||||
public class SortCriteriaLocalisationMapper : EnumLocalisationMapper<SortCriteria>
|
||||
{
|
||||
public override LocalisableString Map(SortCriteria value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case SortCriteria.Title:
|
||||
return BeatmapsStrings.ListingSearchSortingTitle;
|
||||
|
||||
case SortCriteria.Artist:
|
||||
return BeatmapsStrings.ListingSearchSortingArtist;
|
||||
|
||||
case SortCriteria.Difficulty:
|
||||
return BeatmapsStrings.ListingSearchSortingDifficulty;
|
||||
|
||||
case SortCriteria.Ranked:
|
||||
return BeatmapsStrings.ListingSearchSortingRanked;
|
||||
|
||||
case SortCriteria.Rating:
|
||||
return BeatmapsStrings.ListingSearchSortingRating;
|
||||
|
||||
case SortCriteria.Plays:
|
||||
return BeatmapsStrings.ListingSearchSortingPlays;
|
||||
|
||||
case SortCriteria.Favourites:
|
||||
return BeatmapsStrings.ListingSearchSortingFavourites;
|
||||
|
||||
case SortCriteria.Relevance:
|
||||
return BeatmapsStrings.ListingSearchSortingRelevance;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(value), value, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Overlays.BeatmapListing;
|
||||
using osu.Game.Overlays.BeatmapListing.Panels;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -232,7 +233,7 @@ namespace osu.Game.Overlays
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Text = @"... nope, nothing found.",
|
||||
Text = BeatmapsStrings.ListingSearchNotFoundQuote,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -22,8 +23,8 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
private const float height = 50;
|
||||
|
||||
private readonly UpdateableAvatar avatar;
|
||||
private readonly FillFlowContainer fields;
|
||||
private UpdateableAvatar avatar;
|
||||
private FillFlowContainer fields;
|
||||
|
||||
private BeatmapSetInfo beatmapSet;
|
||||
|
||||
@ -35,11 +36,46 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
if (value == beatmapSet) return;
|
||||
|
||||
beatmapSet = value;
|
||||
|
||||
updateDisplay();
|
||||
Scheduler.AddOnce(updateDisplay);
|
||||
}
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = height;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
CornerRadius = 4,
|
||||
Masking = true,
|
||||
Child = avatar = new UpdateableAvatar(showGuestOnNull: false)
|
||||
{
|
||||
Size = new Vector2(height),
|
||||
},
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Radius = 4,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
},
|
||||
},
|
||||
fields = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Padding = new MarginPadding { Left = height + 5 },
|
||||
},
|
||||
};
|
||||
|
||||
Scheduler.AddOnce(updateDisplay);
|
||||
}
|
||||
|
||||
private void updateDisplay()
|
||||
{
|
||||
avatar.User = BeatmapSet?.Metadata.Author;
|
||||
@ -69,45 +105,6 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
}
|
||||
}
|
||||
|
||||
public AuthorInfo()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = height;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
CornerRadius = 4,
|
||||
Masking = true,
|
||||
Child = avatar = new UpdateableAvatar
|
||||
{
|
||||
ShowGuestOnNull = false,
|
||||
Size = new Vector2(height),
|
||||
},
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Radius = 4,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
},
|
||||
},
|
||||
fields = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Padding = new MarginPadding { Left = height + 5 },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private void load()
|
||||
{
|
||||
updateDisplay();
|
||||
}
|
||||
|
||||
private class Field : FillFlowContainer
|
||||
{
|
||||
public Field(string first, string second, FontUsage secondFont)
|
||||
|
@ -36,7 +36,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
public Info()
|
||||
{
|
||||
MetadataSection source, tags, genre, language;
|
||||
OsuSpriteText unrankedPlaceholder;
|
||||
OsuSpriteText notRankedPlaceholder;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = base_height;
|
||||
@ -102,12 +102,12 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Top = 20, Horizontal = 15 },
|
||||
},
|
||||
unrankedPlaceholder = new OsuSpriteText
|
||||
notRankedPlaceholder = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Alpha = 0,
|
||||
Text = "Unranked beatmap",
|
||||
Text = "This beatmap is not ranked",
|
||||
Font = OsuFont.GetFont(size: 12)
|
||||
},
|
||||
},
|
||||
@ -124,7 +124,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
language.Text = b.NewValue?.OnlineInfo?.Language?.Name ?? string.Empty;
|
||||
var setHasLeaderboard = b.NewValue?.OnlineInfo?.Status > 0;
|
||||
successRate.Alpha = setHasLeaderboard ? 1 : 0;
|
||||
unrankedPlaceholder.Alpha = setHasLeaderboard ? 0 : 1;
|
||||
notRankedPlaceholder.Alpha = setHasLeaderboard ? 0 : 1;
|
||||
Height = setHasLeaderboard ? 270 : base_height;
|
||||
};
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
return;
|
||||
|
||||
modsContainer.Add(new ModButton(new ModNoMod()));
|
||||
modsContainer.AddRange(ruleset.NewValue.CreateInstance().GetAllMods().Where(m => m.Ranked).Select(m => new ModButton(m)));
|
||||
modsContainer.AddRange(ruleset.NewValue.CreateInstance().GetAllMods().Where(m => m.UserPlayable).Select(m => new ModButton(m)));
|
||||
|
||||
modsContainer.ForEach(button => button.OnSelectionChanged = selectionChanged);
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
},
|
||||
}
|
||||
},
|
||||
avatar = new UpdateableAvatar
|
||||
avatar = new UpdateableAvatar(showGuestOnNull: false)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@ -75,7 +75,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
Offset = new Vector2(0, 2),
|
||||
Radius = 1,
|
||||
},
|
||||
ShowGuestOnNull = false,
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
|
@ -8,7 +8,6 @@ using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Input.Bindings;
|
||||
@ -25,8 +24,6 @@ namespace osu.Game.Overlays
|
||||
|
||||
public readonly Bindable<APIChangelogBuild> Current = new Bindable<APIChangelogBuild>();
|
||||
|
||||
private Sample sampleBack;
|
||||
|
||||
private List<APIChangelogBuild> builds;
|
||||
|
||||
protected List<APIUpdateStream> Streams;
|
||||
@ -41,8 +38,6 @@ namespace osu.Game.Overlays
|
||||
{
|
||||
Header.Build.BindTarget = Current;
|
||||
|
||||
sampleBack = audio.Samples.Get(@"UI/generic-select-soft");
|
||||
|
||||
Current.BindValueChanged(e =>
|
||||
{
|
||||
if (e.NewValue != null)
|
||||
@ -108,7 +103,6 @@ namespace osu.Game.Overlays
|
||||
else
|
||||
{
|
||||
Current.Value = null;
|
||||
sampleBack?.Play();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -51,7 +51,7 @@ namespace osu.Game.Overlays.Chat.Tabs
|
||||
Child = new DelayedLoadWrapper(avatar = new ClickableAvatar(value.Users.First())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
OpenOnClick = { Value = false },
|
||||
OpenOnClick = false,
|
||||
})
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
@ -13,7 +14,9 @@ namespace osu.Game.Overlays
|
||||
{
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
[Cached]
|
||||
protected readonly OverlayScrollContainer ScrollFlow;
|
||||
|
||||
protected readonly LoadingLayer Loading;
|
||||
private readonly Container content;
|
||||
|
||||
|
@ -18,6 +18,7 @@ using JetBrains.Annotations;
|
||||
using System;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
@ -54,7 +55,7 @@ namespace osu.Game.Overlays
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold),
|
||||
Text = @"Sort by"
|
||||
Text = SortStrings.Default
|
||||
},
|
||||
CreateControl().With(c =>
|
||||
{
|
||||
@ -143,7 +144,7 @@ namespace osu.Game.Overlays
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold),
|
||||
Text = (value as Enum)?.GetDescription() ?? value.ToString()
|
||||
Text = (value as Enum)?.GetLocalisableDescription() ?? value.ToString()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -58,13 +58,11 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
Origin = Anchor.CentreLeft,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
avatar = new UpdateableAvatar
|
||||
avatar = new UpdateableAvatar(openOnClick: false, showGuestOnNull: false)
|
||||
{
|
||||
Size = new Vector2(avatar_size),
|
||||
Masking = true,
|
||||
CornerRadius = avatar_size * 0.25f,
|
||||
OpenOnClick = { Value = false },
|
||||
ShowGuestOnNull = false,
|
||||
},
|
||||
new Container
|
||||
{
|
||||
|
@ -1,11 +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.
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.General
|
||||
@ -35,11 +35,11 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
},
|
||||
};
|
||||
|
||||
if (!Enum.TryParse<Language>(frameworkLocale.Value, out var locale))
|
||||
if (!LanguageExtensions.TryParseCultureCode(frameworkLocale.Value, out var locale))
|
||||
locale = Language.en;
|
||||
languageSelection.Current.Value = locale;
|
||||
|
||||
languageSelection.Current.BindValueChanged(val => frameworkLocale.Value = val.NewValue.ToString());
|
||||
languageSelection.Current.BindValueChanged(val => frameworkLocale.Value = val.NewValue.ToCultureCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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[]
|
||||
{
|
||||
new WebSettings(),
|
||||
new AlertsAndPrivacySettings(),
|
||||
new IntegrationSettings()
|
||||
};
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ namespace osu.Game.Overlays.Settings
|
||||
Margin = new MarginPadding { Top = 5 };
|
||||
RelativeSizeAxes = Axes.X;
|
||||
}
|
||||
|
||||
protected override DropdownMenu CreateMenu() => base.CreateMenu().With(m => m.MaxHeight = 200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,16 +2,20 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Overlays.Settings
|
||||
{
|
||||
public class SettingsNumberBox : SettingsItem<string>
|
||||
{
|
||||
protected override Drawable CreateControl() => new OsuNumberBox
|
||||
protected override Drawable CreateControl() => new NumberBox
|
||||
{
|
||||
Margin = new MarginPadding { Top = 5 },
|
||||
RelativeSizeAxes = Axes.X,
|
||||
};
|
||||
|
||||
public class NumberBox : SettingsTextBox.TextBox
|
||||
{
|
||||
protected override bool CanAddCharacter(char character) => char.IsNumber(character);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,60 @@
|
||||
// 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.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Settings
|
||||
{
|
||||
public class SettingsTextBox : SettingsItem<string>
|
||||
{
|
||||
protected override Drawable CreateControl() => new OsuTextBox
|
||||
protected override Drawable CreateControl() => new TextBox
|
||||
{
|
||||
Margin = new MarginPadding { Top = 5 },
|
||||
RelativeSizeAxes = Axes.X,
|
||||
CommitOnFocusLost = true,
|
||||
};
|
||||
|
||||
public class TextBox : OsuTextBox
|
||||
{
|
||||
private const float border_thickness = 3;
|
||||
|
||||
private Color4 borderColourFocused;
|
||||
private Color4 borderColourUnfocused;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colour)
|
||||
{
|
||||
borderColourUnfocused = colour.Gray4.Opacity(0.5f);
|
||||
borderColourFocused = BorderColour;
|
||||
|
||||
updateBorder();
|
||||
}
|
||||
|
||||
protected override void OnFocus(FocusEvent e)
|
||||
{
|
||||
base.OnFocus(e);
|
||||
|
||||
updateBorder();
|
||||
}
|
||||
|
||||
protected override void OnFocusLost(FocusLostEvent e)
|
||||
{
|
||||
base.OnFocusLost(e);
|
||||
|
||||
updateBorder();
|
||||
}
|
||||
|
||||
private void updateBorder()
|
||||
{
|
||||
BorderThickness = border_thickness;
|
||||
BorderColour = HasFocus ? borderColourFocused : borderColourUnfocused;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +106,19 @@ namespace osu.Game.Overlays
|
||||
public OverlayHeaderTabItem(T value)
|
||||
: base(value)
|
||||
{
|
||||
Text.Text = ((Value as Enum)?.GetDescription() ?? Value.ToString()).ToLower();
|
||||
if (!(Value is Enum enumValue))
|
||||
Text.Text = Value.ToString().ToLower();
|
||||
else
|
||||
{
|
||||
var localisableDescription = enumValue.GetLocalisableDescription();
|
||||
var nonLocalisableDescription = enumValue.GetDescription();
|
||||
|
||||
// If localisable == non-localisable, then we must have a basic string, so .ToLower() is used.
|
||||
Text.Text = localisableDescription.Equals(nonLocalisableDescription)
|
||||
? nonLocalisableDescription.ToLower()
|
||||
: localisableDescription;
|
||||
}
|
||||
|
||||
Text.Font = OsuFont.GetFont(size: 14);
|
||||
Text.Margin = new MarginPadding { Vertical = 16.5f }; // 15px padding + 1.5px line-height difference compensation
|
||||
Bar.Margin = new MarginPadding { Bottom = bar_height };
|
||||
|
@ -32,14 +32,13 @@ namespace osu.Game.Overlays.Toolbar
|
||||
|
||||
Add(new OpaqueBackground { Depth = 1 });
|
||||
|
||||
Flow.Add(avatar = new UpdateableAvatar
|
||||
Flow.Add(avatar = new UpdateableAvatar(openOnClick: false)
|
||||
{
|
||||
Masking = true,
|
||||
Size = new Vector2(32),
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
CornerRadius = 4,
|
||||
OpenOnClick = { Value = false },
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
|
@ -33,7 +33,7 @@ namespace osu.Game.Overlays.Wiki.Markdown
|
||||
|
||||
case ParagraphBlock paragraphBlock:
|
||||
// Check if paragraph only contains an image
|
||||
if (paragraphBlock.Inline.Count() == 1 && paragraphBlock.Inline.FirstChild is LinkInline { IsImage: true } linkInline)
|
||||
if (paragraphBlock.Inline?.Count() == 1 && paragraphBlock.Inline.FirstChild is LinkInline { IsImage: true } linkInline)
|
||||
{
|
||||
container.Add(new WikiMarkdownImageBlock(linkInline));
|
||||
return;
|
||||
|
@ -2,19 +2,15 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using Markdig.Syntax.Inlines;
|
||||
using osu.Framework.Graphics.Containers.Markdown;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Game.Graphics.Containers.Markdown;
|
||||
|
||||
namespace osu.Game.Overlays.Wiki.Markdown
|
||||
{
|
||||
public class WikiMarkdownImage : MarkdownImage, IHasTooltip
|
||||
public class WikiMarkdownImage : OsuMarkdownImage
|
||||
{
|
||||
public string TooltipText { get; }
|
||||
|
||||
public WikiMarkdownImage(LinkInline linkInline)
|
||||
: base(linkInline.Url)
|
||||
: base(linkInline)
|
||||
{
|
||||
TooltipText = linkInline.Title;
|
||||
}
|
||||
|
||||
protected override ImageContainer CreateImageContainer(string url)
|
||||
|
80
osu.Game/Overlays/Wiki/WikiArticlePage.cs
Normal file
80
osu.Game/Overlays/Wiki/WikiArticlePage.cs
Normal file
@ -0,0 +1,80 @@
|
||||
// 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 Markdig.Syntax;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Containers.Markdown;
|
||||
using osu.Game.Overlays.Wiki.Markdown;
|
||||
|
||||
namespace osu.Game.Overlays.Wiki
|
||||
{
|
||||
public class WikiArticlePage : CompositeDrawable
|
||||
{
|
||||
public Container SidebarContainer { get; }
|
||||
|
||||
public WikiArticlePage(string currentPath, string markdown)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
WikiSidebar sidebar;
|
||||
|
||||
InternalChild = new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RowDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
},
|
||||
ColumnDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension(),
|
||||
},
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
SidebarContainer = new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.X,
|
||||
Child = sidebar = new WikiSidebar(),
|
||||
},
|
||||
new ArticleMarkdownContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
CurrentPath = currentPath,
|
||||
Text = markdown,
|
||||
DocumentMargin = new MarginPadding(0),
|
||||
DocumentPadding = new MarginPadding
|
||||
{
|
||||
Vertical = 20,
|
||||
Left = 30,
|
||||
Right = 50,
|
||||
},
|
||||
OnAddHeading = sidebar.AddEntry,
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private class ArticleMarkdownContainer : WikiMarkdownContainer
|
||||
{
|
||||
public Action<HeadingBlock, MarkdownHeading> OnAddHeading;
|
||||
|
||||
protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock)
|
||||
{
|
||||
var heading = base.CreateHeading(headingBlock);
|
||||
|
||||
OnAddHeading(headingBlock, heading);
|
||||
|
||||
return heading;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
66
osu.Game/Overlays/Wiki/WikiSidebar.cs
Normal file
66
osu.Game/Overlays/Wiki/WikiSidebar.cs
Normal file
@ -0,0 +1,66 @@
|
||||
// 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 Markdig.Syntax;
|
||||
using Markdig.Syntax.Inlines;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Containers.Markdown;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
namespace osu.Game.Overlays.Wiki
|
||||
{
|
||||
public class WikiSidebar : OverlaySidebar
|
||||
{
|
||||
private WikiTableOfContents tableOfContents;
|
||||
|
||||
protected override Drawable CreateContent() => new FillFlowContainer
|
||||
{
|
||||
Direction = FillDirection.Vertical,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "CONTENTS",
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
|
||||
Margin = new MarginPadding { Bottom = 5 },
|
||||
},
|
||||
tableOfContents = new WikiTableOfContents(),
|
||||
},
|
||||
};
|
||||
|
||||
public void AddEntry(HeadingBlock headingBlock, MarkdownHeading heading)
|
||||
{
|
||||
switch (headingBlock.Level)
|
||||
{
|
||||
case 2:
|
||||
case 3:
|
||||
tableOfContents.AddEntry(getTitle(headingBlock.Inline), heading, headingBlock.Level == 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private string getTitle(ContainerInline containerInline)
|
||||
{
|
||||
foreach (var inline in containerInline)
|
||||
{
|
||||
switch (inline)
|
||||
{
|
||||
case LiteralInline literalInline:
|
||||
return literalInline.Content.ToString();
|
||||
|
||||
case LinkInline linkInline:
|
||||
if (!linkInline.IsImage)
|
||||
return getTitle(linkInline);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
91
osu.Game/Overlays/Wiki/WikiTableOfContents.cs
Normal file
91
osu.Game/Overlays/Wiki/WikiTableOfContents.cs
Normal file
@ -0,0 +1,91 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Containers.Markdown;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
|
||||
namespace osu.Game.Overlays.Wiki
|
||||
{
|
||||
public class WikiTableOfContents : CompositeDrawable
|
||||
{
|
||||
private readonly FillFlowContainer content;
|
||||
|
||||
private TableOfContentsEntry lastMainTitle;
|
||||
|
||||
private TableOfContentsEntry lastSubTitle;
|
||||
|
||||
public WikiTableOfContents()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
InternalChild = content = new FillFlowContainer
|
||||
{
|
||||
Direction = FillDirection.Vertical,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
};
|
||||
}
|
||||
|
||||
public void AddEntry(string title, MarkdownHeading target, bool subtitle = false)
|
||||
{
|
||||
var entry = new TableOfContentsEntry(title, target, subtitle);
|
||||
|
||||
if (subtitle)
|
||||
{
|
||||
lastMainTitle.Margin = new MarginPadding(0);
|
||||
|
||||
if (lastSubTitle != null)
|
||||
lastSubTitle.Margin = new MarginPadding(0);
|
||||
|
||||
content.Add(lastSubTitle = entry.With(d => d.Margin = new MarginPadding { Bottom = 10 }));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
lastSubTitle = null;
|
||||
|
||||
content.Add(lastMainTitle = entry.With(d => d.Margin = new MarginPadding { Bottom = 5 }));
|
||||
}
|
||||
|
||||
private class TableOfContentsEntry : OsuHoverContainer
|
||||
{
|
||||
private readonly MarkdownHeading target;
|
||||
|
||||
private readonly OsuTextFlowContainer textFlow;
|
||||
|
||||
public TableOfContentsEntry(string text, MarkdownHeading target, bool subtitle = false)
|
||||
{
|
||||
this.target = target;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Child = textFlow = new OsuTextFlowContainer(t =>
|
||||
{
|
||||
t.Font = OsuFont.GetFont(size: subtitle ? 12 : 15);
|
||||
}).With(f =>
|
||||
{
|
||||
f.AddText(text);
|
||||
f.RelativeSizeAxes = Axes.X;
|
||||
f.AutoSizeAxes = Axes.Y;
|
||||
f.Margin = new MarginPadding { Bottom = 2 };
|
||||
});
|
||||
Padding = new MarginPadding { Left = subtitle ? 10 : 0 };
|
||||
}
|
||||
|
||||
protected override IEnumerable<Drawable> EffectTargets => new Drawable[] { textFlow };
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider, OverlayScrollContainer scrollContainer)
|
||||
{
|
||||
IdleColour = colourProvider.Light2;
|
||||
HoverColour = colourProvider.Light1;
|
||||
Action = () => scrollContainer.ScrollTo(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
// 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.Linq;
|
||||
using System.Threading;
|
||||
using osu.Framework.Allocation;
|
||||
@ -10,7 +11,6 @@ using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays.Wiki;
|
||||
using osu.Game.Overlays.Wiki.Markdown;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
@ -31,6 +31,8 @@ namespace osu.Game.Overlays
|
||||
|
||||
private bool displayUpdateRequired = true;
|
||||
|
||||
private WikiArticlePage articlePage;
|
||||
|
||||
public WikiOverlay()
|
||||
: base(OverlayColourScheme.Orange, false)
|
||||
{
|
||||
@ -82,6 +84,17 @@ namespace osu.Game.Overlays
|
||||
}, (cancellationToken = new CancellationTokenSource()).Token);
|
||||
}
|
||||
|
||||
protected override void UpdateAfterChildren()
|
||||
{
|
||||
base.UpdateAfterChildren();
|
||||
|
||||
if (articlePage != null)
|
||||
{
|
||||
articlePage.SidebarContainer.Height = DrawHeight;
|
||||
articlePage.SidebarContainer.Y = Math.Clamp(ScrollFlow.Current - Header.DrawHeight, 0, Math.Max(ScrollFlow.ScrollContent.DrawHeight - DrawHeight - Header.DrawHeight, 0));
|
||||
}
|
||||
}
|
||||
|
||||
private void onPathChanged(ValueChangedEvent<string> e)
|
||||
{
|
||||
cancellationToken?.Cancel();
|
||||
@ -115,39 +128,14 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
else
|
||||
{
|
||||
LoadDisplay(new WikiMarkdownContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
CurrentPath = $@"{api.WebsiteRootUrl}/wiki/{path.Value}/",
|
||||
Text = response.Markdown,
|
||||
DocumentMargin = new MarginPadding(0),
|
||||
DocumentPadding = new MarginPadding
|
||||
{
|
||||
Vertical = 20,
|
||||
Left = 30,
|
||||
Right = 50,
|
||||
},
|
||||
});
|
||||
LoadDisplay(articlePage = new WikiArticlePage($@"{api.WebsiteRootUrl}/wiki/{path.Value}/", response.Markdown));
|
||||
}
|
||||
}
|
||||
|
||||
private void onFail()
|
||||
{
|
||||
LoadDisplay(new WikiMarkdownContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
CurrentPath = $@"{api.WebsiteRootUrl}/wiki/",
|
||||
Text = $"Something went wrong when trying to fetch page \"{path.Value}\".\n\n[Return to the main page](Main_Page).",
|
||||
DocumentMargin = new MarginPadding(0),
|
||||
DocumentPadding = new MarginPadding
|
||||
{
|
||||
Vertical = 20,
|
||||
Left = 30,
|
||||
Right = 50,
|
||||
},
|
||||
});
|
||||
LoadDisplay(articlePage = new WikiArticlePage($@"{api.WebsiteRootUrl}/wiki/",
|
||||
$"Something went wrong when trying to fetch page \"{path.Value}\".\n\n[Return to the main page](Main_Page)."));
|
||||
}
|
||||
|
||||
private void showParentPage()
|
||||
|
47
osu.Game/Performance/HighPerformanceSession.cs
Normal file
47
osu.Game/Performance/HighPerformanceSession.cs
Normal file
@ -0,0 +1,47 @@
|
||||
// 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.Runtime;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
|
||||
namespace osu.Game.Performance
|
||||
{
|
||||
public class HighPerformanceSession : Component
|
||||
{
|
||||
private readonly IBindable<bool> localUserPlaying = new Bindable<bool>();
|
||||
private GCLatencyMode originalGCMode;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuGame game)
|
||||
{
|
||||
localUserPlaying.BindTo(game.LocalUserPlaying);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
localUserPlaying.BindValueChanged(playing =>
|
||||
{
|
||||
if (playing.NewValue)
|
||||
EnableHighPerformanceSession();
|
||||
else
|
||||
DisableHighPerformanceSession();
|
||||
}, true);
|
||||
}
|
||||
|
||||
protected virtual void EnableHighPerformanceSession()
|
||||
{
|
||||
originalGCMode = GCSettings.LatencyMode;
|
||||
GCSettings.LatencyMode = GCLatencyMode.LowLatency;
|
||||
}
|
||||
|
||||
protected virtual void DisableHighPerformanceSession()
|
||||
{
|
||||
if (GCSettings.LatencyMode == GCLatencyMode.LowLatency)
|
||||
GCSettings.LatencyMode = originalGCMode;
|
||||
}
|
||||
}
|
||||
}
|
@ -8,11 +8,11 @@ namespace osu.Game.Rulesets.Difficulty
|
||||
{
|
||||
public class DifficultyAttributes
|
||||
{
|
||||
public Mod[] Mods;
|
||||
public Skill[] Skills;
|
||||
public Mod[] Mods { get; set; }
|
||||
public Skill[] Skills { get; set; }
|
||||
|
||||
public double StarRating;
|
||||
public int MaxCombo;
|
||||
public double StarRating { get; set; }
|
||||
public int MaxCombo { get; set; }
|
||||
|
||||
public DifficultyAttributes()
|
||||
{
|
||||
|
@ -43,6 +43,9 @@ namespace osu.Game.Rulesets.Edit
|
||||
|
||||
protected readonly Ruleset Ruleset;
|
||||
|
||||
// Provides `Playfield`
|
||||
private DependencyContainer dependencies;
|
||||
|
||||
[Resolved]
|
||||
protected EditorClock EditorClock { get; private set; }
|
||||
|
||||
@ -69,6 +72,9 @@ namespace osu.Game.Rulesets.Edit
|
||||
Ruleset = ruleset;
|
||||
}
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) =>
|
||||
dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
@ -88,6 +94,8 @@ namespace osu.Game.Rulesets.Edit
|
||||
return;
|
||||
}
|
||||
|
||||
dependencies.CacheAs(Playfield);
|
||||
|
||||
const float toolbar_width = 200;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
|
@ -1,7 +1,6 @@
|
||||
// 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.Diagnostics;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
@ -32,18 +31,6 @@ namespace osu.Game.Rulesets.Judgements
|
||||
|
||||
private readonly Container aboveHitObjectsContent;
|
||||
|
||||
/// <summary>
|
||||
/// Duration of initial fade in.
|
||||
/// </summary>
|
||||
[Obsolete("Apply any animations manually via ApplyHitAnimations / ApplyMissAnimations. Defaults were moved inside skinned components.")]
|
||||
protected virtual double FadeInDuration => 100;
|
||||
|
||||
/// <summary>
|
||||
/// Duration to wait until fade out begins. Defaults to <see cref="FadeInDuration"/>.
|
||||
/// </summary>
|
||||
[Obsolete("Apply any animations manually via ApplyHitAnimations / ApplyMissAnimations. Defaults were moved inside skinned components.")]
|
||||
protected virtual double FadeOutDelay => FadeInDuration;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a drawable which visualises a <see cref="Judgements.Judgement"/>.
|
||||
/// </summary>
|
||||
|
@ -1,7 +1,6 @@
|
||||
// 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.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
@ -69,14 +68,6 @@ namespace osu.Game.Rulesets.Judgements
|
||||
/// </summary>
|
||||
public double MaxHealthIncrease => HealthIncreaseFor(MaxResult);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the numeric score representation of a <see cref="HitResult"/>.
|
||||
/// </summary>
|
||||
/// <param name="result">The <see cref="HitResult"/> to find the numeric score representation for.</param>
|
||||
/// <returns>The numeric score representation of <paramref name="result"/>.</returns>
|
||||
[Obsolete("Has no effect. Use ToNumericResult(HitResult) (standardised across all rulesets).")] // Can be made non-virtual 20210328
|
||||
protected virtual int NumericResultFor(HitResult result) => ToNumericResult(result);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the numeric score representation of a <see cref="JudgementResult"/>.
|
||||
/// </summary>
|
||||
|
@ -1,7 +1,6 @@
|
||||
// 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 osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mods
|
||||
@ -9,13 +8,12 @@ namespace osu.Game.Rulesets.Mods
|
||||
/// <summary>
|
||||
/// An interface for <see cref="Mod"/>s that can be applied to <see cref="DrawableHitObject"/>s.
|
||||
/// </summary>
|
||||
public interface IApplicableToDrawableHitObjects : IApplicableMod
|
||||
public interface IApplicableToDrawableHitObject : IApplicableMod
|
||||
{
|
||||
/// <summary>
|
||||
/// Applies this <see cref="IApplicableToDrawableHitObjects"/> to a list of <see cref="DrawableHitObject"/>s.
|
||||
/// Applies this <see cref="IApplicableToDrawableHitObject"/> to a <see cref="DrawableHitObject"/>.
|
||||
/// This will only be invoked with top-level <see cref="DrawableHitObject"/>s. Access <see cref="DrawableHitObject.NestedHitObjects"/> if adjusting nested objects is necessary.
|
||||
/// </summary>
|
||||
/// <param name="drawables">The list of <see cref="DrawableHitObject"/>s to apply to.</param>
|
||||
void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables);
|
||||
void ApplyToDrawableHitObject(DrawableHitObject drawable);
|
||||
}
|
||||
}
|
||||
|
18
osu.Game/Rulesets/Mods/IApplicableToDrawableHitObjects.cs
Normal file
18
osu.Game/Rulesets/Mods/IApplicableToDrawableHitObjects.cs
Normal file
@ -0,0 +1,18 @@
|
||||
// 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 osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
[Obsolete(@"Use the singular version IApplicableToDrawableHitObject instead.")] // Can be removed 20211216
|
||||
public interface IApplicableToDrawableHitObjects : IApplicableToDrawableHitObject
|
||||
{
|
||||
void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables);
|
||||
|
||||
void IApplicableToDrawableHitObject.ApplyToDrawableHitObject(DrawableHitObject drawable) => ApplyToDrawableHitObjects(drawable.Yield());
|
||||
}
|
||||
}
|
@ -108,10 +108,14 @@ namespace osu.Game.Rulesets.Mods
|
||||
public virtual bool HasImplementation => this is IApplicableMod;
|
||||
|
||||
/// <summary>
|
||||
/// Returns if this mod is ranked.
|
||||
/// Whether this mod is playable by an end user.
|
||||
/// Should be <c>false</c> for cases where the user is not interacting with the game (so it can be excluded from mutliplayer selection, for example).
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public virtual bool Ranked => false;
|
||||
public virtual bool UserPlayable => true;
|
||||
|
||||
[Obsolete("Going forward, the concept of \"ranked\" doesn't exist. The only exceptions are automation mods, which should now override and set UserPlayable to true.")] // Can be removed 20211009
|
||||
public virtual bool IsRanked => false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this mod requires configuration to apply changes to the game.
|
||||
|
@ -24,6 +24,8 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
public bool RestartOnFail => false;
|
||||
|
||||
public override bool UserPlayable => false;
|
||||
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModRelax), typeof(ModFailCondition), typeof(ModNoFail) };
|
||||
|
||||
public override bool HasImplementation => GetType().GenericTypeArguments.Length == 0;
|
||||
|
@ -17,8 +17,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
public override string Description => "Feeling nostalgic?";
|
||||
|
||||
public override bool Ranked => false;
|
||||
|
||||
public override ModType Type => ModType.Conversion;
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModDoubletime;
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
public override string Description => "Zoooooooooom...";
|
||||
public override bool Ranked => true;
|
||||
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModHalfTime)).ToArray();
|
||||
|
||||
|
@ -15,7 +15,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModEasy;
|
||||
public override ModType Type => ModType.DifficultyReduction;
|
||||
public override double ScoreMultiplier => 0.5;
|
||||
public override bool Ranked => true;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModHardRock), typeof(ModDifficultyAdjust) };
|
||||
|
||||
public virtual void ReadFromDifficulty(BeatmapDifficulty difficulty)
|
||||
|
@ -31,7 +31,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModFlashlight;
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
public override string Description => "Restricted view area.";
|
||||
public override bool Ranked => true;
|
||||
|
||||
internal ModFlashlight()
|
||||
{
|
||||
|
@ -17,7 +17,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override IconUsage? Icon => OsuIcon.ModHalftime;
|
||||
public override ModType Type => ModType.DifficultyReduction;
|
||||
public override string Description => "Less zoom...";
|
||||
public override bool Ranked => true;
|
||||
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModDoubleTime)).ToArray();
|
||||
|
||||
|
@ -14,7 +14,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override string Acronym => "HD";
|
||||
public override IconUsage? Icon => OsuIcon.ModHidden;
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
public override bool Ranked => true;
|
||||
|
||||
public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
|
||||
{
|
||||
|
@ -15,7 +15,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override ModType Type => ModType.DifficultyReduction;
|
||||
public override string Description => "You can't fail, no matter what.";
|
||||
public override double ScoreMultiplier => 0.5;
|
||||
public override bool Ranked => true;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModRelax), typeof(ModFailCondition), typeof(ModAutoplay) };
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override string Acronym => "PF";
|
||||
public override IconUsage? Icon => OsuIcon.ModPerfect;
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
public override bool Ranked => true;
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override string Description => "SS or quit.";
|
||||
|
||||
|
@ -8,7 +8,6 @@ using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays.Settings;
|
||||
|
||||
namespace osu.Game.Rulesets.Mods
|
||||
@ -50,7 +49,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
}
|
||||
}
|
||||
|
||||
private readonly OsuNumberBox seedNumberBox;
|
||||
private readonly SettingsNumberBox.NumberBox seedNumberBox;
|
||||
|
||||
public SeedControl()
|
||||
{
|
||||
@ -76,7 +75,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
seedNumberBox = new OsuNumberBox
|
||||
seedNumberBox = new SettingsNumberBox.NumberBox
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
CommitOnFocusLost = true
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user