diff --git a/osu.Android.props b/osu.Android.props
index b5315c3616..32e236ccd5 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,6 +52,6 @@
-
+
diff --git a/osu.Android/OsuGameAndroid.cs b/osu.Android/OsuGameAndroid.cs
index 21d6336b2c..050bf2b787 100644
--- a/osu.Android/OsuGameAndroid.cs
+++ b/osu.Android/OsuGameAndroid.cs
@@ -7,6 +7,8 @@ using Android.OS;
using osu.Framework.Allocation;
using osu.Game;
using osu.Game.Updater;
+using osu.Game.Utils;
+using Xamarin.Essentials;
namespace osu.Android
{
@@ -72,5 +74,14 @@ namespace osu.Android
}
protected override UpdateManager CreateUpdateManager() => new SimpleUpdateManager();
+
+ protected override BatteryInfo CreateBatteryInfo() => new AndroidBatteryInfo();
+
+ private class AndroidBatteryInfo : BatteryInfo
+ {
+ public override double ChargeLevel => Battery.ChargeLevel;
+
+ public override bool IsCharging => Battery.PowerSource != BatteryPowerSource.Battery;
+ }
}
}
diff --git a/osu.Android/Properties/AndroidManifest.xml b/osu.Android/Properties/AndroidManifest.xml
index 770eaf2222..e717bab310 100644
--- a/osu.Android/Properties/AndroidManifest.xml
+++ b/osu.Android/Properties/AndroidManifest.xml
@@ -6,5 +6,6 @@
+
\ No newline at end of file
diff --git a/osu.Android/osu.Android.csproj b/osu.Android/osu.Android.csproj
index 54857ac87d..582c856a47 100644
--- a/osu.Android/osu.Android.csproj
+++ b/osu.Android/osu.Android.csproj
@@ -63,5 +63,8 @@
5.0.0
+
+
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs
index 485595cea9..12f379bddb 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs
@@ -15,6 +15,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Name => "Mirror";
public override string Acronym => "MR";
public override ModType Type => ModType.Conversion;
+ public override string Description => "Notes are flipped horizontally.";
public override double ScoreMultiplier => 1;
public override bool Ranked => true;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs
index f0db548e74..3b16e9d2b7 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs
@@ -9,6 +9,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Name => "Touch Device";
public override string Acronym => "TD";
+ public override string Description => "Automatically applied to plays on devices with a touchscreen.";
public override double ScoreMultiplier => 1;
public override ModType Type => ModType.System;
diff --git a/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs b/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs
index 1c0bfd56dd..16c1004f37 100644
--- a/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs
+++ b/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs
@@ -144,6 +144,7 @@ namespace osu.Game.Tests.NonVisual
{
public override string Name => nameof(ModA);
public override string Acronym => nameof(ModA);
+ public override string Description => string.Empty;
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(ModIncompatibleWithA), typeof(ModIncompatibleWithAAndB) };
@@ -152,6 +153,7 @@ namespace osu.Game.Tests.NonVisual
private class ModB : Mod
{
public override string Name => nameof(ModB);
+ public override string Description => string.Empty;
public override string Acronym => nameof(ModB);
public override double ScoreMultiplier => 1;
@@ -162,6 +164,7 @@ namespace osu.Game.Tests.NonVisual
{
public override string Name => nameof(ModC);
public override string Acronym => nameof(ModC);
+ public override string Description => string.Empty;
public override double ScoreMultiplier => 1;
}
@@ -169,6 +172,7 @@ namespace osu.Game.Tests.NonVisual
{
public override string Name => $"Incompatible With {nameof(ModA)}";
public override string Acronym => $"Incompatible With {nameof(ModA)}";
+ public override string Description => string.Empty;
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(ModA) };
@@ -187,6 +191,7 @@ namespace osu.Game.Tests.NonVisual
{
public override string Name => $"Incompatible With {nameof(ModA)} and {nameof(ModB)}";
public override string Acronym => $"Incompatible With {nameof(ModA)} and {nameof(ModB)}";
+ public override string Description => string.Empty;
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(ModA), typeof(ModB) };
diff --git a/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs b/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs
index 3afb7481b1..ad2007f202 100644
--- a/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs
+++ b/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs
@@ -140,6 +140,7 @@ namespace osu.Game.Tests.Online
{
public override string Name => "Test Mod";
public override string Acronym => "TM";
+ public override string Description => "This is a test mod.";
public override double ScoreMultiplier => 1;
[SettingSource("Test")]
@@ -156,6 +157,7 @@ namespace osu.Game.Tests.Online
{
public override string Name => "Test Mod";
public override string Acronym => "TMTR";
+ public override string Description => "This is a test mod.";
public override double ScoreMultiplier => 1;
[SettingSource("Initial rate", "The starting speed of the track")]
diff --git a/osu.Game.Tests/Online/TestAPIModMessagePackSerialization.cs b/osu.Game.Tests/Online/TestAPIModMessagePackSerialization.cs
index 74db477cfc..0462e9feb5 100644
--- a/osu.Game.Tests/Online/TestAPIModMessagePackSerialization.cs
+++ b/osu.Game.Tests/Online/TestAPIModMessagePackSerialization.cs
@@ -100,6 +100,7 @@ namespace osu.Game.Tests.Online
{
public override string Name => "Test Mod";
public override string Acronym => "TM";
+ public override string Description => "This is a test mod.";
public override double ScoreMultiplier => 1;
[SettingSource("Test")]
@@ -116,6 +117,7 @@ namespace osu.Game.Tests.Online
{
public override string Name => "Test Mod";
public override string Acronym => "TMTR";
+ public override string Description => "This is a test mod.";
public override double ScoreMultiplier => 1;
[SettingSource("Initial rate", "The starting speed of the track")]
@@ -150,6 +152,7 @@ namespace osu.Game.Tests.Online
{
public override string Name => "Test Mod";
public override string Acronym => "TM";
+ public override string Description => "This is a test mod.";
public override double ScoreMultiplier => 1;
[SettingSource("Test")]
diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
index 655b426e43..f89988cd1a 100644
--- a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
+++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
@@ -65,6 +65,21 @@ namespace osu.Game.Tests.Visual.Background
stack.Push(songSelect = new DummySongSelect());
});
+ ///
+ /// User settings should always be ignored on song select screen.
+ ///
+ [Test]
+ public void TestUserSettingsIgnoredOnSongSelect()
+ {
+ setupUserSettings();
+ AddUntilStep("Screen is undimmed", () => songSelect.IsBackgroundUndimmed());
+ AddUntilStep("Screen using background blur", () => songSelect.IsBackgroundBlur());
+ performFullSetup();
+ AddStep("Exit to song select", () => player.Exit());
+ AddUntilStep("Screen is undimmed", () => songSelect.IsBackgroundUndimmed());
+ AddUntilStep("Screen using background blur", () => songSelect.IsBackgroundBlur());
+ }
+
///
/// Check if properly triggers the visual settings preview when a user hovers over the visual settings panel.
///
@@ -227,17 +242,6 @@ namespace osu.Game.Tests.Visual.Background
songSelect.IsBackgroundUndimmed() && songSelect.IsBackgroundCurrent() && songSelect.CheckBackgroundBlur(results.ExpectedBackgroundBlur));
}
- ///
- /// Check if background gets undimmed and unblurred when leaving for
- ///
- [Test]
- public void TestTransitionOut()
- {
- performFullSetup();
- AddStep("Exit to song select", () => player.Exit());
- AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.IsBlurCorrect());
- }
-
///
/// Check if hovering on the visual settings dialogue after resuming from player still previews the background dim.
///
@@ -333,7 +337,7 @@ namespace osu.Game.Tests.Visual.Background
public bool IsBackgroundVisible() => background.CurrentAlpha == 1;
- public bool IsBlurCorrect() => background.CurrentBlur == new Vector2(BACKGROUND_BLUR);
+ public bool IsBackgroundBlur() => background.CurrentBlur == new Vector2(BACKGROUND_BLUR);
public bool CheckBackgroundBlur(Vector2 expected) => background.CurrentBlur == expected;
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSummaryTimeline.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSummaryTimeline.cs
index 94a9fd7b35..da0c83bb11 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSummaryTimeline.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSummaryTimeline.cs
@@ -5,7 +5,6 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Osu;
-using osu.Game.Rulesets.Osu.Beatmaps;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Components.Timelines.Summary;
using osuTK;
@@ -16,18 +15,28 @@ namespace osu.Game.Tests.Visual.Editing
public class TestSceneEditorSummaryTimeline : EditorClockTestScene
{
[Cached(typeof(EditorBeatmap))]
- private readonly EditorBeatmap editorBeatmap = new EditorBeatmap(new OsuBeatmap());
+ private readonly EditorBeatmap editorBeatmap;
- [BackgroundDependencyLoader]
- private void load()
+ public TestSceneEditorSummaryTimeline()
{
- Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
+ editorBeatmap = new EditorBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo));
+ }
- Add(new SummaryTimeline
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ AddStep("create timeline", () =>
{
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Size = new Vector2(500, 50)
+ // required for track
+ Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap);
+
+ Add(new SummaryTimeline
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(500, 50)
+ });
});
}
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
index 88fbf09ef4..cfdea31a75 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
@@ -25,6 +25,7 @@ using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Screens.Play;
using osu.Game.Screens.Play.PlayerSettings;
+using osu.Game.Utils;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Gameplay
@@ -48,6 +49,9 @@ namespace osu.Game.Tests.Visual.Gameplay
[Cached]
private readonly VolumeOverlay volumeOverlay;
+ [Cached(typeof(BatteryInfo))]
+ private readonly LocalBatteryInfo batteryInfo = new LocalBatteryInfo();
+
private readonly ChangelogOverlay changelogOverlay;
public TestScenePlayerLoader()
@@ -288,6 +292,33 @@ namespace osu.Game.Tests.Visual.Gameplay
}
}
+ [TestCase(false, 1.0, false)] // not charging, above cutoff --> no warning
+ [TestCase(true, 0.1, false)] // charging, below cutoff --> no warning
+ [TestCase(false, 0.25, true)] // not charging, at cutoff --> warning
+ public void TestLowBatteryNotification(bool isCharging, double chargeLevel, bool shouldWarn)
+ {
+ AddStep("reset notification lock", () => sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce).Value = false);
+
+ // set charge status and level
+ AddStep("load player", () => resetPlayer(false, () =>
+ {
+ batteryInfo.SetCharging(isCharging);
+ batteryInfo.SetChargeLevel(chargeLevel);
+ }));
+ AddUntilStep("wait for player", () => player?.LoadState == LoadState.Ready);
+ AddAssert($"notification {(shouldWarn ? "triggered" : "not triggered")}", () => notificationOverlay.UnreadCount.Value == (shouldWarn ? 1 : 0));
+ AddStep("click notification", () =>
+ {
+ var scrollContainer = (OsuScrollContainer)notificationOverlay.Children.Last();
+ var flowContainer = scrollContainer.Children.OfType>().First();
+ var notification = flowContainer.First();
+
+ InputManager.MoveMouseTo(notification);
+ InputManager.Click(MouseButton.Left);
+ });
+ AddUntilStep("wait for player load", () => player.IsLoaded);
+ }
+
[Test]
public void TestEpilepsyWarningEarlyExit()
{
@@ -321,6 +352,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public override string Name => string.Empty;
public override string Acronym => string.Empty;
public override double ScoreMultiplier => 1;
+ public override string Description => string.Empty;
public bool Applied { get; private set; }
@@ -348,5 +380,29 @@ namespace osu.Game.Tests.Visual.Gameplay
throw new TimeoutException();
}
}
+
+ ///
+ /// Mutable dummy BatteryInfo class for
+ ///
+ ///
+ private class LocalBatteryInfo : BatteryInfo
+ {
+ private bool isCharging = true;
+ private double chargeLevel = 1;
+
+ public override bool IsCharging => isCharging;
+
+ public override double ChargeLevel => chargeLevel;
+
+ public void SetCharging(bool value)
+ {
+ isCharging = value;
+ }
+
+ public void SetChargeLevel(double value)
+ {
+ chargeLevel = value;
+ }
+ }
}
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModButton.cs
index 443cf59003..fdc21d80ff 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneModButton.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModButton.cs
@@ -57,6 +57,8 @@ namespace osu.Game.Tests.Visual.UserInterface
private abstract class TestMod : Mod, IApplicableMod
{
public override double ScoreMultiplier => 1.0;
+
+ public override string Description => "This is a test mod.";
}
}
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs
index 89f9b7381b..2158cf77e5 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs
@@ -226,6 +226,8 @@ namespace osu.Game.Tests.Visual.UserInterface
{
public override double ScoreMultiplier => 1.0;
+ public override string Description => "This is a customisable test mod.";
+
public override ModType Type => ModType.Conversion;
[SettingSource("Sample float", "Change something for a mod")]
diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj
index 0e1f6f6b0c..df6d17f615 100644
--- a/osu.Game.Tests/osu.Game.Tests.csproj
+++ b/osu.Game.Tests/osu.Game.Tests.csproj
@@ -22,4 +22,4 @@
-
\ No newline at end of file
+
diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs
index 36eb6964dd..71e1a1efcc 100644
--- a/osu.Game/Configuration/SessionStatics.cs
+++ b/osu.Game/Configuration/SessionStatics.cs
@@ -16,6 +16,7 @@ namespace osu.Game.Configuration
{
SetDefault(Static.LoginOverlayDisplayed, false);
SetDefault(Static.MutedAudioNotificationShownOnce, false);
+ SetDefault(Static.LowBatteryNotificationShownOnce, false);
SetDefault(Static.LastHoverSoundPlaybackTime, (double?)null);
SetDefault(Static.SeasonalBackgrounds, null);
}
@@ -25,6 +26,7 @@ namespace osu.Game.Configuration
{
LoginOverlayDisplayed,
MutedAudioNotificationShownOnce,
+ LowBatteryNotificationShownOnce,
///
/// Info about seasonal backgrounds available fetched from API - see .
diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs
index e285faab11..406819cbd2 100644
--- a/osu.Game/OsuGameBase.cs
+++ b/osu.Game/OsuGameBase.cs
@@ -40,6 +40,7 @@ using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Scoring;
using osu.Game.Skinning;
+using osu.Game.Utils;
using osuTK.Input;
using RuntimeInfo = osu.Framework.RuntimeInfo;
@@ -156,6 +157,8 @@ namespace osu.Game
protected override UserInputManager CreateUserInputManager() => new OsuUserInputManager();
+ protected virtual BatteryInfo CreateBatteryInfo() => null;
+
///
/// The maximum volume at which audio tracks should playback. This can be set lower than 1 to create some head-room for sound effects.
///
@@ -281,6 +284,11 @@ namespace osu.Game
dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory, RulesetStore));
dependencies.Cache(SettingsStore = new SettingsStore(contextFactory));
dependencies.Cache(RulesetConfigCache = new RulesetConfigCache(SettingsStore));
+
+ var powerStatus = CreateBatteryInfo();
+ if (powerStatus != null)
+ dependencies.CacheAs(powerStatus);
+
dependencies.Cache(new SessionStatics());
dependencies.Cache(new OsuColour());
diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs
index 832a14ee1e..4879590e24 100644
--- a/osu.Game/Rulesets/Mods/Mod.cs
+++ b/osu.Game/Rulesets/Mods/Mod.cs
@@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Mods
/// The user readable description of this mod.
///
[JsonIgnore]
- public virtual string Description => string.Empty;
+ public abstract string Description { get; }
///
/// The tooltip to display for this mod when used in a .
diff --git a/osu.Game/Rulesets/Mods/ModNoMod.cs b/osu.Game/Rulesets/Mods/ModNoMod.cs
index 379a2122f2..1009c5bc42 100644
--- a/osu.Game/Rulesets/Mods/ModNoMod.cs
+++ b/osu.Game/Rulesets/Mods/ModNoMod.cs
@@ -12,6 +12,7 @@ namespace osu.Game.Rulesets.Mods
{
public override string Name => "No Mod";
public override string Acronym => "NM";
+ public override string Description => "No mods applied.";
public override double ScoreMultiplier => 1;
public override IconUsage? Icon => FontAwesome.Solid.Ban;
public override ModType Type => ModType.System;
diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
index d95b246c96..669e4cecbe 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
@@ -56,8 +56,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
public virtual IEnumerable GetSamples() => HitObject.Samples;
- private readonly Lazy> nestedHitObjects = new Lazy>();
- public IReadOnlyList NestedHitObjects => nestedHitObjects.IsValueCreated ? nestedHitObjects.Value : (IReadOnlyList)Array.Empty();
+ private readonly List nestedHitObjects = new List();
+ public IReadOnlyList NestedHitObjects => nestedHitObjects;
///
/// Whether this object should handle any user input events.
@@ -249,7 +249,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
// Must be done before the nested DHO is added to occur before the nested Apply()!
drawableNested.ParentHitObject = this;
- nestedHitObjects.Value.Add(drawableNested);
+ nestedHitObjects.Add(drawableNested);
AddNestedHitObject(drawableNested);
}
@@ -305,19 +305,16 @@ namespace osu.Game.Rulesets.Objects.Drawables
if (Samples != null)
Samples.Samples = null;
- if (nestedHitObjects.IsValueCreated)
+ foreach (var obj in nestedHitObjects)
{
- foreach (var obj in nestedHitObjects.Value)
- {
- obj.OnNewResult -= onNewResult;
- obj.OnRevertResult -= onRevertResult;
- obj.ApplyCustomUpdateState -= onApplyCustomUpdateState;
- }
-
- nestedHitObjects.Value.Clear();
- ClearNestedHitObjects();
+ obj.OnNewResult -= onNewResult;
+ obj.OnRevertResult -= onRevertResult;
+ obj.ApplyCustomUpdateState -= onApplyCustomUpdateState;
}
+ nestedHitObjects.Clear();
+ ClearNestedHitObjects();
+
HitObject.DefaultsApplied -= onDefaultsApplied;
OnFree();
diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs
index c40ab4bd94..d55005363c 100644
--- a/osu.Game/Rulesets/UI/Playfield.cs
+++ b/osu.Game/Rulesets/UI/Playfield.cs
@@ -66,7 +66,7 @@ namespace osu.Game.Rulesets.UI
var enumerable = HitObjectContainer.Objects;
- if (nestedPlayfields.IsValueCreated)
+ if (nestedPlayfields.Count != 0)
enumerable = enumerable.Concat(NestedPlayfields.SelectMany(p => p.AllHitObjects));
return enumerable;
@@ -76,9 +76,9 @@ namespace osu.Game.Rulesets.UI
///
/// All s nested inside this .
///
- public IEnumerable NestedPlayfields => nestedPlayfields.IsValueCreated ? nestedPlayfields.Value : Enumerable.Empty();
+ public IEnumerable NestedPlayfields => nestedPlayfields;
- private readonly Lazy> nestedPlayfields = new Lazy>();
+ private readonly List nestedPlayfields = new List();
///
/// Whether judgements should be displayed by this and and all nested s.
@@ -217,7 +217,7 @@ namespace osu.Game.Rulesets.UI
otherPlayfield.HitObjectUsageBegan += h => HitObjectUsageBegan?.Invoke(h);
otherPlayfield.HitObjectUsageFinished += h => HitObjectUsageFinished?.Invoke(h);
- nestedPlayfields.Value.Add(otherPlayfield);
+ nestedPlayfields.Add(otherPlayfield);
}
protected override void LoadComplete()
@@ -279,12 +279,7 @@ namespace osu.Game.Rulesets.UI
return true;
}
- bool removedFromNested = false;
-
- if (nestedPlayfields.IsValueCreated)
- removedFromNested = nestedPlayfields.Value.Any(p => p.Remove(hitObject));
-
- return removedFromNested;
+ return nestedPlayfields.Any(p => p.Remove(hitObject));
}
///
@@ -429,10 +424,7 @@ namespace osu.Game.Rulesets.UI
return;
}
- if (!nestedPlayfields.IsValueCreated)
- return;
-
- foreach (var p in nestedPlayfields.Value)
+ foreach (var p in nestedPlayfields)
p.SetKeepAlive(hitObject, keepAlive);
}
@@ -444,10 +436,7 @@ namespace osu.Game.Rulesets.UI
foreach (var (_, entry) in lifetimeEntryMap)
entry.KeepAlive = true;
- if (!nestedPlayfields.IsValueCreated)
- return;
-
- foreach (var p in nestedPlayfields.Value)
+ foreach (var p in nestedPlayfields)
p.KeepAllAlive();
}
@@ -461,10 +450,7 @@ namespace osu.Game.Rulesets.UI
{
HitObjectContainer.PastLifetimeExtension = value;
- if (!nestedPlayfields.IsValueCreated)
- return;
-
- foreach (var nested in nestedPlayfields.Value)
+ foreach (var nested in nestedPlayfields)
nested.PastLifetimeExtension = value;
}
}
@@ -479,10 +465,7 @@ namespace osu.Game.Rulesets.UI
{
HitObjectContainer.FutureLifetimeExtension = value;
- if (!nestedPlayfields.IsValueCreated)
- return;
-
- foreach (var nested in nestedPlayfields.Value)
+ foreach (var nested in nestedPlayfields)
nested.FutureLifetimeExtension = value;
}
}
diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs
index 10d381b8b7..65bc9cfaea 100644
--- a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs
+++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs
@@ -27,9 +27,12 @@ namespace osu.Game.Screens.Backgrounds
private WorkingBeatmap beatmap;
///
- /// Whether or not user-configured settings relating to brightness of elements should be ignored
+ /// Whether or not user-configured settings relating to brightness of elements should be ignored.
///
- public readonly Bindable IgnoreUserSettings = new Bindable();
+ ///
+ /// Beatmap background screens should not apply user settings by default.
+ ///
+ public readonly Bindable IgnoreUserSettings = new Bindable(true);
public readonly Bindable StoryboardReplacesBackground = new Bindable();
diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BreakPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BreakPart.cs
index e8a4b5c8c7..3d535ec915 100644
--- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BreakPart.cs
+++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BreakPart.cs
@@ -28,7 +28,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
}
[BackgroundDependencyLoader]
- private void load(OsuColour colours) => Colour = colours.Yellow;
+ private void load(OsuColour colours) => Colour = colours.GreyCarmineLight;
}
}
}
diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/GroupVisualisation.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/GroupVisualisation.cs
index 93fe6f9989..8bc8618479 100644
--- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/GroupVisualisation.cs
+++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/GroupVisualisation.cs
@@ -39,7 +39,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
return;
}
- Colour = controlPoints.Any(c => c is TimingControlPoint) ? colours.YellowDark : colours.Green;
+ Colour = Group.ControlPoints.First().GetRepresentingColour(colours);
}, true);
}
}
diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs
index 02cd4bccb4..ae60cd4dd3 100644
--- a/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs
+++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs
@@ -38,6 +38,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary
},
new Container
{
+ Name = "centre line",
RelativeSizeAxes = Axes.Both,
Colour = colours.Gray5,
Children = new Drawable[]
@@ -45,7 +46,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary
new Circle
{
Anchor = Anchor.CentreLeft,
- Origin = Anchor.CentreRight,
+ Origin = Anchor.Centre,
Size = new Vector2(5)
},
new Box
@@ -59,7 +60,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary
new Circle
{
Anchor = Anchor.CentreRight,
- Origin = Anchor.CentreLeft,
+ Origin = Anchor.Centre,
Size = new Vector2(5)
},
}
@@ -69,7 +70,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
- Height = 0.25f
+ Height = 0.10f
}
};
}
diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/DurationVisualisation.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/DurationVisualisation.cs
index de63df5463..ec68bf9c00 100644
--- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/DurationVisualisation.cs
+++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/DurationVisualisation.cs
@@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Visualisations
@@ -10,19 +9,15 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Visualisations
///
/// Represents a spanning point on a timeline part.
///
- public class DurationVisualisation : Container
+ public class DurationVisualisation : Circle
{
protected DurationVisualisation(double startTime, double endTime)
{
- Masking = true;
- CornerRadius = 5;
-
RelativePositionAxes = Axes.X;
RelativeSizeAxes = Axes.Both;
+
X = (float)startTime;
Width = (float)(endTime - startTime);
-
- AddInternal(new Box { RelativeSizeAxes = Axes.Both });
}
}
}
diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/PointVisualisation.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/PointVisualisation.cs
index 53a1f94731..d647c6bfe8 100644
--- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/PointVisualisation.cs
+++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/PointVisualisation.cs
@@ -9,7 +9,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Visualisations
///
/// Represents a singular point on a timeline part.
///
- public class PointVisualisation : Box
+ public class PointVisualisation : Circle
{
public const float MAX_WIDTH = 4;
diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs
index cf15104809..ce580e2b53 100644
--- a/osu.Game/Screens/Play/PlayerLoader.cs
+++ b/osu.Game/Screens/Play/PlayerLoader.cs
@@ -24,6 +24,7 @@ using osu.Game.Overlays.Notifications;
using osu.Game.Screens.Menu;
using osu.Game.Screens.Play.PlayerSettings;
using osu.Game.Users;
+using osu.Game.Utils;
using osuTK;
using osuTK.Graphics;
@@ -112,6 +113,9 @@ namespace osu.Game.Screens.Play
[Resolved]
private AudioManager audioManager { get; set; }
+ [Resolved(CanBeNull = true)]
+ private BatteryInfo batteryInfo { get; set; }
+
public PlayerLoader(Func createPlayer)
{
this.createPlayer = createPlayer;
@@ -121,6 +125,7 @@ namespace osu.Game.Screens.Play
private void load(SessionStatics sessionStatics)
{
muteWarningShownOnce = sessionStatics.GetBindable(Static.MutedAudioNotificationShownOnce);
+ batteryWarningShownOnce = sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce);
InternalChild = (content = new LogoTrackingContainer
{
@@ -196,6 +201,7 @@ namespace osu.Game.Screens.Play
Scheduler.Add(new ScheduledDelegate(pushWhenLoaded, Clock.CurrentTime + 1800, 0));
showMuteWarningIfNeeded();
+ showBatteryWarningIfNeeded();
}
public override void OnResuming(IScreen last)
@@ -470,5 +476,48 @@ namespace osu.Game.Screens.Play
}
#endregion
+
+ #region Low battery warning
+
+ private Bindable batteryWarningShownOnce;
+
+ private void showBatteryWarningIfNeeded()
+ {
+ if (batteryInfo == null) return;
+
+ if (!batteryWarningShownOnce.Value)
+ {
+ if (!batteryInfo.IsCharging && batteryInfo.ChargeLevel <= 0.25)
+ {
+ notificationOverlay?.Post(new BatteryWarningNotification());
+ batteryWarningShownOnce.Value = true;
+ }
+ }
+ }
+
+ private class BatteryWarningNotification : SimpleNotification
+ {
+ public override bool IsImportant => true;
+
+ public BatteryWarningNotification()
+ {
+ Text = "Your battery level is low! Charge your device to prevent interruptions during gameplay.";
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours, NotificationOverlay notificationOverlay)
+ {
+ Icon = FontAwesome.Solid.BatteryQuarter;
+ IconBackgound.Colour = colours.RedDark;
+
+ Activated = delegate
+ {
+ notificationOverlay.Hide();
+ return true;
+ };
+ }
+ }
+
+ #endregion
}
}
diff --git a/osu.Game/Utils/BatteryInfo.cs b/osu.Game/Utils/BatteryInfo.cs
new file mode 100644
index 0000000000..dd9b695e1f
--- /dev/null
+++ b/osu.Game/Utils/BatteryInfo.cs
@@ -0,0 +1,18 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+namespace osu.Game.Utils
+{
+ ///
+ /// Provides access to the system's power status.
+ ///
+ public abstract class BatteryInfo
+ {
+ ///
+ /// The charge level of the battery, from 0 to 1.
+ ///
+ public abstract double ChargeLevel { get; }
+
+ public abstract bool IsCharging { get; }
+ }
+}
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 45b3d5c161..b5405f6262 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -1,4 +1,4 @@
-
+
netstandard2.1
Library
@@ -29,7 +29,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 105a6e59c2..09f6033bfe 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -70,7 +70,7 @@
-
+
@@ -93,7 +93,7 @@
-
+
diff --git a/osu.iOS/OsuGameIOS.cs b/osu.iOS/OsuGameIOS.cs
index 5125ad81e0..702aef45f5 100644
--- a/osu.iOS/OsuGameIOS.cs
+++ b/osu.iOS/OsuGameIOS.cs
@@ -5,6 +5,8 @@ using System;
using Foundation;
using osu.Game;
using osu.Game.Updater;
+using osu.Game.Utils;
+using Xamarin.Essentials;
namespace osu.iOS
{
@@ -13,5 +15,14 @@ namespace osu.iOS
public override Version AssemblyVersion => new Version(NSBundle.MainBundle.InfoDictionary["CFBundleVersion"].ToString());
protected override UpdateManager CreateUpdateManager() => new SimpleUpdateManager();
+
+ protected override BatteryInfo CreateBatteryInfo() => new IOSBatteryInfo();
+
+ private class IOSBatteryInfo : BatteryInfo
+ {
+ public override double ChargeLevel => Battery.ChargeLevel;
+
+ public override bool IsCharging => Battery.PowerSource != BatteryPowerSource.Battery;
+ }
}
}
diff --git a/osu.iOS/osu.iOS.csproj b/osu.iOS/osu.iOS.csproj
index 1e9a21865d..1cbe4422cc 100644
--- a/osu.iOS/osu.iOS.csproj
+++ b/osu.iOS/osu.iOS.csproj
@@ -116,5 +116,8 @@
false
+
+
+