diff --git a/osu.Desktop.VisualTests/Tests/TestCaseUserPanel.cs b/osu.Desktop.VisualTests/Tests/TestCaseUserPanel.cs new file mode 100644 index 0000000000..513bf24e0d --- /dev/null +++ b/osu.Desktop.VisualTests/Tests/TestCaseUserPanel.cs @@ -0,0 +1,57 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Testing; +using osu.Framework.Graphics; +using osu.Game.Users; +using osu.Framework.Graphics.Containers; +using OpenTK; + +namespace osu.Desktop.VisualTests.Tests +{ + internal class TestCaseUserPanel : TestCase + { + public override string Description => @"Panels for displaying a user's status"; + + public override void Reset() + { + base.Reset(); + + UserPanel flyte; + UserPanel peppy; + Add(new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Spacing = new Vector2(10f), + Children = new[] + { + flyte = new UserPanel(new User + { + Username = @"flyte", + Id = 3103765, + Country = new Country { FlagName = @"JP" }, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/3103765/5b012e13611d5761caa7e24fecb3d3a16e1cf48fc2a3032cfd43dd444af83d82.jpeg" + }) { Width = 300 }, + peppy = new UserPanel(new User + { + Username = @"peppy", + Id = 2, + Country = new Country { FlagName = @"AU" }, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/2/08cad88747c235a64fca5f1b770e100f120827ded1ffe3b66bfcd19c940afa65.jpeg" + }) { Width = 300 }, + }, + }); + + flyte.Status.Value = new UserStatusOnline(); + peppy.Status.Value = new UserStatusSoloGame(); + + AddStep(@"spectating", () => { flyte.Status.Value = new UserStatusSpectating(); }); + AddStep(@"multiplaying", () => { flyte.Status.Value = new UserStatusMultiplayerGame(); }); + AddStep(@"modding", () => { flyte.Status.Value = new UserStatusModding(); }); + AddStep(@"offline", () => { flyte.Status.Value = new UserStatusOffline(); }); + AddStep(@"null status", () => { flyte.Status.Value = null; }); + } + } +} diff --git a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj index 8ec0fc83db..68dc8bb7b8 100644 --- a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj +++ b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj @@ -220,6 +220,7 @@ + diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs index 9f91488fe3..3ea05b6558 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs @@ -7,6 +7,8 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics.Backgrounds; using OpenTK.Graphics; +using osu.Game.Beatmaps.ControlPoints; +using osu.Framework.Audio.Track; namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces { @@ -22,6 +24,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces public const float SYMBOL_SIZE = TaikoHitObject.DEFAULT_CIRCLE_DIAMETER * 0.45f; public const float SYMBOL_BORDER = 8; public const float SYMBOL_INNER_SIZE = SYMBOL_SIZE - 2 * SYMBOL_BORDER; + private const double pre_beat_transition_time = 80; /// /// The colour of the inner circle and outer glows. @@ -63,6 +66,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces public CirclePiece(bool isStrong = false) { + EarlyActivationMilliseconds = pre_beat_transition_time; + AddInternal(new Drawable[] { background = new CircularContainer @@ -139,14 +144,31 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces Content.Width = 1 / Content.Scale.X; } + private const float edge_alpha_kiai = 0.5f; + private void resetEdgeEffects() { background.EdgeEffect = new EdgeEffect { Type = EdgeEffectType.Glow, - Colour = AccentColour, - Radius = KiaiMode ? 50 : 8 + Colour = AccentColour.Opacity(KiaiMode ? edge_alpha_kiai : 1f), + Radius = KiaiMode ? 32 : 8 }; } + + protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes) + { + if (!effectPoint.KiaiMode) + return; + + if (beatIndex % (int)timingPoint.TimeSignature != 0) + return; + + double duration = timingPoint.BeatLength * 2; + + background.FadeEdgeEffectTo(1, pre_beat_transition_time, EasingTypes.OutQuint); + using (background.BeginDelayedSequence(pre_beat_transition_time)) + background.FadeEdgeEffectTo(edge_alpha_kiai, duration, EasingTypes.OutQuint); + } } } \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/TaikoPiece.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/TaikoPiece.cs index 83b2e59e44..5e7e9e6350 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/TaikoPiece.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/TaikoPiece.cs @@ -1,14 +1,14 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using OpenTK; using OpenTK.Graphics; +using osu.Game.Graphics.Containers; namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces { - public class TaikoPiece : Container, IHasAccentColour + public class TaikoPiece : BeatSyncedContainer, IHasAccentColour { private Color4 accentColour; /// @@ -17,10 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces public virtual Color4 AccentColour { get { return accentColour; } - set - { - accentColour = value; - } + set { accentColour = value; } } private bool kiaiMode; diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs index 82ceaeed1a..79bb901112 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs @@ -13,12 +13,12 @@ namespace osu.Game.Rulesets.Taiko.Objects /// /// Diameter of a circle relative to the size of the . /// - public const float PLAYFIELD_RELATIVE_DIAMETER = 0.5f; + public const float PLAYFIELD_RELATIVE_DIAMETER = 0.45f; /// /// Scale multiplier for a strong circle. /// - public const float STRONG_CIRCLE_DIAMETER_SCALE = 1.5f; + public const float STRONG_CIRCLE_DIAMETER_SCALE = 1.4f; /// /// Default circle diameter. diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs index 2ebdeaa5b0..c0c329c870 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs @@ -18,22 +18,23 @@ namespace osu.Game.Rulesets.Taiko.UI /// internal class HitExplosion : CircularContainer { - /// - /// The judgement this hit explosion visualises. - /// public readonly TaikoJudgement Judgement; private readonly Box innerFill; - public HitExplosion(TaikoJudgement judgement) - { - Judgement = judgement; + private readonly bool isRim; - Size = new Vector2(TaikoHitObject.DEFAULT_CIRCLE_DIAMETER); + public HitExplosion(TaikoJudgement judgement, bool isRim) + { + this.isRim = isRim; + + Judgement = judgement; Anchor = Anchor.Centre; Origin = Anchor.Centre; + Size = new Vector2(TaikoPlayfield.HIT_TARGET_OFFSET + TaikoHitObject.DEFAULT_CIRCLE_DIAMETER); + RelativePositionAxes = Axes.Both; BorderColour = Color4.White; @@ -54,22 +55,14 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load(OsuColour colours) { - switch (Judgement.TaikoResult) - { - case TaikoHitResult.Good: - innerFill.Colour = colours.Green; - break; - case TaikoHitResult.Great: - innerFill.Colour = colours.Blue; - break; - } + innerFill.Colour = isRim ? colours.BlueDarker : colours.PinkDarker; } protected override void LoadComplete() { base.LoadComplete(); - ScaleTo(5f, 1000, EasingTypes.OutQuint); + ScaleTo(3f, 1000, EasingTypes.OutQuint); FadeOut(500); Expire(); @@ -80,7 +73,7 @@ namespace osu.Game.Rulesets.Taiko.UI /// public void VisualiseSecondHit() { - ResizeTo(Size * TaikoHitObject.STRONG_CIRCLE_DIAMETER_SCALE, 50); + ResizeTo(new Vector2(TaikoPlayfield.HIT_TARGET_OFFSET + TaikoHitObject.DEFAULT_STRONG_CIRCLE_DIAMETER), 50); } } } diff --git a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs new file mode 100644 index 0000000000..e0da3ed3db --- /dev/null +++ b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs @@ -0,0 +1,68 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Rulesets.Taiko.Judgements; +using osu.Game.Rulesets.Taiko.Objects; + +namespace osu.Game.Rulesets.Taiko.UI +{ + public class KiaiHitExplosion : CircularContainer + { + public readonly TaikoJudgement Judgement; + + private readonly bool isRim; + + public KiaiHitExplosion(TaikoJudgement judgement, bool isRim) + { + this.isRim = isRim; + + Judgement = judgement; + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + RelativeSizeAxes = Axes.Y; + Size = new Vector2(TaikoHitObject.DEFAULT_CIRCLE_DIAMETER, 1); + + Masking = true; + Alpha = 0.25f; + + Children = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + EdgeEffect = new EdgeEffect + { + Type = EdgeEffectType.Glow, + Colour = isRim ? colours.BlueDarker : colours.PinkDarker, + Radius = 60, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + ScaleTo(new Vector2(1, 3f), 500, EasingTypes.OutQuint); + FadeOut(250); + + Expire(); + } + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 2278158506..c7bd4a6704 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -24,12 +24,12 @@ namespace osu.Game.Rulesets.Taiko.UI /// /// The default play field height. /// - public const float DEFAULT_PLAYFIELD_HEIGHT = 168f; + public const float DEFAULT_PLAYFIELD_HEIGHT = 178f; /// /// The offset from which the center of the hit target lies at. /// - private const float hit_target_offset = TaikoHitObject.DEFAULT_STRONG_CIRCLE_DIAMETER / 2f + 40; + public const float HIT_TARGET_OFFSET = TaikoHitObject.DEFAULT_STRONG_CIRCLE_DIAMETER / 2f + 40; /// /// The size of the left area of the playfield. This area contains the input drum. @@ -39,15 +39,18 @@ namespace osu.Game.Rulesets.Taiko.UI protected override Container Content => hitObjectContainer; private readonly Container hitExplosionContainer; + private readonly Container kiaiExplosionContainer; private readonly Container barLineContainer; private readonly Container judgementContainer; private readonly Container hitObjectContainer; private readonly Container topLevelHitContainer; - private readonly Container leftBackgroundContainer; - private readonly Container rightBackgroundContainer; - private readonly Box leftBackground; - private readonly Box rightBackground; + + private readonly Container overlayBackgroundContainer; + private readonly Container backgroundContainer; + + private readonly Box overlayBackground; + private readonly Box background; public TaikoPlayfield() { @@ -59,7 +62,7 @@ namespace osu.Game.Rulesets.Taiko.UI Height = DEFAULT_PLAYFIELD_HEIGHT, Children = new[] { - rightBackgroundContainer = new Container + backgroundContainer = new Container { Name = "Transparent playfield background", RelativeSizeAxes = Axes.Both, @@ -73,7 +76,7 @@ namespace osu.Game.Rulesets.Taiko.UI }, Children = new Drawable[] { - rightBackground = new Box + background = new Box { RelativeSizeAxes = Axes.Both, Alpha = 0.6f @@ -82,24 +85,23 @@ namespace osu.Game.Rulesets.Taiko.UI }, new Container { - Name = "Transparent playfield elements", + Name = "Right area", RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = left_area_size }, + Margin = new MarginPadding { Left = left_area_size }, Children = new Drawable[] { new Container { - Name = "Hit target container", - X = hit_target_offset, + Name = "Masked elements", RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = HIT_TARGET_OFFSET }, + Masking = true, Children = new Drawable[] { hitExplosionContainer = new Container { - Anchor = Anchor.CentreLeft, - Origin = Anchor.Centre, RelativeSizeAxes = Axes.Y, - BlendingMode = BlendingMode.Additive + BlendingMode = BlendingMode.Additive, }, barLineContainer = new Container { @@ -114,23 +116,32 @@ namespace osu.Game.Rulesets.Taiko.UI { RelativeSizeAxes = Axes.Both, }, - judgementContainer = new Container - { - RelativeSizeAxes = Axes.Y, - BlendingMode = BlendingMode.Additive - }, - }, + } + }, + kiaiExplosionContainer = new Container + { + Name = "Kiai hit explosions", + RelativeSizeAxes = Axes.Y, + Margin = new MarginPadding { Left = HIT_TARGET_OFFSET }, + BlendingMode = BlendingMode.Additive + }, + judgementContainer = new Container + { + Name = "Judgements", + RelativeSizeAxes = Axes.Y, + Margin = new MarginPadding { Left = HIT_TARGET_OFFSET }, + BlendingMode = BlendingMode.Additive }, } }, - leftBackgroundContainer = new Container + overlayBackgroundContainer = new Container { Name = "Left overlay", Size = new Vector2(left_area_size, DEFAULT_PLAYFIELD_HEIGHT), BorderThickness = 1, Children = new Drawable[] { - leftBackground = new Box + overlayBackground = new Box { RelativeSizeAxes = Axes.Both, }, @@ -164,11 +175,11 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load(OsuColour colours) { - leftBackgroundContainer.BorderColour = colours.Gray0; - leftBackground.Colour = colours.Gray1; + overlayBackgroundContainer.BorderColour = colours.Gray0; + overlayBackground.Colour = colours.Gray1; - rightBackgroundContainer.BorderColour = colours.Gray1; - rightBackground.Colour = colours.Gray0; + backgroundContainer.BorderColour = colours.Gray1; + background.Colour = colours.Gray0; } public override void Add(DrawableHitObject h) @@ -204,6 +215,8 @@ namespace osu.Game.Rulesets.Taiko.UI if (!wasHit) return; + bool isRim = judgedObject.HitObject is RimHit; + if (!secondHit) { if (judgedObject.X >= -0.05f && !(judgedObject is DrawableSwell)) @@ -212,7 +225,11 @@ namespace osu.Game.Rulesets.Taiko.UI topLevelHitContainer.Add(judgedObject.CreateProxy()); } - hitExplosionContainer.Add(new HitExplosion(judgedObject.Judgement)); + hitExplosionContainer.Add(new HitExplosion(judgedObject.Judgement, isRim)); + + if (judgedObject.HitObject.Kiai) + kiaiExplosionContainer.Add(new KiaiHitExplosion(judgedObject.Judgement, isRim)); + } else hitExplosionContainer.Children.FirstOrDefault(e => e.Judgement == judgedObject.Judgement)?.VisualiseSecondHit(); @@ -221,7 +238,7 @@ namespace osu.Game.Rulesets.Taiko.UI /// /// This is a very special type of container. It serves a similar purpose to , however unlike , /// this will only adjust the scale relative to the height of its parent and will maintain the original width relative to its parent. - /// + /// /// /// By adjusting the scale relative to the height of its parent, the aspect ratio of this container's children is maintained, however this is undesirable /// in the case where the hit object container should not have its width adjusted by scale. To counteract this, another container is nested inside this diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj index 983dc72d9e..8d6fcb503c 100644 --- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj +++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj @@ -87,6 +87,7 @@ + diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs index 86a47d8a95..d94388ed87 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs @@ -12,6 +12,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using OpenTK; using osu.Framework.Input; +using osu.Game.Users; namespace osu.Game.Overlays.Settings.Sections.General { @@ -73,9 +74,9 @@ namespace osu.Game.Overlays.Settings.Sections.General case APIState.Online: Children = new Drawable[] { - new OsuSpriteText + new UserPanel(api.LocalUser.Value) { - Text = $"Connected as {api.Username}!", + RelativeSizeAxes = Axes.X, }, new OsuButton { diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs new file mode 100644 index 0000000000..c78a69dac8 --- /dev/null +++ b/osu.Game/Users/UserPanel.cs @@ -0,0 +1,209 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using OpenTK.Graphics; +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Users +{ + public class UserPanel : Container + { + private const float height = 100; + private const float content_padding = 10; + private const float status_height = 30; + + private OsuColour colours; + + private readonly Container statusBar; + private readonly Box statusBg; + private readonly OsuSpriteText statusMessage; + + public readonly Bindable Status = new Bindable(); + + public UserPanel(User user) + { + Height = height - status_height; + Masking = true; + CornerRadius = 5; + EdgeEffect = new EdgeEffect + { + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(0.25f), + Radius = 4, + }; + + Children = new Drawable[] + { + new AsyncLoadWrapper(new CoverBackgroundSprite(user) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + FillMode = FillMode.Fill, + OnLoadComplete = d => d.FadeInFromZero(200), + }) { RelativeSizeAxes = Axes.Both }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black.Opacity(0.7f), + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Top = content_padding, Left = content_padding, Right = content_padding }, + Children = new Drawable[] + { + new UpdateableAvatar + { + Size = new Vector2(height - status_height - content_padding * 2), + User = user, + Masking = true, + CornerRadius = 5, + EdgeEffect = new EdgeEffect + { + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(0.25f), + Radius = 4, + }, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = height - status_height - content_padding }, + Children = new Drawable[] + { + new OsuSpriteText + { + Text = user.Username, + TextSize = 18, + Font = @"Exo2.0-SemiBoldItalic", + }, + new FillFlowContainer + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + AutoSizeAxes = Axes.X, + Height = 20f, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5f, 0f), + Children = new Drawable[] + { + new DrawableFlag(user.Country?.FlagName ?? @"__") + { + Width = 30f, + RelativeSizeAxes = Axes.Y, + }, + new Container + { + Width = 40f, + RelativeSizeAxes = Axes.Y, + }, + new CircularContainer + { + Width = 20f, + RelativeSizeAxes = Axes.Y, + }, + }, + }, + }, + }, + }, + }, + statusBar = new Container + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + Alpha = 0f, + Children = new Drawable[] + { + statusBg = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0.5f, + }, + new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Spacing = new Vector2(5f, 0f), + Children = new[] + { + new TextAwesome + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Icon = FontAwesome.fa_circle_o, + Shadow = true, + TextSize = 14, + }, + statusMessage = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = @"Exo2.0-Semibold", + }, + }, + }, + }, + }, + }; + + Status.ValueChanged += displayStatus; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + this.colours = colours; + } + + private void displayStatus(UserStatus status) + { + const float transition_duration = 500; + + if (status == null) + { + statusBar.ResizeHeightTo(0f, transition_duration, EasingTypes.OutQuint); + statusBar.FadeOut(transition_duration, EasingTypes.OutQuint); + ResizeHeightTo(height - status_height, transition_duration, EasingTypes.OutQuint); + } + else + { + statusBar.ResizeHeightTo(status_height, transition_duration, EasingTypes.OutQuint); + statusBar.FadeIn(transition_duration, EasingTypes.OutQuint); + ResizeHeightTo(height, transition_duration, EasingTypes.OutQuint); + + statusBg.FadeColour(status.GetAppropriateColour(colours), 500, EasingTypes.OutQuint); + statusMessage.Text = status.Message; + } + } + + private class CoverBackgroundSprite : Sprite + { + private readonly User user; + + public CoverBackgroundSprite(User user) + { + this.user = user; + } + + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + if (!string.IsNullOrEmpty(user.CoverUrl)) + Texture = textures.Get(user.CoverUrl); + } + } + } +} diff --git a/osu.Game/Users/UserStatus.cs b/osu.Game/Users/UserStatus.cs new file mode 100644 index 0000000000..dcb5ccbd8f --- /dev/null +++ b/osu.Game/Users/UserStatus.cs @@ -0,0 +1,61 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK.Graphics; +using osu.Game.Graphics; + +namespace osu.Game.Users +{ + public abstract class UserStatus + { + public abstract string Message { get; } + public abstract Color4 GetAppropriateColour(OsuColour colours); + } + + public abstract class UserStatusAvailable : UserStatus + { + public override Color4 GetAppropriateColour(OsuColour colours) => colours.BlueDarker; + } + + public abstract class UserStatusBusy : UserStatus + { + public override Color4 GetAppropriateColour(OsuColour colours) => colours.YellowDark; + } + + public class UserStatusOffline : UserStatus + { + public override string Message => @"Offline"; + public override Color4 GetAppropriateColour(OsuColour colours) => colours.Gray7; + } + + public class UserStatusOnline : UserStatusAvailable + { + public override string Message => @"Online"; + } + + public class UserStatusSpectating : UserStatusAvailable + { + public override string Message => @"Spectating a game"; + } + + public class UserStatusInLobby : UserStatusAvailable + { + public override string Message => @"in Multiplayer Lobby"; + } + + public class UserStatusSoloGame : UserStatusBusy + { + public override string Message => @"Solo Game"; + } + + public class UserStatusMultiplayerGame: UserStatusBusy + { + public override string Message => @"Multiplaying"; + } + + public class UserStatusModding : UserStatus + { + public override string Message => @"Modding a map"; + public override Color4 GetAppropriateColour(OsuColour colours) => colours.PurpleDark; + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 84ccec8763..98fb4b9707 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -432,6 +432,8 @@ + +