mirror of
https://github.com/osukey/osukey.git
synced 2025-08-03 22:56:36 +09:00
Merge branch 'master' of https://github.com/ppy/osu into linkify-metadata
This commit is contained in:
@ -33,23 +33,26 @@ namespace osu.Game.Overlays.AccountCreation
|
||||
private OsuTextBox emailTextBox;
|
||||
private OsuPasswordTextBox passwordTextBox;
|
||||
|
||||
private IAPIProvider api;
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
private ShakeContainer registerShake;
|
||||
private IEnumerable<Drawable> characterCheckText;
|
||||
|
||||
private OsuTextBox[] textboxes;
|
||||
private ProcessingOverlay processingOverlay;
|
||||
private GameHost host;
|
||||
private LoadingLayer loadingLayer;
|
||||
|
||||
[Resolved]
|
||||
private GameHost host { get; set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, IAPIProvider api, GameHost host)
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
this.api = api;
|
||||
this.host = host;
|
||||
FillFlowContainer mainContent;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
mainContent = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
@ -121,7 +124,7 @@ namespace osu.Game.Overlays.AccountCreation
|
||||
},
|
||||
},
|
||||
},
|
||||
processingOverlay = new ProcessingOverlay { Alpha = 0 }
|
||||
loadingLayer = new LoadingLayer(mainContent)
|
||||
};
|
||||
|
||||
textboxes = new[] { usernameTextBox, emailTextBox, passwordTextBox };
|
||||
@ -129,7 +132,7 @@ namespace osu.Game.Overlays.AccountCreation
|
||||
usernameDescription.AddText("This will be your public presence. No profanity, no impersonation. Avoid exposing your own personal details, too!");
|
||||
|
||||
emailAddressDescription.AddText("Will be used for notifications, account verification and in the case you forget your password. No spam, ever.");
|
||||
emailAddressDescription.AddText(" Make sure to get it right!", cp => cp.Font = cp.Font.With(Typeface.Exo, weight: FontWeight.Bold));
|
||||
emailAddressDescription.AddText(" Make sure to get it right!", cp => cp.Font = cp.Font.With(Typeface.Torus, weight: FontWeight.Bold));
|
||||
|
||||
passwordDescription.AddText("At least ");
|
||||
characterCheckText = passwordDescription.AddText("8 characters long");
|
||||
@ -141,7 +144,7 @@ namespace osu.Game.Overlays.AccountCreation
|
||||
public override void OnEntering(IScreen last)
|
||||
{
|
||||
base.OnEntering(last);
|
||||
processingOverlay.Hide();
|
||||
loadingLayer.Hide();
|
||||
|
||||
if (host?.OnScreenKeyboardOverlapsGameWindow != true)
|
||||
focusNextTextbox();
|
||||
@ -159,7 +162,7 @@ namespace osu.Game.Overlays.AccountCreation
|
||||
emailAddressDescription.ClearErrors();
|
||||
passwordDescription.ClearErrors();
|
||||
|
||||
processingOverlay.Show();
|
||||
loadingLayer.Show();
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
@ -192,7 +195,7 @@ namespace osu.Game.Overlays.AccountCreation
|
||||
}
|
||||
|
||||
registerShake.Shake();
|
||||
processingOverlay.Hide();
|
||||
loadingLayer.Hide();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,9 @@ namespace osu.Game.Overlays.AccountCreation
|
||||
{
|
||||
private OsuTextFlowContainer multiAccountExplanationText;
|
||||
private LinkFlowContainer furtherAssistance;
|
||||
private IAPIProvider api;
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
private const string help_centre_url = "/help/wiki/Help_Centre#login";
|
||||
|
||||
@ -39,10 +41,8 @@ namespace osu.Game.Overlays.AccountCreation
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OsuColour colours, IAPIProvider api, OsuGame game, TextureStore textures)
|
||||
private void load(OsuColour colours, OsuGame game, TextureStore textures)
|
||||
{
|
||||
this.api = api;
|
||||
|
||||
if (string.IsNullOrEmpty(api.ProvidedUsername))
|
||||
return;
|
||||
|
||||
|
24
osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs
Normal file
24
osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs
Normal file
@ -0,0 +1,24 @@
|
||||
// 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.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing
|
||||
{
|
||||
public class BeatmapListingHeader : OverlayHeader
|
||||
{
|
||||
protected override ScreenTitle CreateTitle() => new BeatmapListingTitle();
|
||||
|
||||
private class BeatmapListingTitle : ScreenTitle
|
||||
{
|
||||
public BeatmapListingTitle()
|
||||
{
|
||||
Title = @"beatmap";
|
||||
Section = @"listing";
|
||||
}
|
||||
|
||||
protected override Drawable CreateIcon() => new ScreenTitleTextureIcon(@"Icons/changelog");
|
||||
}
|
||||
}
|
||||
}
|
127
osu.Game/Overlays/BeatmapListing/BeatmapListingSearchSection.cs
Normal file
127
osu.Game/Overlays/BeatmapListing/BeatmapListingSearchSection.cs
Normal file
@ -0,0 +1,127 @@
|
||||
// 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.Framework.Graphics.Shapes;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing
|
||||
{
|
||||
public class BeatmapListingSearchSection : CompositeDrawable
|
||||
{
|
||||
public Bindable<string> Query => textBox.Current;
|
||||
|
||||
public Bindable<RulesetInfo> Ruleset => modeFilter.Current;
|
||||
|
||||
public Bindable<BeatmapSearchCategory> Category => categoryFilter.Current;
|
||||
|
||||
public BeatmapSetInfo BeatmapSet
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value == null || string.IsNullOrEmpty(value.OnlineInfo.Covers.Cover))
|
||||
{
|
||||
beatmapCover.FadeOut(600, Easing.OutQuint);
|
||||
return;
|
||||
}
|
||||
|
||||
beatmapCover.BeatmapSet = value;
|
||||
beatmapCover.FadeTo(0.1f, 200, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly BeatmapSearchTextBox textBox;
|
||||
private readonly BeatmapSearchRulesetFilterRow modeFilter;
|
||||
private readonly BeatmapSearchFilterRow<BeatmapSearchCategory> categoryFilter;
|
||||
|
||||
private readonly Box background;
|
||||
private readonly UpdateableBeatmapSetCover beatmapCover;
|
||||
|
||||
public BeatmapListingSearchSection()
|
||||
{
|
||||
AutoSizeAxes = Axes.Y;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
Child = beatmapCover = new UpdateableBeatmapSetCover
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Vertical = 20,
|
||||
Horizontal = 40,
|
||||
},
|
||||
Child = new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 20),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
textBox = new BeatmapSearchTextBox
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
},
|
||||
new ReverseChildIDFillFlowContainer<Drawable>
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
Padding = new MarginPadding { Horizontal = 10 },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
modeFilter = new BeatmapSearchRulesetFilterRow(),
|
||||
categoryFilter = new BeatmapSearchFilterRow<BeatmapSearchCategory>(@"Categories"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Category.Value = BeatmapSearchCategory.Leaderboard;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
background.Colour = colourProvider.Dark6;
|
||||
}
|
||||
|
||||
private class BeatmapSearchTextBox : SearchTextBox
|
||||
{
|
||||
protected override Color4 SelectionColour => Color4.Gray;
|
||||
|
||||
public BeatmapSearchTextBox()
|
||||
{
|
||||
PlaceholderText = @"type in keywords...";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
108
osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs
Normal file
108
osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs
Normal file
@ -0,0 +1,108 @@
|
||||
// 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.Bindables;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Graphics;
|
||||
using osuTK.Graphics;
|
||||
using osuTK;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Overlays.Direct;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing
|
||||
{
|
||||
public class BeatmapListingSortTabControl : OverlaySortTabControl<DirectSortCriteria>
|
||||
{
|
||||
public readonly Bindable<SortDirection> SortDirection = new Bindable<SortDirection>(Overlays.SortDirection.Descending);
|
||||
|
||||
public BeatmapListingSortTabControl()
|
||||
{
|
||||
Current.Value = DirectSortCriteria.Ranked;
|
||||
}
|
||||
|
||||
protected override SortTabControl CreateControl() => new BeatmapSortTabControl
|
||||
{
|
||||
SortDirection = { BindTarget = SortDirection }
|
||||
};
|
||||
|
||||
private class BeatmapSortTabControl : SortTabControl
|
||||
{
|
||||
public readonly Bindable<SortDirection> SortDirection = new Bindable<SortDirection>();
|
||||
|
||||
protected override TabItem<DirectSortCriteria> CreateTabItem(DirectSortCriteria value) => new BeatmapSortTabItem(value)
|
||||
{
|
||||
SortDirection = { BindTarget = SortDirection }
|
||||
};
|
||||
}
|
||||
|
||||
private class BeatmapSortTabItem : SortTabItem
|
||||
{
|
||||
public readonly Bindable<SortDirection> SortDirection = new Bindable<SortDirection>();
|
||||
|
||||
public BeatmapSortTabItem(DirectSortCriteria value)
|
||||
: base(value)
|
||||
{
|
||||
}
|
||||
|
||||
protected override TabButton CreateTabButton(DirectSortCriteria value) => new BeatmapTabButton(value)
|
||||
{
|
||||
Active = { BindTarget = Active },
|
||||
SortDirection = { BindTarget = SortDirection }
|
||||
};
|
||||
}
|
||||
|
||||
private class BeatmapTabButton : TabButton
|
||||
{
|
||||
public readonly Bindable<SortDirection> SortDirection = new Bindable<SortDirection>();
|
||||
|
||||
protected override Color4 ContentColour
|
||||
{
|
||||
set
|
||||
{
|
||||
base.ContentColour = value;
|
||||
icon.Colour = value;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly SpriteIcon icon;
|
||||
|
||||
public BeatmapTabButton(DirectSortCriteria value)
|
||||
: base(value)
|
||||
{
|
||||
Add(icon = new SpriteIcon
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
AlwaysPresent = true,
|
||||
Alpha = 0,
|
||||
Size = new Vector2(6)
|
||||
});
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
SortDirection.BindValueChanged(direction =>
|
||||
{
|
||||
icon.Icon = direction.NewValue == Overlays.SortDirection.Ascending ? FontAwesome.Solid.CaretUp : FontAwesome.Solid.CaretDown;
|
||||
}, true);
|
||||
}
|
||||
|
||||
protected override void UpdateState()
|
||||
{
|
||||
base.UpdateState();
|
||||
icon.FadeTo(Active.Value || IsHovered ? 1 : 0, 200, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override bool OnClick(ClickEvent e)
|
||||
{
|
||||
if (Active.Value)
|
||||
SortDirection.Value = SortDirection.Value == Overlays.SortDirection.Ascending ? Overlays.SortDirection.Descending : Overlays.SortDirection.Ascending;
|
||||
|
||||
return base.OnClick(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
173
osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs
Normal file
173
osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs
Normal file
@ -0,0 +1,173 @@
|
||||
// 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 JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing
|
||||
{
|
||||
public class BeatmapSearchFilterRow<T> : CompositeDrawable, IHasCurrentValue<T>
|
||||
{
|
||||
private readonly BindableWithCurrent<T> current = new BindableWithCurrent<T>();
|
||||
|
||||
public Bindable<T> Current
|
||||
{
|
||||
get => current.Current;
|
||||
set => current.Current = value;
|
||||
}
|
||||
|
||||
public BeatmapSearchFilterRow(string headerName)
|
||||
{
|
||||
AutoSizeAxes = Axes.Y;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AddInternal(new GridContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
ColumnDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.Absolute, size: 100),
|
||||
new Dimension()
|
||||
},
|
||||
RowDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.AutoSize)
|
||||
},
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Font = OsuFont.GetFont(size: 10),
|
||||
Text = headerName.ToUpper()
|
||||
},
|
||||
CreateFilter().With(f =>
|
||||
{
|
||||
f.Current = current;
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
protected virtual BeatmapSearchFilter CreateFilter() => new BeatmapSearchFilter();
|
||||
|
||||
protected class BeatmapSearchFilter : TabControl<T>
|
||||
{
|
||||
public BeatmapSearchFilter()
|
||||
{
|
||||
Anchor = Anchor.BottomLeft;
|
||||
Origin = Anchor.BottomLeft;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = 15;
|
||||
|
||||
TabContainer.Spacing = new Vector2(10, 0);
|
||||
|
||||
if (typeof(T).IsEnum)
|
||||
{
|
||||
foreach (var val in (T[])Enum.GetValues(typeof(T)))
|
||||
AddItem(val);
|
||||
}
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
((FilterDropdown)Dropdown).AccentColour = colourProvider.Light2;
|
||||
}
|
||||
|
||||
protected override Dropdown<T> CreateDropdown() => new FilterDropdown();
|
||||
|
||||
protected override TabItem<T> CreateTabItem(T value) => new FilterTabItem(value);
|
||||
|
||||
protected class FilterTabItem : TabItem<T>
|
||||
{
|
||||
protected virtual float TextSize => 13;
|
||||
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; }
|
||||
|
||||
private readonly OsuSpriteText text;
|
||||
|
||||
public FilterTabItem(T value)
|
||||
: base(value)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Anchor = Anchor.BottomLeft;
|
||||
Origin = Anchor.BottomLeft;
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
text = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: TextSize, weight: FontWeight.Regular),
|
||||
Text = (value as Enum)?.GetDescription() ?? value.ToString()
|
||||
},
|
||||
new HoverClickSounds()
|
||||
});
|
||||
|
||||
Enabled.Value = true;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
updateState();
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
base.OnHover(e);
|
||||
updateState();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
base.OnHoverLost(e);
|
||||
updateState();
|
||||
}
|
||||
|
||||
protected override void OnActivated() => updateState();
|
||||
|
||||
protected override void OnDeactivated() => updateState();
|
||||
|
||||
private void updateState() => text.FadeColour(Active.Value ? Color4.White : getStateColour(), 200, Easing.OutQuint);
|
||||
|
||||
private Color4 getStateColour() => IsHovered ? colourProvider.Light1 : colourProvider.Light3;
|
||||
}
|
||||
|
||||
private class FilterDropdown : OsuTabDropdown<T>
|
||||
{
|
||||
protected override DropdownHeader CreateHeader() => new FilterHeader
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight
|
||||
};
|
||||
|
||||
private class FilterHeader : OsuTabDropdownHeader
|
||||
{
|
||||
public FilterHeader()
|
||||
{
|
||||
Background.Height = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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 osu.Framework.Allocation;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing
|
||||
{
|
||||
public class BeatmapSearchRulesetFilterRow : BeatmapSearchFilterRow<RulesetInfo>
|
||||
{
|
||||
public BeatmapSearchRulesetFilterRow()
|
||||
: base(@"Mode")
|
||||
{
|
||||
}
|
||||
|
||||
protected override BeatmapSearchFilter CreateFilter() => new RulesetFilter();
|
||||
|
||||
private class RulesetFilter : BeatmapSearchFilter
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetStore rulesets)
|
||||
{
|
||||
AddItem(new RulesetInfo
|
||||
{
|
||||
Name = @"Any"
|
||||
});
|
||||
|
||||
foreach (var r in rulesets.AvailableRulesets)
|
||||
AddItem(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing
|
||||
{
|
||||
public class BeatmapSearchSmallFilterRow<T> : BeatmapSearchFilterRow<T>
|
||||
{
|
||||
public BeatmapSearchSmallFilterRow(string headerName)
|
||||
: base(headerName)
|
||||
{
|
||||
}
|
||||
|
||||
protected override BeatmapSearchFilter CreateFilter() => new SmallBeatmapSearchFilter();
|
||||
|
||||
private class SmallBeatmapSearchFilter : BeatmapSearchFilter
|
||||
{
|
||||
protected override TabItem<T> CreateTabItem(T value) => new SmallTabItem(value);
|
||||
|
||||
private class SmallTabItem : FilterTabItem
|
||||
{
|
||||
public SmallTabItem(T value)
|
||||
: base(value)
|
||||
{
|
||||
}
|
||||
|
||||
protected override float TextSize => 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
313
osu.Game/Overlays/BeatmapListingOverlay.cs
Normal file
313
osu.Game/Overlays/BeatmapListingOverlay.cs
Normal file
@ -0,0 +1,313 @@
|
||||
// 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.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Overlays.BeatmapListing;
|
||||
using osu.Game.Overlays.Direct;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
public class BeatmapListingOverlay : FullscreenOverlay
|
||||
{
|
||||
[Resolved]
|
||||
private PreviewTrackManager previewTrackManager { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
private SearchBeatmapSetsRequest getSetsRequest;
|
||||
|
||||
private Drawable currentContent;
|
||||
private BeatmapListingSearchSection searchSection;
|
||||
private BeatmapListingSortTabControl sortControl;
|
||||
|
||||
public BeatmapListingOverlay()
|
||||
: base(OverlayColourScheme.Blue)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = ColourProvider.Background6
|
||||
},
|
||||
new BasicScrollContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
ScrollbarVisible = false,
|
||||
Child = new ReverseChildIDFillFlowContainer<Drawable>
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 10),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
Masking = true,
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Radius = 3,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
},
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new BeatmapListingHeader(),
|
||||
searchSection = new BeatmapListingSearchSection(),
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = ColourProvider.Background4,
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 40,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = ColourProvider.Background5
|
||||
},
|
||||
sortControl = new BeatmapListingSortTabControl
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Margin = new MarginPadding { Left = 20 }
|
||||
}
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Padding = new MarginPadding { Horizontal = 20 },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
panelTarget = new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
},
|
||||
loadingLayer = new LoadingLayer(panelTarget),
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
var sortCriteria = sortControl.Current;
|
||||
var sortDirection = sortControl.SortDirection;
|
||||
|
||||
searchSection.Query.BindValueChanged(query =>
|
||||
{
|
||||
sortCriteria.Value = string.IsNullOrEmpty(query.NewValue) ? DirectSortCriteria.Ranked : DirectSortCriteria.Relevance;
|
||||
sortDirection.Value = SortDirection.Descending;
|
||||
|
||||
queueUpdateSearch(true);
|
||||
});
|
||||
|
||||
searchSection.Ruleset.BindValueChanged(_ => queueUpdateSearch());
|
||||
searchSection.Category.BindValueChanged(_ => queueUpdateSearch());
|
||||
sortCriteria.BindValueChanged(_ => queueUpdateSearch());
|
||||
sortDirection.BindValueChanged(_ => queueUpdateSearch());
|
||||
}
|
||||
|
||||
private ScheduledDelegate queryChangedDebounce;
|
||||
|
||||
private LoadingLayer loadingLayer;
|
||||
private Container panelTarget;
|
||||
|
||||
private void queueUpdateSearch(bool queryTextChanged = false)
|
||||
{
|
||||
getSetsRequest?.Cancel();
|
||||
|
||||
queryChangedDebounce?.Cancel();
|
||||
queryChangedDebounce = Scheduler.AddDelayed(updateSearch, queryTextChanged ? 500 : 100);
|
||||
}
|
||||
|
||||
private void updateSearch()
|
||||
{
|
||||
if (!IsLoaded)
|
||||
return;
|
||||
|
||||
if (State.Value == Visibility.Hidden)
|
||||
return;
|
||||
|
||||
if (API == null)
|
||||
return;
|
||||
|
||||
previewTrackManager.StopAnyPlaying(this);
|
||||
|
||||
loadingLayer.Show();
|
||||
|
||||
getSetsRequest = new SearchBeatmapSetsRequest(
|
||||
searchSection.Query.Value,
|
||||
searchSection.Ruleset.Value,
|
||||
searchSection.Category.Value,
|
||||
sortControl.Current.Value,
|
||||
sortControl.SortDirection.Value);
|
||||
|
||||
getSetsRequest.Success += response => Schedule(() => recreatePanels(response));
|
||||
|
||||
API.Queue(getSetsRequest);
|
||||
}
|
||||
|
||||
private void recreatePanels(SearchBeatmapSetsResponse response)
|
||||
{
|
||||
if (response.Total == 0)
|
||||
{
|
||||
searchSection.BeatmapSet = null;
|
||||
LoadComponentAsync(new NotFoundDrawable(), addContentToPlaceholder);
|
||||
return;
|
||||
}
|
||||
|
||||
var beatmaps = response.BeatmapSets.Select(r => r.ToBeatmapSet(rulesets)).ToList();
|
||||
|
||||
var newPanels = new FillFlowContainer<DirectPanel>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Spacing = new Vector2(10),
|
||||
Alpha = 0,
|
||||
Margin = new MarginPadding { Vertical = 15 },
|
||||
ChildrenEnumerable = beatmaps.Select<BeatmapSetInfo, DirectPanel>(b => new DirectGridPanel(b)
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
})
|
||||
};
|
||||
|
||||
LoadComponentAsync(newPanels, loaded =>
|
||||
{
|
||||
addContentToPlaceholder(loaded);
|
||||
searchSection.BeatmapSet = beatmaps.First();
|
||||
});
|
||||
}
|
||||
|
||||
private void addContentToPlaceholder(Drawable content)
|
||||
{
|
||||
loadingLayer.Hide();
|
||||
|
||||
Drawable lastContent = currentContent;
|
||||
|
||||
if (lastContent != null)
|
||||
{
|
||||
lastContent.FadeOut(100, Easing.OutQuint).Expire();
|
||||
|
||||
// Consider the case when the new content is smaller than the last content.
|
||||
// If the auto-size computation is delayed until fade out completes, the background remain high for too long making the resulting transition to the smaller height look weird.
|
||||
// At the same time, if the last content's height is bypassed immediately, there is a period where the new content is at Alpha = 0 when the auto-sized height will be 0.
|
||||
// To resolve both of these issues, the bypass is delayed until a point when the content transitions (fade-in and fade-out) overlap and it looks good to do so.
|
||||
lastContent.Delay(25).Schedule(() => lastContent.BypassAutoSizeAxes = Axes.Y);
|
||||
}
|
||||
|
||||
panelTarget.Add(currentContent = content);
|
||||
currentContent.FadeIn(200, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
getSetsRequest?.Cancel();
|
||||
queryChangedDebounce?.Cancel();
|
||||
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
|
||||
private class NotFoundDrawable : CompositeDrawable
|
||||
{
|
||||
public NotFoundDrawable()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = 250;
|
||||
Alpha = 0;
|
||||
Margin = new MarginPadding { Top = 15 };
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore textures)
|
||||
{
|
||||
AddInternal(new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(10, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Sprite
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fit,
|
||||
Texture = textures.Get(@"Online/not-found")
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Text = @"... nope, nothing found.",
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -50,7 +51,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
fields.Children = new Drawable[]
|
||||
{
|
||||
new Field("mapped by", BeatmapSet.Metadata.Author.Username, OsuFont.GetFont(weight: FontWeight.Regular, italics: true)),
|
||||
new Field("submitted on", online.Submitted.ToString(@"MMMM d, yyyy"), OsuFont.GetFont(weight: FontWeight.Bold))
|
||||
new Field("submitted", online.Submitted, OsuFont.GetFont(weight: FontWeight.Bold))
|
||||
{
|
||||
Margin = new MarginPadding { Top = 5 },
|
||||
},
|
||||
@ -58,11 +59,11 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
|
||||
if (online.Ranked.HasValue)
|
||||
{
|
||||
fields.Add(new Field("ranked on", online.Ranked.Value.ToString(@"MMMM d, yyyy"), OsuFont.GetFont(weight: FontWeight.Bold)));
|
||||
fields.Add(new Field(online.Status.ToString().ToLowerInvariant(), online.Ranked.Value, OsuFont.GetFont(weight: FontWeight.Bold)));
|
||||
}
|
||||
else if (online.LastUpdated.HasValue)
|
||||
{
|
||||
fields.Add(new Field("last updated on", online.LastUpdated.Value.ToString(@"MMMM d, yyyy"), OsuFont.GetFont(weight: FontWeight.Bold)));
|
||||
fields.Add(new Field("last updated", online.LastUpdated.Value, OsuFont.GetFont(weight: FontWeight.Bold)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,7 +77,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
CornerRadius = 3,
|
||||
CornerRadius = 4,
|
||||
Masking = true,
|
||||
Child = avatar = new UpdateableAvatar
|
||||
{
|
||||
@ -87,7 +88,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Radius = 3,
|
||||
Radius = 4,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
},
|
||||
},
|
||||
@ -117,15 +118,34 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = $"{first} ",
|
||||
Font = OsuFont.GetFont(size: 13)
|
||||
Font = OsuFont.GetFont(size: 11)
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = second,
|
||||
Font = secondFont.With(size: 13)
|
||||
Font = secondFont.With(size: 11)
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public Field(string first, DateTimeOffset second, FontUsage secondFont)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Direction = FillDirection.Horizontal;
|
||||
|
||||
Children = new[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = $"{first} ",
|
||||
Font = OsuFont.GetFont(size: 13)
|
||||
},
|
||||
new DrawableDate(second)
|
||||
{
|
||||
Font = secondFont.With(size: 13)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
@ -105,7 +106,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
TooltipText = name;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Height = 24f;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@ -113,7 +114,8 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new SpriteIcon
|
||||
@ -121,17 +123,17 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.Centre,
|
||||
Icon = FontAwesome.Solid.Square,
|
||||
Size = new Vector2(13),
|
||||
Size = new Vector2(12),
|
||||
Rotation = 45,
|
||||
Colour = OsuColour.FromHex(@"441288"),
|
||||
Colour = Color4Extensions.FromHex(@"441288"),
|
||||
},
|
||||
new SpriteIcon
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.Centre,
|
||||
Icon = icon,
|
||||
Size = new Vector2(13),
|
||||
Colour = OsuColour.FromHex(@"f7dd55"),
|
||||
Size = new Vector2(12),
|
||||
Colour = Color4Extensions.FromHex(@"f7dd55"),
|
||||
Scale = new Vector2(0.8f),
|
||||
},
|
||||
value = new OsuSpriteText
|
||||
@ -139,7 +141,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Margin = new MarginPadding { Left = 10 },
|
||||
Font = OsuFont.GetFont(size: 13, weight: FontWeight.Bold),
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -6,7 +6,6 @@ using System.Linq;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
@ -19,7 +18,6 @@ using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
@ -34,7 +32,6 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
public readonly DifficultiesContainer Difficulties;
|
||||
|
||||
public readonly Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
|
||||
|
||||
private BeatmapSetInfo beatmapSet;
|
||||
|
||||
public BeatmapSetInfo BeatmapSet
|
||||
@ -67,7 +64,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Margin = new MarginPadding { Left = -(tile_icon_padding + tile_spacing / 2) },
|
||||
Margin = new MarginPadding { Left = -(tile_icon_padding + tile_spacing / 2), Bottom = 10 },
|
||||
OnLostHover = () =>
|
||||
{
|
||||
showBeatmap(Beatmap.Value);
|
||||
@ -77,7 +74,6 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Margin = new MarginPadding { Top = 10 },
|
||||
Spacing = new Vector2(5f),
|
||||
Children = new[]
|
||||
{
|
||||
@ -85,13 +81,13 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Font = OsuFont.GetFont(size: 20, weight: FontWeight.Bold)
|
||||
Font = OsuFont.GetFont(size: 17, weight: FontWeight.Bold)
|
||||
},
|
||||
starRating = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Font = OsuFont.GetFont(size: 13, weight: FontWeight.Bold),
|
||||
Font = OsuFont.GetFont(size: 11, weight: FontWeight.Bold),
|
||||
Text = "Star Difficulty",
|
||||
Alpha = 0,
|
||||
Margin = new MarginPadding { Bottom = 1 },
|
||||
@ -192,9 +188,11 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
public class DifficultySelectorButton : OsuClickableContainer, IStateful<DifficultySelectorState>
|
||||
{
|
||||
private const float transition_duration = 100;
|
||||
private const float size = 52;
|
||||
private const float size = 54;
|
||||
private const float background_size = size - 2;
|
||||
|
||||
private readonly Container bg;
|
||||
private readonly Container background;
|
||||
private readonly Box backgroundBox;
|
||||
private readonly DifficultyIcon icon;
|
||||
|
||||
public readonly BeatmapInfo Beatmap;
|
||||
@ -230,16 +228,16 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
bg = new Container
|
||||
background = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Size = new Vector2(background_size),
|
||||
Masking = true,
|
||||
CornerRadius = 4,
|
||||
Child = new Box
|
||||
Child = backgroundBox = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black.Opacity(0.5f),
|
||||
},
|
||||
Alpha = 0.5f
|
||||
}
|
||||
},
|
||||
icon = new DifficultyIcon(beatmap, shouldShowTooltip: false)
|
||||
{
|
||||
@ -273,15 +271,21 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
|
||||
private void fadeIn()
|
||||
{
|
||||
bg.FadeIn(transition_duration);
|
||||
background.FadeIn(transition_duration);
|
||||
icon.FadeIn(transition_duration);
|
||||
}
|
||||
|
||||
private void fadeOut()
|
||||
{
|
||||
bg.FadeOut();
|
||||
background.FadeOut();
|
||||
icon.FadeTo(0.7f, transition_duration);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
backgroundBox.Colour = colourProvider.Background6;
|
||||
}
|
||||
}
|
||||
|
||||
private class Statistic : FillFlowContainer
|
||||
@ -314,13 +318,13 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
Origin = Anchor.CentreLeft,
|
||||
Icon = icon,
|
||||
Shadow = true,
|
||||
Size = new Vector2(13),
|
||||
Size = new Vector2(12),
|
||||
},
|
||||
text = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold, italics: true)
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold, italics: true),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -2,17 +2,14 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
public class BeatmapRulesetSelector : RulesetSelector
|
||||
public class BeatmapRulesetSelector : OverlayRulesetSelector
|
||||
{
|
||||
private readonly Bindable<BeatmapSetInfo> beatmapSet = new Bindable<BeatmapSetInfo>();
|
||||
|
||||
@ -28,21 +25,9 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
}
|
||||
}
|
||||
|
||||
public BeatmapRulesetSelector()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
protected override TabItem<RulesetInfo> CreateTabItem(RulesetInfo value) => new BeatmapRulesetTabItem(value)
|
||||
{
|
||||
BeatmapSet = { BindTarget = beatmapSet }
|
||||
};
|
||||
|
||||
protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(10, 0),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -3,143 +3,74 @@
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
public class BeatmapRulesetTabItem : TabItem<RulesetInfo>
|
||||
public class BeatmapRulesetTabItem : OverlayRulesetTabItem
|
||||
{
|
||||
private readonly OsuSpriteText name, count;
|
||||
private readonly Box bar;
|
||||
|
||||
public readonly Bindable<BeatmapSetInfo> BeatmapSet = new Bindable<BeatmapSetInfo>();
|
||||
|
||||
public override bool PropagatePositionalInputSubTree => Enabled.Value && !Active.Value && base.PropagatePositionalInputSubTree;
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; }
|
||||
|
||||
private OsuSpriteText count;
|
||||
private Container countContainer;
|
||||
|
||||
public BeatmapRulesetTabItem(RulesetInfo value)
|
||||
: base(value)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
FillFlowContainer nameContainer;
|
||||
|
||||
Children = new Drawable[]
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Add(countContainer = new Container
|
||||
{
|
||||
nameContainer = new FillFlowContainer
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Masking = true,
|
||||
CornerRadius = 4f,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Margin = new MarginPadding { Bottom = 7.5f },
|
||||
Spacing = new Vector2(2.5f),
|
||||
Children = new Drawable[]
|
||||
new Box
|
||||
{
|
||||
name = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Text = value.Name,
|
||||
Font = OsuFont.Default.With(size: 18),
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
CornerRadius = 4f,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black.Opacity(0.5f),
|
||||
},
|
||||
count = new OsuSpriteText
|
||||
{
|
||||
Alpha = 0,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Margin = new MarginPadding { Horizontal = 5f },
|
||||
Font = OsuFont.Default.With(weight: FontWeight.SemiBold),
|
||||
}
|
||||
}
|
||||
}
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colourProvider.Background6
|
||||
},
|
||||
count = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Margin = new MarginPadding { Horizontal = 5f },
|
||||
Font = OsuFont.Default.With(weight: FontWeight.SemiBold),
|
||||
Colour = colourProvider.Foreground1,
|
||||
}
|
||||
},
|
||||
bar = new Box
|
||||
{
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
},
|
||||
new HoverClickSounds(),
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
BeatmapSet.BindValueChanged(setInfo =>
|
||||
{
|
||||
var beatmapsCount = setInfo.NewValue?.Beatmaps.Count(b => b.Ruleset.Equals(Value)) ?? 0;
|
||||
|
||||
count.Text = beatmapsCount.ToString();
|
||||
count.Alpha = beatmapsCount > 0 ? 1f : 0f;
|
||||
countContainer.FadeTo(beatmapsCount > 0 ? 1 : 0);
|
||||
|
||||
Enabled.Value = beatmapsCount > 0;
|
||||
}, true);
|
||||
|
||||
Enabled.BindValueChanged(v => nameContainer.Alpha = v.NewValue ? 1f : 0.5f, true);
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colour { get; set; }
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
count.Colour = colour.Gray9;
|
||||
bar.Colour = colour.Blue;
|
||||
|
||||
updateState();
|
||||
}
|
||||
|
||||
private void updateState()
|
||||
{
|
||||
var isHoveredOrActive = IsHovered || Active.Value;
|
||||
|
||||
bar.ResizeHeightTo(isHoveredOrActive ? 4 : 0, 200, Easing.OutQuint);
|
||||
|
||||
name.Colour = isHoveredOrActive ? colour.GrayE : colour.GrayC;
|
||||
name.Font = name.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Regular);
|
||||
}
|
||||
|
||||
#region Hovering and activation logic
|
||||
|
||||
protected override void OnActivated() => updateState();
|
||||
|
||||
protected override void OnDeactivated() => updateState();
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
updateState();
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e) => updateState();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
35
osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs
Normal file
35
osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs
Normal file
@ -0,0 +1,35 @@
|
||||
// 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.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
public class BeatmapSetHeader : OverlayHeader
|
||||
{
|
||||
public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
||||
|
||||
public BeatmapRulesetSelector RulesetSelector { get; private set; }
|
||||
|
||||
protected override ScreenTitle CreateTitle() => new BeatmapHeaderTitle();
|
||||
|
||||
protected override Drawable CreateTitleContent() => RulesetSelector = new BeatmapRulesetSelector
|
||||
{
|
||||
Current = Ruleset
|
||||
};
|
||||
|
||||
private class BeatmapHeaderTitle : ScreenTitle
|
||||
{
|
||||
public BeatmapHeaderTitle()
|
||||
{
|
||||
Title = @"beatmap";
|
||||
Section = @"info";
|
||||
}
|
||||
|
||||
protected override Drawable CreateIcon() => new ScreenTitleTextureIcon(@"Icons/changelog");
|
||||
}
|
||||
}
|
||||
}
|
29
osu.Game/Overlays/BeatmapSet/BeatmapSetLayoutSection.cs
Normal file
29
osu.Game/Overlays/BeatmapSet/BeatmapSetLayoutSection.cs
Normal file
@ -0,0 +1,29 @@
|
||||
// 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.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
public class BeatmapSetLayoutSection : Container
|
||||
{
|
||||
public BeatmapSetLayoutSection()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Masking = true;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Radius = 3,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@ using System.Diagnostics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -25,7 +24,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
private readonly BindableBool favourited = new BindableBool();
|
||||
|
||||
private PostBeatmapFavouriteRequest request;
|
||||
private DimmedLoadingLayer loading;
|
||||
private LoadingLayer loading;
|
||||
|
||||
private readonly Bindable<User> localUser = new Bindable<User>();
|
||||
|
||||
@ -54,14 +53,11 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
Size = new Vector2(18),
|
||||
Shadow = false,
|
||||
},
|
||||
loading = new DimmedLoadingLayer(0.8f, 0.5f),
|
||||
loading = new LoadingLayer(icon, false),
|
||||
});
|
||||
|
||||
Action = () =>
|
||||
{
|
||||
if (loading.State.Value == Visibility.Visible)
|
||||
return;
|
||||
|
||||
// guaranteed by disabled state above.
|
||||
Debug.Assert(BeatmapSet.Value.OnlineBeatmapSetID != null);
|
||||
|
||||
|
@ -2,8 +2,8 @@
|
||||
// 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.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
@ -19,9 +19,9 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
BackgroundColour = OsuColour.FromHex(@"094c5f");
|
||||
Triangles.ColourLight = OsuColour.FromHex(@"0f7c9b");
|
||||
Triangles.ColourDark = OsuColour.FromHex(@"094c5f");
|
||||
BackgroundColour = Color4Extensions.FromHex(@"094c5f");
|
||||
Triangles.ColourLight = Color4Extensions.FromHex(@"0f7c9b");
|
||||
Triangles.ColourDark = Color4Extensions.FromHex(@"094c5f");
|
||||
Triangles.TriangleScale = 1.5f;
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
{
|
||||
public class HeaderDownloadButton : BeatmapDownloadTrackingComposite, IHasTooltip
|
||||
{
|
||||
private const int text_size = 12;
|
||||
|
||||
private readonly bool noVideo;
|
||||
|
||||
public string TooltipText => button.Enabled.Value ? "download this beatmap" : "login to download";
|
||||
@ -80,8 +82,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Icon = FontAwesome.Solid.Download,
|
||||
Size = new Vector2(16),
|
||||
Margin = new MarginPadding { Right = 5 },
|
||||
Size = new Vector2(18),
|
||||
},
|
||||
}
|
||||
},
|
||||
@ -120,7 +121,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "Downloading...",
|
||||
Font = OsuFont.GetFont(size: 13, weight: FontWeight.Bold)
|
||||
Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold)
|
||||
},
|
||||
};
|
||||
break;
|
||||
@ -131,7 +132,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "Importing...",
|
||||
Font = OsuFont.GetFont(size: 13, weight: FontWeight.Bold)
|
||||
Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold)
|
||||
},
|
||||
};
|
||||
break;
|
||||
@ -146,12 +147,12 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "Download",
|
||||
Font = OsuFont.GetFont(size: 13, weight: FontWeight.Bold)
|
||||
Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold)
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = BeatmapSet.Value.OnlineInfo.HasVideo && noVideo ? "without Video" : string.Empty,
|
||||
Font = OsuFont.GetFont(size: 11, weight: FontWeight.Bold)
|
||||
Text = getVideoSuffixText(),
|
||||
Font = OsuFont.GetFont(size: text_size - 2, weight: FontWeight.Bold)
|
||||
},
|
||||
};
|
||||
this.FadeIn(200);
|
||||
@ -163,5 +164,13 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
private void userChanged(ValueChangedEvent<User> e) => button.Enabled.Value = !(e.NewValue is GuestUser);
|
||||
|
||||
private void enabledChanged(ValueChangedEvent<bool> e) => this.FadeColour(e.NewValue ? Color4.White : Color4.Gray, 200, Easing.OutQuint);
|
||||
|
||||
private string getVideoSuffixText()
|
||||
{
|
||||
if (!BeatmapSet.Value.OnlineInfo.HasVideo)
|
||||
return string.Empty;
|
||||
|
||||
return noVideo ? "without Video" : "with Video";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
@ -14,7 +13,6 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Overlays.Direct;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
{
|
||||
@ -22,7 +20,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
{
|
||||
private const float transition_duration = 500;
|
||||
|
||||
private readonly Box bg, progress;
|
||||
private readonly Box background, progress;
|
||||
private readonly PlayButton playButton;
|
||||
|
||||
private PreviewTrack preview => playButton.Preview;
|
||||
@ -40,10 +38,10 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
bg = new Box
|
||||
background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
Alpha = 0.5f
|
||||
},
|
||||
new Container
|
||||
{
|
||||
@ -71,9 +69,10 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OsuColour colours, OverlayColourProvider colourProvider)
|
||||
{
|
||||
progress.Colour = colours.Yellow;
|
||||
background.Colour = colourProvider.Background6;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
@ -91,13 +90,13 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
bg.FadeColour(Color4.Black.Opacity(0.5f), 100);
|
||||
background.FadeTo(0.75f, 80);
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
bg.FadeColour(Color4.Black.Opacity(0.25f), 100);
|
||||
background.FadeTo(0.5f, 80);
|
||||
base.OnHoverLost(e);
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
// 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.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
@ -10,7 +9,6 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays.BeatmapSet.Buttons;
|
||||
using osu.Game.Screens.Select.Details;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
@ -21,6 +19,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
private readonly PreviewButton preview;
|
||||
private readonly BasicStats basic;
|
||||
private readonly AdvancedStats advanced;
|
||||
private readonly DetailBox ratingBox;
|
||||
|
||||
private BeatmapSetInfo beatmapSet;
|
||||
|
||||
@ -54,6 +53,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
private void updateDisplay()
|
||||
{
|
||||
Ratings.Metrics = BeatmapSet?.Metrics;
|
||||
ratingBox.Alpha = BeatmapSet?.OnlineInfo?.Status > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
public Details()
|
||||
@ -74,7 +74,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Margin = new MarginPadding { Vertical = 10 },
|
||||
Padding = new MarginPadding { Vertical = 10 }
|
||||
},
|
||||
},
|
||||
new DetailBox
|
||||
@ -86,7 +86,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
Margin = new MarginPadding { Vertical = 7.5f },
|
||||
},
|
||||
},
|
||||
new DetailBox
|
||||
ratingBox = new DetailBox
|
||||
{
|
||||
Child = Ratings = new UserRatings
|
||||
{
|
||||
@ -107,6 +107,8 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
private class DetailBox : Container
|
||||
{
|
||||
private readonly Container content;
|
||||
private readonly Box background;
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
public DetailBox()
|
||||
@ -116,10 +118,10 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black.Opacity(0.5f),
|
||||
Alpha = 0.5f
|
||||
},
|
||||
content = new Container
|
||||
{
|
||||
@ -129,6 +131,12 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
background.Colour = colourProvider.Background6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,12 +26,11 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
public class Header : BeatmapDownloadTrackingComposite
|
||||
{
|
||||
private const float transition_duration = 200;
|
||||
private const float tabs_height = 50;
|
||||
private const float buttons_height = 45;
|
||||
private const float buttons_spacing = 5;
|
||||
|
||||
private readonly Box tabsBg;
|
||||
private readonly UpdateableBeatmapSetCover cover;
|
||||
private readonly Box coverGradient;
|
||||
private readonly OsuSpriteText title, artist;
|
||||
private readonly AuthorInfo author;
|
||||
private readonly FillFlowContainer downloadButtonsContainer;
|
||||
@ -41,14 +40,13 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
|
||||
public bool DownloadButtonsVisible => downloadButtonsContainer.Any();
|
||||
|
||||
public readonly BeatmapRulesetSelector RulesetSelector;
|
||||
public BeatmapRulesetSelector RulesetSelector => beatmapSetHeader.RulesetSelector;
|
||||
public readonly BeatmapPicker Picker;
|
||||
|
||||
private readonly FavouriteButton favouriteButton;
|
||||
|
||||
private readonly FillFlowContainer fadeContent;
|
||||
|
||||
private readonly LoadingAnimation loading;
|
||||
private readonly LoadingSpinner loading;
|
||||
private readonly BeatmapSetHeader beatmapSetHeader;
|
||||
|
||||
[Cached(typeof(IBindable<RulesetInfo>))]
|
||||
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
|
||||
@ -69,154 +67,147 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
Offset = new Vector2(0f, 1f),
|
||||
};
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
InternalChild = new FillFlowContainer
|
||||
{
|
||||
new Container
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = tabs_height,
|
||||
Children = new Drawable[]
|
||||
beatmapSetHeader = new BeatmapSetHeader
|
||||
{
|
||||
tabsBg = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
RulesetSelector = new BeatmapRulesetSelector
|
||||
{
|
||||
Current = ruleset,
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
}
|
||||
Ruleset = { BindTarget = ruleset },
|
||||
},
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding { Top = tabs_height },
|
||||
Children = new Drawable[]
|
||||
new Container
|
||||
{
|
||||
new Container
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
new Container
|
||||
{
|
||||
cover = new UpdateableBeatmapSetCover
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
},
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.3f), Color4.Black.Opacity(0.8f)),
|
||||
},
|
||||
},
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Top = 20,
|
||||
Bottom = 30,
|
||||
Left = BeatmapSetOverlay.X_PADDING,
|
||||
Right = BeatmapSetOverlay.X_PADDING + BeatmapSetOverlay.RIGHT_WIDTH,
|
||||
},
|
||||
Children = new Drawable[]
|
||||
{
|
||||
fadeContent = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
cover = new UpdateableBeatmapSetCover
|
||||
{
|
||||
new Container
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
},
|
||||
coverGradient = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
},
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Vertical = BeatmapSetOverlay.Y_PADDING,
|
||||
Left = BeatmapSetOverlay.X_PADDING,
|
||||
Right = BeatmapSetOverlay.X_PADDING + BeatmapSetOverlay.RIGHT_WIDTH,
|
||||
},
|
||||
Children = new Drawable[]
|
||||
{
|
||||
fadeContent = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Child = Picker = new BeatmapPicker(),
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Direction = FillDirection.Horizontal,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
new Container
|
||||
{
|
||||
title = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 37, weight: FontWeight.Bold, italics: true)
|
||||
},
|
||||
externalLink = new ExternalLinkButton
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Margin = new MarginPadding { Left = 3, Bottom = 4 }, //To better lineup with the font
|
||||
},
|
||||
}
|
||||
},
|
||||
artist = new OsuSpriteText { Font = OsuFont.GetFont(size: 25, weight: FontWeight.SemiBold, italics: true) },
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Margin = new MarginPadding { Top = 20 },
|
||||
Child = author = new AuthorInfo(),
|
||||
},
|
||||
beatmapAvailability = new BeatmapAvailability(),
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = buttons_height,
|
||||
Margin = new MarginPadding { Top = 10 },
|
||||
Children = new Drawable[]
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Child = Picker = new BeatmapPicker(),
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
favouriteButton = new FavouriteButton
|
||||
Direction = FillDirection.Horizontal,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Margin = new MarginPadding { Top = 15 },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
BeatmapSet = { BindTarget = BeatmapSet }
|
||||
},
|
||||
downloadButtonsContainer = new FillFlowContainer
|
||||
title = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 30, weight: FontWeight.SemiBold, italics: true)
|
||||
},
|
||||
externalLink = new ExternalLinkButton
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Margin = new MarginPadding { Left = 3, Bottom = 4 }, //To better lineup with the font
|
||||
},
|
||||
}
|
||||
},
|
||||
artist = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 20, weight: FontWeight.Medium, italics: true),
|
||||
Margin = new MarginPadding { Bottom = 20 }
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Child = author = new AuthorInfo(),
|
||||
},
|
||||
beatmapAvailability = new BeatmapAvailability(),
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = buttons_height,
|
||||
Margin = new MarginPadding { Top = 10 },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Left = buttons_height + buttons_spacing },
|
||||
Spacing = new Vector2(buttons_spacing),
|
||||
favouriteButton = new FavouriteButton
|
||||
{
|
||||
BeatmapSet = { BindTarget = BeatmapSet }
|
||||
},
|
||||
downloadButtonsContainer = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Left = buttons_height + buttons_spacing },
|
||||
Spacing = new Vector2(buttons_spacing),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
loading = new LoadingAnimation
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Scale = new Vector2(1.5f),
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Margin = new MarginPadding { Top = BeatmapSetOverlay.TOP_PADDING, Right = BeatmapSetOverlay.X_PADDING },
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(10),
|
||||
Children = new Drawable[]
|
||||
}
|
||||
},
|
||||
loading = new LoadingSpinner
|
||||
{
|
||||
onlineStatusPill = new BeatmapSetOnlineStatusPill
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Scale = new Vector2(1.5f),
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Margin = new MarginPadding { Top = BeatmapSetOverlay.Y_PADDING, Right = BeatmapSetOverlay.X_PADDING },
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(10),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
TextSize = 14,
|
||||
TextPadding = new MarginPadding { Horizontal = 25, Vertical = 8 }
|
||||
onlineStatusPill = new BeatmapSetOnlineStatusPill
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
TextSize = 14,
|
||||
TextPadding = new MarginPadding { Horizontal = 35, Vertical = 10 }
|
||||
},
|
||||
Details = new Details(),
|
||||
},
|
||||
Details = new Details(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
Picker.Beatmap.ValueChanged += b =>
|
||||
@ -227,9 +218,10 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
tabsBg.Colour = colours.Gray3;
|
||||
coverGradient.Colour = ColourInfo.GradientVertical(colourProvider.Background6.Opacity(0.3f), colourProvider.Background6.Opacity(0.8f));
|
||||
onlineStatusPill.BackgroundColour = colourProvider.Background6;
|
||||
|
||||
State.BindValueChanged(_ => updateDownloadButtons());
|
||||
|
||||
|
@ -3,10 +3,8 @@
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -16,17 +14,18 @@ using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.Chat;
|
||||
using osu.Game.Screens.Select;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
public class Info : Container
|
||||
{
|
||||
private const float transition_duration = 250;
|
||||
private const float metadata_width = 225;
|
||||
private const float metadata_width = 175;
|
||||
private const float spacing = 20;
|
||||
private const float base_height = 220;
|
||||
|
||||
private readonly Box successRateBackground;
|
||||
private readonly Box background;
|
||||
private readonly SuccessRate successRate;
|
||||
|
||||
public readonly Bindable<BeatmapSetInfo> BeatmapSet = new Bindable<BeatmapSetInfo>();
|
||||
@ -40,23 +39,16 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
public Info()
|
||||
{
|
||||
MetadataSection source, tags, genre, language;
|
||||
OsuSpriteText unrankedPlaceholder;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = 220;
|
||||
Masking = true;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Radius = 3,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
};
|
||||
Height = base_height;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.White,
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
new Container
|
||||
{
|
||||
@ -113,6 +105,14 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Top = 20, Horizontal = 15 },
|
||||
},
|
||||
unrankedPlaceholder = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Alpha = 0,
|
||||
Text = "Unranked beatmap",
|
||||
Font = OsuFont.GetFont(size: 12)
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -125,13 +125,18 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
tags.Text = b.NewValue?.Metadata.Tags ?? string.Empty;
|
||||
genre.Text = b.NewValue?.OnlineInfo?.Genre?.Name ?? string.Empty;
|
||||
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;
|
||||
Height = setHasLeaderboard ? 270 : base_height;
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
successRateBackground.Colour = colours.GrayE;
|
||||
successRateBackground.Colour = colourProvider.Background4;
|
||||
background.Colour = colourProvider.Background5;
|
||||
}
|
||||
|
||||
private class MetadataSection : FillFlowContainer
|
||||
@ -153,7 +158,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
this.FadeIn(transition_duration);
|
||||
|
||||
textFlow.Clear();
|
||||
static void format(SpriteText t) => t.Font = t.Font.With(size: 14);
|
||||
static void format(SpriteText t) => t.Font = t.Font.With(size: 12);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
@ -189,12 +194,11 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
header = new OsuSpriteText
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = this.type.ToString(),
|
||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold),
|
||||
Shadow = false,
|
||||
Margin = new MarginPadding { Top = 20 },
|
||||
Margin = new MarginPadding { Top = 15 },
|
||||
},
|
||||
textFlow = new LinkFlowContainer
|
||||
{
|
||||
@ -203,12 +207,6 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
header.Colour = textFlow.Colour = colours.Gray5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using osu.Game.Screens.Select.Leaderboards;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
@ -26,10 +25,10 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
AccentColour = colours.Blue;
|
||||
LineColour = Color4.Gray;
|
||||
AccentColour = colourProvider.Highlight1;
|
||||
LineColour = colourProvider.Background1;
|
||||
}
|
||||
|
||||
private class ScopeSelectorTabItem : PageTabItem
|
||||
@ -37,7 +36,6 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
public ScopeSelectorTabItem(BeatmapLeaderboardScope value)
|
||||
: base(value)
|
||||
{
|
||||
Text.Font = OsuFont.GetFont(size: 16);
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
|
@ -7,8 +7,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Scoring;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
@ -17,20 +15,15 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
{
|
||||
public class DrawableTopScore : CompositeDrawable
|
||||
{
|
||||
private const float fade_duration = 100;
|
||||
|
||||
private Color4 backgroundIdleColour;
|
||||
private Color4 backgroundHoveredColour;
|
||||
|
||||
private readonly Box background;
|
||||
|
||||
public DrawableTopScore(ScoreInfo score, int position = 1)
|
||||
public DrawableTopScore(ScoreInfo score, int? position = 1)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
Masking = true;
|
||||
CornerRadius = 10;
|
||||
CornerRadius = 4;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
@ -49,7 +42,12 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding(10),
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Vertical = 10,
|
||||
Left = 10,
|
||||
Right = 30,
|
||||
},
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new AutoSizingGrid
|
||||
@ -84,24 +82,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
backgroundIdleColour = colours.Gray3;
|
||||
backgroundHoveredColour = colours.Gray4;
|
||||
|
||||
background.Colour = backgroundIdleColour;
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
background.FadeColour(backgroundHoveredColour, fade_duration, Easing.OutQuint);
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
background.FadeColour(backgroundIdleColour, fade_duration, Easing.OutQuint);
|
||||
base.OnHoverLost(e);
|
||||
background.Colour = colourProvider.Background4;
|
||||
}
|
||||
|
||||
private class AutoSizingGrid : GridContainer
|
||||
|
@ -21,7 +21,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 10),
|
||||
Spacing = new Vector2(0, 20),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
@ -29,9 +29,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Text = @"You need to be an osu!supporter to access the friend and country rankings!",
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold),
|
||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold),
|
||||
},
|
||||
text = new LinkFlowContainer(t => t.Font = t.Font.With(size: 12))
|
||||
text = new LinkFlowContainer(t => t.Font = t.Font.With(size: 11))
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
|
@ -22,8 +22,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
public class ScoreTable : TableContainer
|
||||
{
|
||||
private const float horizontal_inset = 20;
|
||||
private const float row_height = 25;
|
||||
private const int text_size = 14;
|
||||
private const float row_height = 22;
|
||||
private const int text_size = 12;
|
||||
|
||||
private readonly FillFlowContainer backgroundFlow;
|
||||
|
||||
@ -52,22 +52,28 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
highAccuracyColour = colours.GreenLight;
|
||||
}
|
||||
|
||||
public IReadOnlyList<ScoreInfo> Scores
|
||||
private bool showPerformancePoints;
|
||||
|
||||
public void DisplayScores(IReadOnlyList<ScoreInfo> scores, bool showPerformanceColumn)
|
||||
{
|
||||
set
|
||||
{
|
||||
Content = null;
|
||||
backgroundFlow.Clear();
|
||||
ClearScores();
|
||||
|
||||
if (value?.Any() != true)
|
||||
return;
|
||||
if (!scores.Any())
|
||||
return;
|
||||
|
||||
for (int i = 0; i < value.Count; i++)
|
||||
backgroundFlow.Add(new ScoreTableRowBackground(i, value[i]));
|
||||
showPerformancePoints = showPerformanceColumn;
|
||||
|
||||
Columns = createHeaders(value[0]);
|
||||
Content = value.Select((s, i) => createContent(i, s)).ToArray().ToRectangular();
|
||||
}
|
||||
for (int i = 0; i < scores.Count; i++)
|
||||
backgroundFlow.Add(new ScoreTableRowBackground(i, scores[i], row_height));
|
||||
|
||||
Columns = createHeaders(scores.FirstOrDefault());
|
||||
Content = scores.Select((s, i) => createContent(i, s)).ToArray().ToRectangular();
|
||||
}
|
||||
|
||||
public void ClearScores()
|
||||
{
|
||||
Content = null;
|
||||
backgroundFlow.Clear();
|
||||
}
|
||||
|
||||
private TableColumn[] createHeaders(ScoreInfo score)
|
||||
@ -77,25 +83,30 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
new TableColumn("rank", Anchor.CentreRight, new Dimension(GridSizeMode.AutoSize)),
|
||||
new TableColumn("", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 70)), // grade
|
||||
new TableColumn("score", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)),
|
||||
new TableColumn("accuracy", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)),
|
||||
new TableColumn("player", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 150)),
|
||||
new TableColumn("max combo", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 70, maxSize: 90))
|
||||
new TableColumn("accuracy", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, minSize: 60, maxSize: 70)),
|
||||
new TableColumn("", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 25)), // flag
|
||||
new TableColumn("player", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 125)),
|
||||
new TableColumn("max combo", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 70, maxSize: 120))
|
||||
};
|
||||
|
||||
foreach (var statistic in score.Statistics)
|
||||
columns.Add(new TableColumn(statistic.Key.GetDescription(), Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 50, maxSize: 70)));
|
||||
foreach (var statistic in score.SortedStatistics.Take(score.SortedStatistics.Count() - 1))
|
||||
columns.Add(new TableColumn(statistic.Key.GetDescription(), Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 35, maxSize: 60)));
|
||||
|
||||
columns.AddRange(new[]
|
||||
{
|
||||
new TableColumn("pp", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 40, maxSize: 70)),
|
||||
new TableColumn("mods", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)),
|
||||
});
|
||||
columns.Add(new TableColumn(score.SortedStatistics.LastOrDefault().Key.GetDescription(), Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 45, maxSize: 95)));
|
||||
|
||||
if (showPerformancePoints)
|
||||
columns.Add(new TableColumn("pp", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 30)));
|
||||
|
||||
columns.Add(new TableColumn("mods", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)));
|
||||
|
||||
return columns.ToArray();
|
||||
}
|
||||
|
||||
private Drawable[] createContent(int index, ScoreInfo score)
|
||||
{
|
||||
var username = new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: text_size)) { AutoSizeAxes = Axes.Both };
|
||||
username.AddUserLink(score.User);
|
||||
|
||||
var content = new List<Drawable>
|
||||
{
|
||||
new OsuSpriteText
|
||||
@ -105,7 +116,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
},
|
||||
new UpdateableRank(score.Rank)
|
||||
{
|
||||
Size = new Vector2(30, 20)
|
||||
Size = new Vector2(28, 14)
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
@ -116,41 +127,25 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
new OsuSpriteText
|
||||
{
|
||||
Margin = new MarginPadding { Right = horizontal_inset },
|
||||
Text = $@"{score.Accuracy:P2}",
|
||||
Text = score.DisplayAccuracy,
|
||||
Font = OsuFont.GetFont(size: text_size),
|
||||
Colour = score.Accuracy == 1 ? highAccuracyColour : Color4.White
|
||||
},
|
||||
};
|
||||
|
||||
var username = new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: text_size)) { AutoSizeAxes = Axes.Both };
|
||||
username.AddUserLink(score.User);
|
||||
|
||||
content.AddRange(new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
new UpdateableFlag(score.User.Country)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Margin = new MarginPadding { Right = horizontal_inset },
|
||||
Spacing = new Vector2(5, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new UpdateableFlag(score.User.Country)
|
||||
{
|
||||
Size = new Vector2(20, 13),
|
||||
ShowPlaceholderOnNull = false,
|
||||
},
|
||||
username
|
||||
}
|
||||
Size = new Vector2(19, 13),
|
||||
ShowPlaceholderOnNull = false,
|
||||
},
|
||||
username,
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = $@"{score.MaxCombo:N0}x",
|
||||
Font = OsuFont.GetFont(size: text_size)
|
||||
Font = OsuFont.GetFont(size: text_size),
|
||||
Colour = score.MaxCombo == score.Beatmap?.MaxCombo ? highAccuracyColour : Color4.White
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
foreach (var kvp in score.Statistics)
|
||||
foreach (var kvp in score.SortedStatistics)
|
||||
{
|
||||
content.Add(new OsuSpriteText
|
||||
{
|
||||
@ -160,24 +155,25 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
});
|
||||
}
|
||||
|
||||
content.AddRange(new Drawable[]
|
||||
if (showPerformancePoints)
|
||||
{
|
||||
new OsuSpriteText
|
||||
content.Add(new OsuSpriteText
|
||||
{
|
||||
Text = $@"{score.PP:N0}",
|
||||
Font = OsuFont.GetFont(size: text_size)
|
||||
},
|
||||
new FillFlowContainer
|
||||
});
|
||||
}
|
||||
|
||||
content.Add(new FillFlowContainer
|
||||
{
|
||||
Direction = FillDirection.Horizontal,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Spacing = new Vector2(1),
|
||||
ChildrenEnumerable = score.Mods.Select(m => new ModIcon(m)
|
||||
{
|
||||
Direction = FillDirection.Horizontal,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Spacing = new Vector2(1),
|
||||
ChildrenEnumerable = score.Mods.Select(m => new ModIcon(m)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Scale = new Vector2(0.3f)
|
||||
})
|
||||
},
|
||||
Scale = new Vector2(0.3f)
|
||||
})
|
||||
});
|
||||
|
||||
return content.ToArray();
|
||||
@ -190,7 +186,13 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
public HeaderText(string text)
|
||||
{
|
||||
Text = text.ToUpper();
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Black);
|
||||
Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
Colour = colourProvider.Foreground1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,15 +22,15 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
private readonly int index;
|
||||
private readonly ScoreInfo score;
|
||||
|
||||
public ScoreTableRowBackground(int index, ScoreInfo score)
|
||||
public ScoreTableRowBackground(int index, ScoreInfo score, float height)
|
||||
{
|
||||
this.index = index;
|
||||
this.score = score;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = 25;
|
||||
Height = height;
|
||||
|
||||
CornerRadius = 3;
|
||||
CornerRadius = 5;
|
||||
Masking = true;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
@ -48,18 +48,18 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, IAPIProvider api)
|
||||
private void load(OsuColour colours, OverlayColourProvider colourProvider, IAPIProvider api)
|
||||
{
|
||||
var isOwnScore = api.LocalUser.Value.Id == score.UserID;
|
||||
|
||||
if (isOwnScore)
|
||||
background.Colour = colours.GreenDarker;
|
||||
else if (index % 2 == 0)
|
||||
background.Colour = colours.Gray3;
|
||||
background.Colour = colourProvider.Background4;
|
||||
else
|
||||
background.Alpha = 0;
|
||||
|
||||
hoveredBackground.Colour = isOwnScore ? colours.GreenDark : colours.Gray4;
|
||||
hoveredBackground.Colour = isOwnScore ? colours.GreenDark : colourProvider.Background3;
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
|
@ -5,8 +5,6 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK;
|
||||
using System.Linq;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
@ -14,13 +12,14 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Select.Leaderboards;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
{
|
||||
public class ScoresContainer : CompositeDrawable
|
||||
public class ScoresContainer : BeatmapSetLayoutSection
|
||||
{
|
||||
private const int spacing = 15;
|
||||
|
||||
@ -32,10 +31,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
private readonly Box background;
|
||||
private readonly ScoreTable scoreTable;
|
||||
private readonly FillFlowContainer topScoresContainer;
|
||||
private readonly DimmedLoadingLayer loading;
|
||||
private readonly LoadingLayer loading;
|
||||
private readonly LeaderboardModSelector modSelector;
|
||||
private readonly NoScoresPlaceholder noScoresPlaceholder;
|
||||
private readonly FillFlowContainer content;
|
||||
private readonly NotSupporterPlaceholder notSupporterPlaceholder;
|
||||
|
||||
[Resolved]
|
||||
@ -54,17 +52,17 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
|
||||
if (value?.Scores.Any() != true)
|
||||
{
|
||||
scoreTable.Scores = null;
|
||||
scoreTable.ClearScores();
|
||||
scoreTable.Hide();
|
||||
return;
|
||||
}
|
||||
|
||||
var scoreInfos = value.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToList();
|
||||
var topScore = scoreInfos.First();
|
||||
|
||||
scoreTable.Scores = scoreInfos;
|
||||
scoreTable.DisplayScores(scoreInfos, topScore.Beatmap?.Status == BeatmapSetOnlineStatus.Ranked);
|
||||
scoreTable.Show();
|
||||
|
||||
var topScore = scoreInfos.First();
|
||||
var userScore = value.UserScore;
|
||||
var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets);
|
||||
|
||||
@ -77,23 +75,21 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
|
||||
public ScoresContainer()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
InternalChildren = new Drawable[]
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
content = new FillFlowContainer
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Width = 0.95f,
|
||||
Direction = FillDirection.Vertical,
|
||||
Margin = new MarginPadding { Vertical = spacing },
|
||||
Padding = new MarginPadding { Horizontal = 50 },
|
||||
Margin = new MarginPadding { Vertical = 20 },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
@ -122,7 +118,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Margin = new MarginPadding { Vertical = spacing },
|
||||
Margin = new MarginPadding { Top = spacing },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
noScoresPlaceholder = new NoScoresPlaceholder
|
||||
@ -161,27 +157,18 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
}
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
CornerRadius = 10,
|
||||
Child = loading = new DimmedLoadingLayer(iconScale: 0.8f)
|
||||
{
|
||||
Alpha = 0,
|
||||
},
|
||||
}
|
||||
loading = new LoadingLayer()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
background.Colour = colours.Gray2;
|
||||
background.Colour = colourProvider.Background5;
|
||||
|
||||
user.BindTo(api.LocalUser);
|
||||
}
|
||||
@ -192,8 +179,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
scope.BindValueChanged(_ => getScores());
|
||||
ruleset.BindValueChanged(_ => getScores());
|
||||
|
||||
modSelector.SelectedMods.ItemsAdded += _ => getScores();
|
||||
modSelector.SelectedMods.ItemsRemoved += _ => getScores();
|
||||
modSelector.SelectedMods.CollectionChanged += (_, __) => getScores();
|
||||
|
||||
Beatmap.BindValueChanged(onBeatmapChanged);
|
||||
user.BindValueChanged(onUserChanged, true);
|
||||
@ -234,7 +220,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
if (Beatmap.Value?.OnlineBeatmapID.HasValue != true || Beatmap.Value.Status <= BeatmapSetOnlineStatus.Pending)
|
||||
{
|
||||
Scores = null;
|
||||
content.Hide();
|
||||
Hide();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -248,7 +234,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
|
||||
notSupporterPlaceholder.Hide();
|
||||
|
||||
content.Show();
|
||||
Show();
|
||||
loading.Show();
|
||||
|
||||
getScoresRequest = new GetScoresRequest(Beatmap.Value, Beatmap.Value.Ruleset, scope.Value, modSelector.SelectedMods);
|
||||
|
@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
@ -23,9 +24,11 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
public class TopScoreStatisticsSection : CompositeDrawable
|
||||
{
|
||||
private const float margin = 10;
|
||||
private const float top_columns_min_width = 64;
|
||||
private const float bottom_columns_min_width = 45;
|
||||
|
||||
private readonly FontUsage smallFont = OsuFont.GetFont(size: 20);
|
||||
private readonly FontUsage largeFont = OsuFont.GetFont(size: 25);
|
||||
private readonly FontUsage smallFont = OsuFont.GetFont(size: 16);
|
||||
private readonly FontUsage largeFont = OsuFont.GetFont(size: 22, weight: FontWeight.Light);
|
||||
|
||||
private readonly TextColumn totalScoreColumn;
|
||||
private readonly TextColumn accuracyColumn;
|
||||
@ -44,9 +47,23 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Spacing = new Vector2(10, 0),
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(margin, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
totalScoreColumn = new TextColumn("total score", largeFont, top_columns_min_width),
|
||||
accuracyColumn = new TextColumn("accuracy", largeFont, top_columns_min_width),
|
||||
maxComboColumn = new TextColumn("max combo", largeFont, top_columns_min_width)
|
||||
}
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
@ -62,24 +79,10 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(margin, 0),
|
||||
},
|
||||
ppColumn = new TextColumn("pp", smallFont),
|
||||
ppColumn = new TextColumn("pp", smallFont, bottom_columns_min_width),
|
||||
modsColumn = new ModsInfoColumn(),
|
||||
}
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(margin, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
totalScoreColumn = new TextColumn("total score", largeFont),
|
||||
accuracyColumn = new TextColumn("accuracy", largeFont),
|
||||
maxComboColumn = new TextColumn("max combo", largeFont)
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -92,16 +95,17 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
set
|
||||
{
|
||||
totalScoreColumn.Text = $@"{value.TotalScore:N0}";
|
||||
accuracyColumn.Text = $@"{value.Accuracy:P2}";
|
||||
accuracyColumn.Text = value.DisplayAccuracy;
|
||||
maxComboColumn.Text = $@"{value.MaxCombo:N0}x";
|
||||
ppColumn.Alpha = value.Beatmap?.Status == BeatmapSetOnlineStatus.Ranked ? 1 : 0;
|
||||
ppColumn.Text = $@"{value.PP:N0}";
|
||||
|
||||
statisticsColumns.ChildrenEnumerable = value.Statistics.Select(kvp => createStatisticsColumn(kvp.Key, kvp.Value));
|
||||
statisticsColumns.ChildrenEnumerable = value.SortedStatistics.Select(kvp => createStatisticsColumn(kvp.Key, kvp.Value));
|
||||
modsColumn.Mods = value.Mods;
|
||||
}
|
||||
}
|
||||
|
||||
private TextColumn createStatisticsColumn(HitResult hitResult, int count) => new TextColumn(hitResult.GetDescription(), smallFont)
|
||||
private TextColumn createStatisticsColumn(HitResult hitResult, int count) => new TextColumn(hitResult.GetDescription(), smallFont, bottom_columns_min_width)
|
||||
{
|
||||
Text = count.ToString()
|
||||
};
|
||||
@ -109,37 +113,61 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
private class InfoColumn : CompositeDrawable
|
||||
{
|
||||
private readonly Box separator;
|
||||
private readonly OsuSpriteText text;
|
||||
|
||||
public InfoColumn(string title, Drawable content)
|
||||
public InfoColumn(string title, Drawable content, float? minWidth = null)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Margin = new MarginPadding { Vertical = 5 };
|
||||
|
||||
InternalChild = new FillFlowContainer
|
||||
InternalChild = new GridContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 2),
|
||||
Children = new[]
|
||||
ColumnDimensions = new[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
new Dimension(GridSizeMode.AutoSize, minSize: minWidth ?? 0)
|
||||
},
|
||||
RowDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension(GridSizeMode.Absolute, 2),
|
||||
new Dimension(GridSizeMode.AutoSize)
|
||||
},
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Black),
|
||||
Text = title.ToUpper()
|
||||
text = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold),
|
||||
Text = title.ToUpper(),
|
||||
// 2px padding bottom + 1px vertical to compensate for the additional spacing because of 1.25 line-height in osu-web
|
||||
Padding = new MarginPadding { Top = 1, Bottom = 3 }
|
||||
}
|
||||
},
|
||||
separator = new Box
|
||||
new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 2
|
||||
separator = new Box
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 2,
|
||||
},
|
||||
},
|
||||
content
|
||||
new[]
|
||||
{
|
||||
// osu-web has 4px margin here but also uses 0.9 line-height, reducing margin to 2px seems like a good alternative to that
|
||||
content.With(c => c.Margin = new MarginPadding { Top = 2 })
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
separator.Colour = colours.Gray5;
|
||||
text.Colour = colourProvider.Foreground1;
|
||||
separator.Colour = colourProvider.Background3;
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,13 +175,13 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
{
|
||||
private readonly SpriteText text;
|
||||
|
||||
public TextColumn(string title, FontUsage font)
|
||||
: this(title, new OsuSpriteText { Font = font })
|
||||
public TextColumn(string title, FontUsage font, float? minWidth = null)
|
||||
: this(title, new OsuSpriteText { Font = font }, minWidth)
|
||||
{
|
||||
}
|
||||
|
||||
private TextColumn(string title, SpriteText text)
|
||||
: base(title, text)
|
||||
private TextColumn(string title, SpriteText text, float? minWidth = null)
|
||||
: base(title, text, minWidth)
|
||||
{
|
||||
this.text = text;
|
||||
}
|
||||
@ -171,9 +199,10 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
public ModsInfoColumn()
|
||||
: this(new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(1),
|
||||
Height = 18f
|
||||
})
|
||||
{
|
||||
}
|
||||
@ -189,15 +218,11 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
set
|
||||
{
|
||||
modsContainer.Clear();
|
||||
|
||||
foreach (Mod mod in value)
|
||||
modsContainer.Children = value.Select(mod => new ModIcon(mod)
|
||||
{
|
||||
modsContainer.Add(new ModIcon(mod)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Scale = new Vector2(0.3f),
|
||||
});
|
||||
}
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Scale = new Vector2(0.25f),
|
||||
}).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +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 System;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -13,7 +13,6 @@ using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.Leaderboards;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Users.Drawables;
|
||||
using osu.Game.Utils;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -25,7 +24,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
private readonly UpdateableRank rank;
|
||||
private readonly UpdateableAvatar avatar;
|
||||
private readonly LinkFlowContainer usernameText;
|
||||
private readonly SpriteText date;
|
||||
private readonly DrawableDate achievedOn;
|
||||
private readonly UpdateableFlag flag;
|
||||
|
||||
public TopScoreUserSection()
|
||||
@ -51,13 +50,13 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Font = OsuFont.GetFont(size: 24, weight: FontWeight.Bold, italics: true)
|
||||
Font = OsuFont.GetFont(size: 18, weight: FontWeight.Bold)
|
||||
},
|
||||
rank = new UpdateableRank(ScoreRank.D)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(40),
|
||||
Size = new Vector2(28),
|
||||
FillMode = FillMode.Fit,
|
||||
},
|
||||
}
|
||||
@ -66,9 +65,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(80),
|
||||
Size = new Vector2(70),
|
||||
Masking = true,
|
||||
CornerRadius = 5,
|
||||
CornerRadius = 4,
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
@ -87,23 +86,37 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
Spacing = new Vector2(0, 3),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
usernameText = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 20, weight: FontWeight.Bold, italics: true))
|
||||
usernameText = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 18, weight: FontWeight.Bold, italics: true))
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
},
|
||||
date = new OsuSpriteText
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Font = OsuFont.GetFont(size: 15, weight: FontWeight.Bold)
|
||||
Children = new[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "achieved ",
|
||||
Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold)
|
||||
},
|
||||
achievedOn = new DrawableDate(DateTimeOffset.MinValue)
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold)
|
||||
},
|
||||
}
|
||||
},
|
||||
flag = new UpdateableFlag
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Size = new Vector2(20, 13),
|
||||
Size = new Vector2(19, 13),
|
||||
Margin = new MarginPadding { Top = 3 }, // makes spacing look more even
|
||||
ShowPlaceholderOnNull = false,
|
||||
},
|
||||
}
|
||||
@ -112,15 +125,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
public int? ScorePosition
|
||||
{
|
||||
rankText.Colour = colours.Yellow;
|
||||
}
|
||||
|
||||
public int ScorePosition
|
||||
{
|
||||
set => rankText.Text = $"#{value}";
|
||||
set => rankText.Text = value == null ? "-" : $"#{value}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -132,7 +139,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
{
|
||||
avatar.User = value.User;
|
||||
flag.Country = value.User.Country;
|
||||
date.Text = $@"achieved {HumanizerUtils.Humanize(value.Date)}";
|
||||
achievedOn.Date = value.Date;
|
||||
|
||||
usernameText.Clear();
|
||||
usernameText.AddUserLink(value.User);
|
||||
|
@ -17,7 +17,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
protected readonly FailRetryGraph Graph;
|
||||
|
||||
private readonly FillFlowContainer header;
|
||||
private readonly OsuSpriteText successRateLabel, successPercent, graphLabel;
|
||||
private readonly OsuSpriteText successPercent;
|
||||
private readonly Bar successRate;
|
||||
private readonly Container percentContainer;
|
||||
|
||||
@ -42,7 +42,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
int playCount = beatmap?.OnlineInfo?.PlayCount ?? 0;
|
||||
|
||||
var rate = playCount != 0 ? (float)passCount / playCount : 0;
|
||||
successPercent.Text = rate.ToString("0%");
|
||||
successPercent.Text = rate.ToString("0.#%");
|
||||
successRate.Length = rate;
|
||||
percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic);
|
||||
|
||||
@ -60,12 +60,12 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
successRateLabel = new OsuSpriteText
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Text = "Success Rate",
|
||||
Font = OsuFont.GetFont(size: 13)
|
||||
Font = OsuFont.GetFont(size: 12)
|
||||
},
|
||||
successRate = new Bar
|
||||
{
|
||||
@ -82,15 +82,15 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopCentre,
|
||||
Font = OsuFont.GetFont(size: 13),
|
||||
Font = OsuFont.GetFont(size: 12),
|
||||
},
|
||||
},
|
||||
graphLabel = new OsuSpriteText
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Text = "Points of Failure",
|
||||
Font = OsuFont.GetFont(size: 13),
|
||||
Font = OsuFont.GetFont(size: 12),
|
||||
Margin = new MarginPadding { Vertical = 20 },
|
||||
},
|
||||
},
|
||||
@ -105,11 +105,10 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OsuColour colours, OverlayColourProvider colourProvider)
|
||||
{
|
||||
successRateLabel.Colour = successPercent.Colour = graphLabel.Colour = colours.Gray5;
|
||||
successRate.AccentColour = colours.Green;
|
||||
successRate.BackgroundColour = colours.GrayD;
|
||||
successRate.BackgroundColour = colourProvider.Background6;
|
||||
|
||||
updateDisplay();
|
||||
}
|
||||
|
@ -9,11 +9,11 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Overlays.BeatmapSet;
|
||||
using osu.Game.Overlays.BeatmapSet.Scores;
|
||||
using osu.Game.Overlays.Comments;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK;
|
||||
|
||||
@ -22,47 +22,64 @@ namespace osu.Game.Overlays
|
||||
public class BeatmapSetOverlay : FullscreenOverlay
|
||||
{
|
||||
public const float X_PADDING = 40;
|
||||
public const float TOP_PADDING = 25;
|
||||
public const float Y_PADDING = 25;
|
||||
public const float RIGHT_WIDTH = 275;
|
||||
protected readonly Header Header;
|
||||
|
||||
private RulesetStore rulesets;
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
private readonly Bindable<BeatmapSetInfo> beatmapSet = new Bindable<BeatmapSetInfo>();
|
||||
|
||||
// receive input outside our bounds so we can trigger a close event on ourselves.
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
||||
|
||||
private readonly Box background;
|
||||
|
||||
public BeatmapSetOverlay()
|
||||
: base(OverlayColourScheme.Blue)
|
||||
{
|
||||
OsuScrollContainer scroll;
|
||||
Info info;
|
||||
CommentsSection comments;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.Gray(0.2f)
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
scroll = new OsuScrollContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
ScrollbarVisible = false,
|
||||
Child = new ReverseChildIDFillFlowContainer<Drawable>
|
||||
Child = new ReverseChildIDFillFlowContainer<BeatmapSetLayoutSection>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
Spacing = new Vector2(0, 20),
|
||||
Children = new[]
|
||||
{
|
||||
Header = new Header(),
|
||||
info = new Info(),
|
||||
new BeatmapSetLayoutSection
|
||||
{
|
||||
Child = new ReverseChildIDFillFlowContainer<Drawable>
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Header = new Header(),
|
||||
info = new Info()
|
||||
}
|
||||
},
|
||||
},
|
||||
new ScoresContainer
|
||||
{
|
||||
Beatmap = { BindTarget = Header.Picker.Beatmap }
|
||||
}
|
||||
},
|
||||
comments = new CommentsSection()
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -70,6 +87,7 @@ namespace osu.Game.Overlays
|
||||
|
||||
Header.BeatmapSet.BindTo(beatmapSet);
|
||||
info.BeatmapSet.BindTo(beatmapSet);
|
||||
comments.BeatmapSet.BindTo(beatmapSet);
|
||||
|
||||
Header.Picker.Beatmap.ValueChanged += b =>
|
||||
{
|
||||
@ -80,9 +98,9 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetStore rulesets)
|
||||
private void load()
|
||||
{
|
||||
this.rulesets = rulesets;
|
||||
background.Colour = ColourProvider.Background6;
|
||||
}
|
||||
|
||||
protected override void PopOutComplete()
|
||||
@ -132,5 +150,30 @@ namespace osu.Game.Overlays
|
||||
beatmapSet.Value = set;
|
||||
Show();
|
||||
}
|
||||
|
||||
private class CommentsSection : BeatmapSetLayoutSection
|
||||
{
|
||||
public readonly Bindable<BeatmapSetInfo> BeatmapSet = new Bindable<BeatmapSetInfo>();
|
||||
|
||||
public CommentsSection()
|
||||
{
|
||||
CommentsContainer comments;
|
||||
|
||||
Add(comments = new CommentsContainer());
|
||||
|
||||
BeatmapSet.BindValueChanged(beatmapSet =>
|
||||
{
|
||||
if (beatmapSet.NewValue?.OnlineBeatmapSetID is int onlineBeatmapSetID)
|
||||
{
|
||||
Show();
|
||||
comments.ShowComments(CommentableType.Beatmapset, onlineBeatmapSetID);
|
||||
}
|
||||
else
|
||||
{
|
||||
Hide();
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ using osuTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using System.Net;
|
||||
using osuTK;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
|
||||
namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
@ -51,28 +52,27 @@ namespace osu.Game.Overlays.Changelog
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OsuColour colours, OverlayColourProvider colourProvider)
|
||||
{
|
||||
foreach (var categoryEntries in Build.ChangelogEntries.GroupBy(b => b.Category).OrderBy(c => c.Key))
|
||||
{
|
||||
ChangelogEntries.Add(new OsuSpriteText
|
||||
{
|
||||
Text = categoryEntries.Key,
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 24),
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 18),
|
||||
Margin = new MarginPadding { Top = 35, Bottom = 15 },
|
||||
});
|
||||
|
||||
var fontLarge = OsuFont.GetFont(size: 18);
|
||||
var fontMedium = OsuFont.GetFont(size: 14);
|
||||
var fontSmall = OsuFont.GetFont(size: 12);
|
||||
var fontLarge = OsuFont.GetFont(size: 16);
|
||||
var fontMedium = OsuFont.GetFont(size: 12);
|
||||
|
||||
foreach (APIChangelogEntry entry in categoryEntries)
|
||||
foreach (var entry in categoryEntries)
|
||||
{
|
||||
var entryColour = entry.Major ? colours.YellowLight : Color4.White;
|
||||
|
||||
LinkFlowContainer title;
|
||||
|
||||
Container titleContainer = new Container
|
||||
var titleContainer = new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
@ -83,9 +83,9 @@ namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreRight,
|
||||
Size = new Vector2(fontSmall.Size),
|
||||
Size = new Vector2(10),
|
||||
Icon = entry.Type == ChangelogEntryType.Fix ? FontAwesome.Solid.Check : FontAwesome.Solid.Plus,
|
||||
Colour = entryColour,
|
||||
Colour = entryColour.Opacity(0.5f),
|
||||
Margin = new MarginPadding { Right = 5 },
|
||||
},
|
||||
title = new LinkFlowContainer
|
||||
@ -93,6 +93,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
Direction = FillDirection.Full,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
TextAnchor = Anchor.BottomLeft,
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -123,10 +124,11 @@ namespace osu.Game.Overlays.Changelog
|
||||
});
|
||||
}
|
||||
|
||||
title.AddText(" by ", t =>
|
||||
title.AddText("by ", t =>
|
||||
{
|
||||
t.Font = fontMedium;
|
||||
t.Colour = entryColour;
|
||||
t.Padding = new MarginPadding { Left = 10 };
|
||||
});
|
||||
|
||||
if (entry.GithubUser.UserId != null)
|
||||
@ -153,7 +155,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
title.AddText(entry.GithubUser.DisplayName, t =>
|
||||
{
|
||||
t.Font = fontSmall;
|
||||
t.Font = fontMedium;
|
||||
t.Colour = entryColour;
|
||||
});
|
||||
}
|
||||
@ -162,7 +164,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
|
||||
if (!string.IsNullOrEmpty(entry.MessageHtml))
|
||||
{
|
||||
TextFlowContainer message = new TextFlowContainer
|
||||
var message = new TextFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
@ -171,8 +173,8 @@ namespace osu.Game.Overlays.Changelog
|
||||
// todo: use markdown parsing once API returns markdown
|
||||
message.AddText(WebUtility.HtmlDecode(Regex.Replace(entry.MessageHtml, @"<(.|\n)*?>", string.Empty)), t =>
|
||||
{
|
||||
t.Font = fontSmall;
|
||||
t.Colour = new Color4(235, 184, 254, 255);
|
||||
t.Font = fontMedium;
|
||||
t.Colour = colourProvider.Foreground1;
|
||||
});
|
||||
|
||||
ChangelogEntries.Add(message);
|
||||
|
@ -19,7 +19,6 @@ namespace osu.Game.Overlays.Changelog
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Direction = FillDirection.Vertical;
|
||||
Padding = new MarginPadding { Bottom = 100 };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
@ -14,32 +16,40 @@ namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
public class ChangelogHeader : BreadcrumbControlOverlayHeader
|
||||
{
|
||||
public readonly Bindable<APIChangelogBuild> Current = new Bindable<APIChangelogBuild>();
|
||||
public readonly Bindable<APIChangelogBuild> Build = new Bindable<APIChangelogBuild>();
|
||||
|
||||
public Action ListingSelected;
|
||||
|
||||
public UpdateStreamBadgeArea Streams;
|
||||
public ChangelogUpdateStreamControl Streams;
|
||||
|
||||
private const string listing_string = "listing";
|
||||
|
||||
private Box streamsBackground;
|
||||
|
||||
public ChangelogHeader()
|
||||
{
|
||||
TabControl.AddItem(listing_string);
|
||||
TabControl.Current.ValueChanged += e =>
|
||||
Current.ValueChanged += e =>
|
||||
{
|
||||
if (e.NewValue == listing_string)
|
||||
ListingSelected?.Invoke();
|
||||
};
|
||||
|
||||
Current.ValueChanged += showBuild;
|
||||
Build.ValueChanged += showBuild;
|
||||
|
||||
Streams.Current.ValueChanged += e =>
|
||||
{
|
||||
if (e.NewValue?.LatestBuild != null && !e.NewValue.Equals(Current.Value?.UpdateStream))
|
||||
Current.Value = e.NewValue.LatestBuild;
|
||||
if (e.NewValue?.LatestBuild != null && !e.NewValue.Equals(Build.Value?.UpdateStream))
|
||||
Build.Value = e.NewValue.LatestBuild;
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
streamsBackground.Colour = colourProvider.Background5;
|
||||
}
|
||||
|
||||
private ChangelogHeaderTitle title;
|
||||
|
||||
private void showBuild(ValueChangedEvent<APIChangelogBuild> e)
|
||||
@ -50,7 +60,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
if (e.NewValue != null)
|
||||
{
|
||||
TabControl.AddItem(e.NewValue.ToString());
|
||||
TabControl.Current.Value = e.NewValue.ToString();
|
||||
Current.Value = e.NewValue.ToString();
|
||||
|
||||
updateCurrentStream();
|
||||
|
||||
@ -58,7 +68,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
}
|
||||
else
|
||||
{
|
||||
TabControl.Current.Value = listing_string;
|
||||
Current.Value = listing_string;
|
||||
Streams.Current.Value = null;
|
||||
title.Version = null;
|
||||
}
|
||||
@ -72,7 +82,21 @@ namespace osu.Game.Overlays.Changelog
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Streams = new UpdateStreamBadgeArea(),
|
||||
streamsBackground = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Horizontal = 65,
|
||||
Vertical = 20
|
||||
},
|
||||
Child = Streams = new ChangelogUpdateStreamControl()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -86,10 +110,10 @@ namespace osu.Game.Overlays.Changelog
|
||||
|
||||
private void updateCurrentStream()
|
||||
{
|
||||
if (Current.Value == null)
|
||||
if (Build.Value == null)
|
||||
return;
|
||||
|
||||
Streams.Current.Value = Streams.Items.FirstOrDefault(s => s.Name == Current.Value.UpdateStream.Name);
|
||||
Streams.Current.Value = Streams.Items.FirstOrDefault(s => s.Name == Build.Value.UpdateStream.Name);
|
||||
}
|
||||
|
||||
private class ChangelogHeaderTitle : ScreenTitle
|
||||
|
@ -10,7 +10,6 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
@ -24,13 +23,13 @@ namespace osu.Game.Overlays.Changelog
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
DateTime currentDate = DateTime.MinValue;
|
||||
var currentDate = DateTime.MinValue;
|
||||
|
||||
if (entries == null) return;
|
||||
|
||||
foreach (APIChangelogBuild build in entries)
|
||||
foreach (var build in entries)
|
||||
{
|
||||
if (build.CreatedAt.Date != currentDate)
|
||||
{
|
||||
@ -40,7 +39,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 2,
|
||||
Colour = new Color4(17, 17, 17, 255),
|
||||
Colour = colourProvider.Background6,
|
||||
Margin = new MarginPadding { Top = 30 },
|
||||
});
|
||||
}
|
||||
@ -49,10 +48,9 @@ namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Margin = new MarginPadding { Top = 15 },
|
||||
Text = build.CreatedAt.Date.ToString("dd MMM yyyy"),
|
||||
Margin = new MarginPadding { Top = 20 },
|
||||
Text = build.CreatedAt.Date.ToString("dd MMMM yyyy"),
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 24),
|
||||
Colour = OsuColour.FromHex(@"FD5"),
|
||||
});
|
||||
|
||||
currentDate = build.CreatedAt.Date;
|
||||
@ -68,7 +66,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
Child = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = new Color4(32, 24, 35, 255),
|
||||
Colour = colourProvider.Background6,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
@ -16,6 +17,7 @@ using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays.Comments;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.Changelog
|
||||
@ -30,7 +32,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(CancellationToken? cancellation, IAPIProvider api)
|
||||
private void load(CancellationToken? cancellation, IAPIProvider api, OverlayColourProvider colourProvider)
|
||||
{
|
||||
bool complete = false;
|
||||
|
||||
@ -57,11 +59,22 @@ namespace osu.Game.Overlays.Changelog
|
||||
|
||||
if (build != null)
|
||||
{
|
||||
CommentsContainer comments;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new ChangelogBuildWithNavigation(build) { SelectBuild = SelectBuild },
|
||||
new Comments(build)
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 2,
|
||||
Colour = colourProvider.Background6,
|
||||
Margin = new MarginPadding { Top = 30 },
|
||||
},
|
||||
comments = new CommentsContainer()
|
||||
};
|
||||
|
||||
comments.ShowComments(CommentableType.Build, build.Id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,6 +85,8 @@ namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
}
|
||||
|
||||
private OsuSpriteText date;
|
||||
|
||||
protected override FillFlowContainer CreateHeader()
|
||||
{
|
||||
var fill = base.CreateHeader();
|
||||
@ -81,11 +96,10 @@ namespace osu.Game.Overlays.Changelog
|
||||
existing.Scale = new Vector2(1.25f);
|
||||
existing.Action = null;
|
||||
|
||||
existing.Add(new OsuSpriteText
|
||||
existing.Add(date = new OsuSpriteText
|
||||
{
|
||||
Text = Build.CreatedAt.Date.ToString("dd MMM yyyy"),
|
||||
Text = Build.CreatedAt.Date.ToString("dd MMMM yyyy"),
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 14),
|
||||
Colour = OsuColour.FromHex(@"FD5"),
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Margin = new MarginPadding { Top = 5 },
|
||||
@ -105,6 +119,12 @@ namespace osu.Game.Overlays.Changelog
|
||||
|
||||
return fill;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
date.Colour = colourProvider.Light1;
|
||||
}
|
||||
}
|
||||
|
||||
private class NavigationIconButton : IconButton
|
||||
|
12
osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs
Normal file
12
osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs
Normal file
@ -0,0 +1,12 @@
|
||||
// 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.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
public class ChangelogUpdateStreamControl : OverlayStreamControl<APIUpdateStream>
|
||||
{
|
||||
protected override OverlayStreamItem<APIUpdateStream> CreateStreamItem(APIUpdateStream value) => new ChangelogUpdateStreamItem(value);
|
||||
}
|
||||
}
|
28
osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs
Normal file
28
osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs
Normal file
@ -0,0 +1,28 @@
|
||||
// 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 Humanizer;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
public class ChangelogUpdateStreamItem : OverlayStreamItem<APIUpdateStream>
|
||||
{
|
||||
public ChangelogUpdateStreamItem(APIUpdateStream stream)
|
||||
: base(stream)
|
||||
{
|
||||
if (stream.IsFeatured)
|
||||
Width *= 2;
|
||||
}
|
||||
|
||||
protected override string MainText => Value.DisplayName;
|
||||
|
||||
protected override string AdditionalText => Value.LatestBuild.DisplayVersion;
|
||||
|
||||
protected override string InfoText => Value.LatestBuild.Users > 0 ? $"{"user".ToQuantity(Value.LatestBuild.Users, "N0")} online" : null;
|
||||
|
||||
protected override Color4 GetBarColour(OsuColour colours) => Value.Colour;
|
||||
}
|
||||
}
|
@ -1,157 +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 Humanizer;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
public class UpdateStreamBadge : TabItem<APIUpdateStream>
|
||||
{
|
||||
private const float badge_height = 66.5f;
|
||||
private const float badge_width = 100;
|
||||
private const float transition_duration = 100;
|
||||
|
||||
private readonly ExpandingBar expandingBar;
|
||||
private SampleChannel sampleClick;
|
||||
private SampleChannel sampleHover;
|
||||
|
||||
private readonly FillFlowContainer<SpriteText> text;
|
||||
|
||||
public readonly Bindable<APIUpdateStream> SelectedTab = new Bindable<APIUpdateStream>();
|
||||
|
||||
private readonly Container fadeContainer;
|
||||
|
||||
public UpdateStreamBadge(APIUpdateStream stream)
|
||||
: base(stream)
|
||||
{
|
||||
Size = new Vector2(stream.IsFeatured ? badge_width * 2 : badge_width, badge_height);
|
||||
Padding = new MarginPadding(5);
|
||||
|
||||
Child = fadeContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
text = new FillFlowContainer<SpriteText>
|
||||
{
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = stream.DisplayName,
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 12),
|
||||
Margin = new MarginPadding { Top = 6 },
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = stream.LatestBuild.DisplayVersion,
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Light, size: 16),
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = stream.LatestBuild.Users > 0 ? $"{stream.LatestBuild.Users:N0} {"user".Pluralize(stream.LatestBuild.Users == 1)} online" : null,
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 10),
|
||||
Colour = new Color4(203, 164, 218, 255),
|
||||
},
|
||||
}
|
||||
},
|
||||
expandingBar = new ExpandingBar
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Colour = stream.Colour,
|
||||
ExpandedSize = 4,
|
||||
CollapsedSize = 2,
|
||||
IsCollapsed = true
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
SelectedTab.BindValueChanged(_ => updateState(), true);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
sampleClick = audio.Samples.Get(@"UI/generic-select-soft");
|
||||
sampleHover = audio.Samples.Get(@"UI/generic-hover-soft");
|
||||
}
|
||||
|
||||
protected override void OnActivated() => updateState();
|
||||
|
||||
protected override void OnDeactivated() => updateState();
|
||||
|
||||
protected override bool OnClick(ClickEvent e)
|
||||
{
|
||||
sampleClick?.Play();
|
||||
return base.OnClick(e);
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
sampleHover?.Play();
|
||||
updateState();
|
||||
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
updateState();
|
||||
base.OnHoverLost(e);
|
||||
}
|
||||
|
||||
private void updateState()
|
||||
{
|
||||
// Expand based on the local state
|
||||
bool shouldExpand = Active.Value || IsHovered;
|
||||
|
||||
// Expand based on whether no build is selected and the badge area is hovered
|
||||
shouldExpand |= SelectedTab.Value == null && !externalDimRequested;
|
||||
|
||||
if (shouldExpand)
|
||||
{
|
||||
expandingBar.Expand();
|
||||
fadeContainer.FadeTo(1, transition_duration);
|
||||
}
|
||||
else
|
||||
{
|
||||
expandingBar.Collapse();
|
||||
fadeContainer.FadeTo(0.5f, transition_duration);
|
||||
}
|
||||
|
||||
text.FadeTo(externalDimRequested && !IsHovered ? 0.5f : 1, transition_duration);
|
||||
}
|
||||
|
||||
private bool externalDimRequested;
|
||||
|
||||
public void EnableDim()
|
||||
{
|
||||
externalDimRequested = true;
|
||||
updateState();
|
||||
}
|
||||
|
||||
public void DisableDim()
|
||||
{
|
||||
externalDimRequested = false;
|
||||
updateState();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,73 +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 osu.Framework.Graphics;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
public class UpdateStreamBadgeArea : TabControl<APIUpdateStream>
|
||||
{
|
||||
public UpdateStreamBadgeArea()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
AddInternal(new Box
|
||||
{
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.12f,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
});
|
||||
}
|
||||
|
||||
public void Populate(List<APIUpdateStream> streams)
|
||||
{
|
||||
foreach (APIUpdateStream updateStream in streams)
|
||||
AddItem(updateStream);
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
foreach (UpdateStreamBadge streamBadge in TabContainer.Children.OfType<UpdateStreamBadge>())
|
||||
streamBadge.EnableDim();
|
||||
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
foreach (UpdateStreamBadge streamBadge in TabContainer.Children.OfType<UpdateStreamBadge>())
|
||||
streamBadge.DisableDim();
|
||||
|
||||
base.OnHoverLost(e);
|
||||
}
|
||||
|
||||
protected override TabFillFlowContainer CreateTabFlow()
|
||||
{
|
||||
var flow = base.CreateTabFlow();
|
||||
|
||||
flow.RelativeSizeAxes = Axes.X;
|
||||
flow.AutoSizeAxes = Axes.Y;
|
||||
flow.AllowMultiline = true;
|
||||
flow.Padding = new MarginPadding
|
||||
{
|
||||
Vertical = 20,
|
||||
Horizontal = 85,
|
||||
};
|
||||
|
||||
return flow;
|
||||
}
|
||||
|
||||
protected override Dropdown<APIUpdateStream> CreateDropdown() => null;
|
||||
|
||||
protected override TabItem<APIUpdateStream> CreateTabItem(APIUpdateStream value) =>
|
||||
new UpdateStreamBadge(value) { SelectedTab = { BindTarget = Current } };
|
||||
}
|
||||
}
|
@ -13,7 +13,6 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Online.API.Requests;
|
||||
@ -42,14 +41,14 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio, OsuColour colour)
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colour.PurpleDarkAlternative,
|
||||
Colour = ColourProvider.Background4,
|
||||
},
|
||||
new OsuScrollContainer
|
||||
{
|
||||
@ -78,7 +77,7 @@ namespace osu.Game.Overlays
|
||||
|
||||
sampleBack = audio.Samples.Get(@"UI/generic-select-soft");
|
||||
|
||||
Header.Current.BindTo(Current);
|
||||
Header.Build.BindTo(Current);
|
||||
|
||||
Current.BindValueChanged(e =>
|
||||
{
|
||||
|
@ -123,7 +123,7 @@ namespace osu.Game.Overlays.Chat
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Radius = 1,
|
||||
Colour = OsuColour.FromHex(message.Sender.Colour),
|
||||
Colour = Color4Extensions.FromHex(message.Sender.Colour),
|
||||
Type = EdgeEffectType.Shadow,
|
||||
},
|
||||
Padding = new MarginPadding { Left = 3, Right = 3, Bottom = 1, Top = -3 },
|
||||
@ -172,7 +172,7 @@ namespace osu.Game.Overlays.Chat
|
||||
t.Font = OsuFont.GetFont(italics: true);
|
||||
|
||||
if (senderHasBackground)
|
||||
t.Colour = OsuColour.FromHex(message.Sender.Colour);
|
||||
t.Colour = Color4Extensions.FromHex(message.Sender.Colour);
|
||||
}
|
||||
|
||||
t.Font = t.Font.With(size: TextSize);
|
||||
@ -249,41 +249,41 @@ namespace osu.Game.Overlays.Chat
|
||||
|
||||
private static readonly Color4[] username_colours =
|
||||
{
|
||||
OsuColour.FromHex("588c7e"),
|
||||
OsuColour.FromHex("b2a367"),
|
||||
OsuColour.FromHex("c98f65"),
|
||||
OsuColour.FromHex("bc5151"),
|
||||
OsuColour.FromHex("5c8bd6"),
|
||||
OsuColour.FromHex("7f6ab7"),
|
||||
OsuColour.FromHex("a368ad"),
|
||||
OsuColour.FromHex("aa6880"),
|
||||
Color4Extensions.FromHex("588c7e"),
|
||||
Color4Extensions.FromHex("b2a367"),
|
||||
Color4Extensions.FromHex("c98f65"),
|
||||
Color4Extensions.FromHex("bc5151"),
|
||||
Color4Extensions.FromHex("5c8bd6"),
|
||||
Color4Extensions.FromHex("7f6ab7"),
|
||||
Color4Extensions.FromHex("a368ad"),
|
||||
Color4Extensions.FromHex("aa6880"),
|
||||
|
||||
OsuColour.FromHex("6fad9b"),
|
||||
OsuColour.FromHex("f2e394"),
|
||||
OsuColour.FromHex("f2ae72"),
|
||||
OsuColour.FromHex("f98f8a"),
|
||||
OsuColour.FromHex("7daef4"),
|
||||
OsuColour.FromHex("a691f2"),
|
||||
OsuColour.FromHex("c894d3"),
|
||||
OsuColour.FromHex("d895b0"),
|
||||
Color4Extensions.FromHex("6fad9b"),
|
||||
Color4Extensions.FromHex("f2e394"),
|
||||
Color4Extensions.FromHex("f2ae72"),
|
||||
Color4Extensions.FromHex("f98f8a"),
|
||||
Color4Extensions.FromHex("7daef4"),
|
||||
Color4Extensions.FromHex("a691f2"),
|
||||
Color4Extensions.FromHex("c894d3"),
|
||||
Color4Extensions.FromHex("d895b0"),
|
||||
|
||||
OsuColour.FromHex("53c4a1"),
|
||||
OsuColour.FromHex("eace5c"),
|
||||
OsuColour.FromHex("ea8c47"),
|
||||
OsuColour.FromHex("fc4f4f"),
|
||||
OsuColour.FromHex("3d94ea"),
|
||||
OsuColour.FromHex("7760ea"),
|
||||
OsuColour.FromHex("af52c6"),
|
||||
OsuColour.FromHex("e25696"),
|
||||
Color4Extensions.FromHex("53c4a1"),
|
||||
Color4Extensions.FromHex("eace5c"),
|
||||
Color4Extensions.FromHex("ea8c47"),
|
||||
Color4Extensions.FromHex("fc4f4f"),
|
||||
Color4Extensions.FromHex("3d94ea"),
|
||||
Color4Extensions.FromHex("7760ea"),
|
||||
Color4Extensions.FromHex("af52c6"),
|
||||
Color4Extensions.FromHex("e25696"),
|
||||
|
||||
OsuColour.FromHex("677c66"),
|
||||
OsuColour.FromHex("9b8732"),
|
||||
OsuColour.FromHex("8c5129"),
|
||||
OsuColour.FromHex("8c3030"),
|
||||
OsuColour.FromHex("1f5d91"),
|
||||
OsuColour.FromHex("4335a5"),
|
||||
OsuColour.FromHex("812a96"),
|
||||
OsuColour.FromHex("992861"),
|
||||
Color4Extensions.FromHex("677c66"),
|
||||
Color4Extensions.FromHex("9b8732"),
|
||||
Color4Extensions.FromHex("8c5129"),
|
||||
Color4Extensions.FromHex("8c3030"),
|
||||
Color4Extensions.FromHex("1f5d91"),
|
||||
Color4Extensions.FromHex("4335a5"),
|
||||
Color4Extensions.FromHex("812a96"),
|
||||
Color4Extensions.FromHex("992861"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Chat.Selection
|
||||
private const float text_size = 15;
|
||||
private const float transition_duration = 100;
|
||||
|
||||
private readonly Channel channel;
|
||||
public readonly Channel Channel;
|
||||
|
||||
private readonly Bindable<bool> joinedBind = new Bindable<bool>();
|
||||
private readonly OsuSpriteText name;
|
||||
@ -36,7 +36,7 @@ namespace osu.Game.Overlays.Chat.Selection
|
||||
private Color4 topicColour;
|
||||
private Color4 hoverColour;
|
||||
|
||||
public IEnumerable<string> FilterTerms => new[] { channel.Name, channel.Topic };
|
||||
public IEnumerable<string> FilterTerms => new[] { Channel.Name, Channel.Topic ?? string.Empty };
|
||||
|
||||
public bool MatchingFilter
|
||||
{
|
||||
@ -50,7 +50,7 @@ namespace osu.Game.Overlays.Chat.Selection
|
||||
|
||||
public ChannelListItem(Channel channel)
|
||||
{
|
||||
this.channel = channel;
|
||||
Channel = channel;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
@ -148,7 +148,7 @@ namespace osu.Game.Overlays.Chat.Selection
|
||||
hoverColour = colours.Yellow;
|
||||
|
||||
joinedBind.ValueChanged += joined => updateColour(joined.NewValue);
|
||||
joinedBind.BindTo(channel.Joined);
|
||||
joinedBind.BindTo(Channel.Joined);
|
||||
|
||||
joinedBind.TriggerChange();
|
||||
FinishTransforms(true);
|
||||
@ -156,7 +156,7 @@ namespace osu.Game.Overlays.Chat.Selection
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
if (!channel.Joined.Value)
|
||||
if (!Channel.Joined.Value)
|
||||
name.FadeColour(hoverColour, 50, Easing.OutQuint);
|
||||
|
||||
return base.OnHover(e);
|
||||
@ -164,7 +164,7 @@ namespace osu.Game.Overlays.Chat.Selection
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
if (!channel.Joined.Value)
|
||||
if (!Channel.Joined.Value)
|
||||
name.FadeColour(Color4.White, transition_duration);
|
||||
}
|
||||
|
||||
|
@ -41,10 +41,10 @@ namespace osu.Game.Overlays.Chat.Selection
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
Waves.FirstWaveColour = OsuColour.FromHex("353535");
|
||||
Waves.SecondWaveColour = OsuColour.FromHex("434343");
|
||||
Waves.ThirdWaveColour = OsuColour.FromHex("515151");
|
||||
Waves.FourthWaveColour = OsuColour.FromHex("595959");
|
||||
Waves.FirstWaveColour = Color4Extensions.FromHex("353535");
|
||||
Waves.SecondWaveColour = Color4Extensions.FromHex("434343");
|
||||
Waves.ThirdWaveColour = Color4Extensions.FromHex("515151");
|
||||
Waves.FourthWaveColour = Color4Extensions.FromHex("595959");
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@ -154,7 +154,7 @@ namespace osu.Game.Overlays.Chat.Selection
|
||||
{
|
||||
bg.Colour = colours.Gray3;
|
||||
triangles.ColourDark = colours.Gray3;
|
||||
triangles.ColourLight = OsuColour.FromHex(@"353535");
|
||||
triangles.ColourLight = Color4Extensions.FromHex(@"353535");
|
||||
|
||||
headerBg.Colour = colours.Gray2.Opacity(0.75f);
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ namespace osu.Game.Overlays.Chat.Tabs
|
||||
public ChannelSelectorTabChannel()
|
||||
{
|
||||
Name = "+";
|
||||
Type = ChannelType.System;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Chat.Tabs
|
||||
// performTabSort might've made selectorTab's position wonky, fix it
|
||||
TabContainer.SetLayoutPosition(selectorTab, float.MaxValue);
|
||||
|
||||
((ChannelTabItem)item).OnRequestClose += tabCloseRequested;
|
||||
((ChannelTabItem)item).OnRequestClose += channelItem => OnRequestLeave?.Invoke(channelItem.Value);
|
||||
|
||||
base.AddTabItem(item, addToDropdown);
|
||||
}
|
||||
@ -74,18 +74,24 @@ namespace osu.Game.Overlays.Chat.Tabs
|
||||
|
||||
/// <summary>
|
||||
/// Removes a channel from the ChannelTabControl.
|
||||
/// If the selected channel is the one that is beeing removed, the next available channel will be selected.
|
||||
/// If the selected channel is the one that is being removed, the next available channel will be selected.
|
||||
/// </summary>
|
||||
/// <param name="channel">The channel that is going to be removed.</param>
|
||||
public void RemoveChannel(Channel channel)
|
||||
{
|
||||
RemoveItem(channel);
|
||||
|
||||
if (Current.Value == channel)
|
||||
{
|
||||
// Prefer non-selector channels first
|
||||
Current.Value = Items.FirstOrDefault(c => !(c is ChannelSelectorTabItem.ChannelSelectorTabChannel)) ?? Items.FirstOrDefault();
|
||||
var allChannels = TabContainer.AllTabItems.Select(tab => tab.Value).ToList();
|
||||
var isNextTabSelector = allChannels[allChannels.IndexOf(channel) + 1] == selectorTab.Value;
|
||||
|
||||
// selectorTab is not switchable, so we have to explicitly select it if it's the only tab left
|
||||
if (isNextTabSelector && allChannels.Count == 2)
|
||||
SelectTab(selectorTab);
|
||||
else
|
||||
SwitchTab(isNextTabSelector ? -1 : 1);
|
||||
}
|
||||
|
||||
RemoveItem(channel);
|
||||
}
|
||||
|
||||
protected override void SelectTab(TabItem<Channel> tab)
|
||||
@ -100,21 +106,6 @@ namespace osu.Game.Overlays.Chat.Tabs
|
||||
selectorTab.Active.Value = false;
|
||||
}
|
||||
|
||||
private void tabCloseRequested(TabItem<Channel> tab)
|
||||
{
|
||||
int totalTabs = TabContainer.Count - 1; // account for selectorTab
|
||||
int currentIndex = Math.Clamp(TabContainer.IndexOf(tab), 1, totalTabs);
|
||||
|
||||
if (tab == SelectedTab && totalTabs > 1)
|
||||
// Select the tab after tab-to-be-removed's index, or the tab before if current == last
|
||||
SelectTab(TabContainer[currentIndex == totalTabs ? currentIndex - 1 : currentIndex + 1]);
|
||||
else if (totalTabs == 1 && !selectorTab.Active.Value)
|
||||
// Open channel selection overlay if all channel tabs will be closed after removing this tab
|
||||
SelectTab(selectorTab);
|
||||
|
||||
OnRequestLeave?.Invoke(tab.Value);
|
||||
}
|
||||
|
||||
protected override TabFillFlowContainer CreateTabFlow() => new ChannelTabFillFlowContainer
|
||||
{
|
||||
Direction = FillDirection.Full,
|
||||
|
@ -89,7 +89,7 @@ namespace osu.Game.Overlays.Chat.Tabs
|
||||
{
|
||||
var user = Value.Users.First();
|
||||
|
||||
BackgroundActive = user.Colour != null ? OsuColour.FromHex(user.Colour) : colours.BlueDark;
|
||||
BackgroundActive = user.Colour != null ? Color4Extensions.FromHex(user.Colour) : colours.BlueDark;
|
||||
BackgroundInactive = BackgroundActive.Darken(0.5f);
|
||||
}
|
||||
}
|
||||
|
@ -30,13 +30,14 @@ namespace osu.Game.Overlays
|
||||
private const float textbox_height = 60;
|
||||
private const float channel_selection_min_height = 0.3f;
|
||||
|
||||
private ChannelManager channelManager;
|
||||
[Resolved]
|
||||
private ChannelManager channelManager { get; set; }
|
||||
|
||||
private Container<DrawableChannel> currentChannelContainer;
|
||||
|
||||
private readonly List<DrawableChannel> loadedChannels = new List<DrawableChannel>();
|
||||
|
||||
private LoadingAnimation loading;
|
||||
private LoadingSpinner loading;
|
||||
|
||||
private FocusedTextBox textbox;
|
||||
|
||||
@ -72,7 +73,7 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config, OsuColour colours, ChannelManager channelManager)
|
||||
private void load(OsuConfigManager config, OsuColour colours)
|
||||
{
|
||||
const float padding = 5;
|
||||
|
||||
@ -145,7 +146,7 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
}
|
||||
},
|
||||
loading = new LoadingAnimation(),
|
||||
loading = new LoadingSpinner(),
|
||||
}
|
||||
},
|
||||
tabsArea = new TabsArea
|
||||
@ -209,8 +210,6 @@ namespace osu.Game.Overlays
|
||||
|
||||
chatBackground.Colour = colours.ChatBlue;
|
||||
|
||||
this.channelManager = channelManager;
|
||||
|
||||
loading.Show();
|
||||
|
||||
// This is a relatively expensive (and blocking) operation.
|
||||
@ -321,8 +320,10 @@ namespace osu.Game.Overlays
|
||||
|
||||
private void selectTab(int index)
|
||||
{
|
||||
var channel = ChannelTabControl.Items.Skip(index).FirstOrDefault();
|
||||
if (channel != null && !(channel is ChannelSelectorTabItem.ChannelSelectorTabChannel))
|
||||
var channel = ChannelTabControl.Items
|
||||
.Where(tab => !(tab is ChannelSelectorTabItem.ChannelSelectorTabChannel))
|
||||
.ElementAtOrDefault(index);
|
||||
if (channel != null)
|
||||
ChannelTabControl.Current.Value = channel;
|
||||
}
|
||||
|
||||
|
71
osu.Game/Overlays/Comments/CancellableCommentEditor.cs
Normal file
71
osu.Game/Overlays/Comments/CancellableCommentEditor.cs
Normal file
@ -0,0 +1,71 @@
|
||||
// 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.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
public abstract class CancellableCommentEditor : CommentEditor
|
||||
{
|
||||
public Action OnCancel;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
ButtonsContainer.Add(new CancelButton
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Action = () => OnCancel?.Invoke()
|
||||
});
|
||||
}
|
||||
|
||||
private class CancelButton : OsuHoverContainer
|
||||
{
|
||||
protected override IEnumerable<Drawable> EffectTargets => new[] { background };
|
||||
|
||||
private readonly Box background;
|
||||
|
||||
public CancelButton()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Child = new CircularContainer
|
||||
{
|
||||
Masking = true,
|
||||
Height = 25,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
|
||||
Margin = new MarginPadding { Horizontal = 20 },
|
||||
Text = @"Cancel"
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
IdleColour = colourProvider.Light4;
|
||||
HoverColour = colourProvider.Light3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
245
osu.Game/Overlays/Comments/CommentEditor.cs
Normal file
245
osu.Game/Overlays/Comments/CommentEditor.cs
Normal file
@ -0,0 +1,245 @@
|
||||
// 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.Containers;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osuTK.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using osuTK;
|
||||
using osu.Framework.Bindables;
|
||||
|
||||
namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
public abstract class CommentEditor : CompositeDrawable
|
||||
{
|
||||
private const int side_padding = 8;
|
||||
|
||||
public Action<string> OnCommit;
|
||||
|
||||
public bool IsLoading
|
||||
{
|
||||
get => commitButton.IsLoading;
|
||||
set => commitButton.IsLoading = value;
|
||||
}
|
||||
|
||||
protected abstract string FooterText { get; }
|
||||
|
||||
protected abstract string CommitButtonText { get; }
|
||||
|
||||
protected abstract string TextBoxPlaceholder { get; }
|
||||
|
||||
protected FillFlowContainer ButtonsContainer { get; private set; }
|
||||
|
||||
protected readonly Bindable<string> Current = new Bindable<string>();
|
||||
|
||||
private CommitButton commitButton;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
EditorTextBox textBox;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Masking = true;
|
||||
CornerRadius = 6;
|
||||
BorderThickness = 3;
|
||||
BorderColour = colourProvider.Background3;
|
||||
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colourProvider.Background3
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
textBox = new EditorTextBox
|
||||
{
|
||||
Height = 40,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
PlaceholderText = TextBoxPlaceholder,
|
||||
Current = Current
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Name = "Footer",
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 35,
|
||||
Padding = new MarginPadding { Horizontal = side_padding },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold),
|
||||
Text = FooterText
|
||||
},
|
||||
ButtonsContainer = new FillFlowContainer
|
||||
{
|
||||
Name = "Buttons",
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(5, 0),
|
||||
Child = commitButton = new CommitButton(CommitButtonText)
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Action = () =>
|
||||
{
|
||||
OnCommit?.Invoke(Current.Value);
|
||||
Current.Value = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
textBox.OnCommit += (u, v) =>
|
||||
{
|
||||
if (commitButton.IsBlocked.Value)
|
||||
return;
|
||||
|
||||
commitButton.Click();
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
Current.BindValueChanged(text => commitButton.IsBlocked.Value = string.IsNullOrEmpty(text.NewValue), true);
|
||||
}
|
||||
|
||||
private class EditorTextBox : BasicTextBox
|
||||
{
|
||||
protected override float LeftRightPadding => side_padding;
|
||||
|
||||
protected override Color4 SelectionColour => Color4.Gray;
|
||||
|
||||
private OsuSpriteText placeholder;
|
||||
|
||||
public EditorTextBox()
|
||||
{
|
||||
Masking = false;
|
||||
TextContainer.Height = 0.4f;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
BackgroundUnfocused = BackgroundFocused = colourProvider.Background5;
|
||||
placeholder.Colour = colourProvider.Background3;
|
||||
BackgroundCommit = colourProvider.Background3;
|
||||
}
|
||||
|
||||
protected override SpriteText CreatePlaceholder() => placeholder = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Regular),
|
||||
};
|
||||
|
||||
protected override Drawable GetDrawableCharacter(char c) => new FallingDownContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Child = new OsuSpriteText { Text = c.ToString(), Font = OsuFont.GetFont(size: CalculatedTextSize) },
|
||||
};
|
||||
}
|
||||
|
||||
private class CommitButton : LoadingButton
|
||||
{
|
||||
private const int duration = 200;
|
||||
|
||||
public readonly BindableBool IsBlocked = new BindableBool();
|
||||
|
||||
public override bool PropagatePositionalInputSubTree => !IsBlocked.Value && base.PropagatePositionalInputSubTree;
|
||||
|
||||
protected override IEnumerable<Drawable> EffectTargets => new[] { background };
|
||||
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; }
|
||||
|
||||
private OsuSpriteText drawableText;
|
||||
private Box background;
|
||||
private Box blockedBackground;
|
||||
|
||||
public CommitButton(string text)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
LoadingAnimationSize = new Vector2(10);
|
||||
|
||||
drawableText.Text = text;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
IdleColour = colourProvider.Light4;
|
||||
HoverColour = colourProvider.Light3;
|
||||
blockedBackground.Colour = colourProvider.Background5;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
IsBlocked.BindValueChanged(onBlockedStateChanged, true);
|
||||
}
|
||||
|
||||
private void onBlockedStateChanged(ValueChangedEvent<bool> isBlocked)
|
||||
{
|
||||
drawableText.FadeColour(isBlocked.NewValue ? colourProvider.Foreground1 : Color4.White, duration, Easing.OutQuint);
|
||||
background.FadeTo(isBlocked.NewValue ? 0 : 1, duration, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override Drawable CreateContent() => new CircularContainer
|
||||
{
|
||||
Masking = true,
|
||||
Height = 25,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
blockedBackground = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0
|
||||
},
|
||||
drawableText = new OsuSpriteText
|
||||
{
|
||||
AlwaysPresent = true,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
|
||||
Margin = new MarginPadding { Horizontal = 20 }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
protected override void OnLoadStarted() => drawableText.FadeOut(duration, Easing.OutQuint);
|
||||
|
||||
protected override void OnLoadFinished() => drawableText.FadeIn(duration, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
@ -12,17 +12,20 @@ using osu.Game.Online.API.Requests.Responses;
|
||||
using System.Threading;
|
||||
using System.Linq;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
public class CommentsContainer : CompositeDrawable
|
||||
{
|
||||
private CommentableType type;
|
||||
private long? id;
|
||||
private readonly Bindable<CommentableType> type = new Bindable<CommentableType>();
|
||||
private readonly BindableLong id = new BindableLong();
|
||||
|
||||
public readonly Bindable<CommentsSortCriteria> Sort = new Bindable<CommentsSortCriteria>();
|
||||
public readonly BindableBool ShowDeleted = new BindableBool();
|
||||
|
||||
protected readonly Bindable<User> User = new Bindable<User>();
|
||||
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
@ -31,7 +34,7 @@ namespace osu.Game.Overlays.Comments
|
||||
private int currentPage;
|
||||
|
||||
private FillFlowContainer content;
|
||||
private DeletedChildrenPlaceholder deletedChildrenPlaceholder;
|
||||
private DeletedCommentsCounter deletedCommentsCounter;
|
||||
private CommentsShowMoreButton moreButton;
|
||||
private TotalCommentsCounter commentCounter;
|
||||
|
||||
@ -68,6 +71,7 @@ namespace osu.Game.Overlays.Comments
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Name = @"Footer",
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
@ -84,7 +88,7 @@ namespace osu.Game.Overlays.Comments
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
deletedChildrenPlaceholder = new DeletedChildrenPlaceholder
|
||||
deletedCommentsCounter = new DeletedCommentsCounter
|
||||
{
|
||||
ShowDeleted = { BindTarget = ShowDeleted }
|
||||
},
|
||||
@ -108,10 +112,13 @@ namespace osu.Game.Overlays.Comments
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
User.BindTo(api.LocalUser);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
User.BindValueChanged(_ => refetchComments());
|
||||
Sort.BindValueChanged(_ => refetchComments(), true);
|
||||
base.LoadComplete();
|
||||
}
|
||||
@ -120,8 +127,8 @@ namespace osu.Game.Overlays.Comments
|
||||
/// <param name="id">The id of the resource to get comments for.</param>
|
||||
public void ShowComments(CommentableType type, long id)
|
||||
{
|
||||
this.type = type;
|
||||
this.id = id;
|
||||
this.type.Value = type;
|
||||
this.id.Value = id;
|
||||
|
||||
if (!IsLoaded)
|
||||
return;
|
||||
@ -140,20 +147,21 @@ namespace osu.Game.Overlays.Comments
|
||||
|
||||
private void getComments()
|
||||
{
|
||||
if (!id.HasValue)
|
||||
if (id.Value <= 0)
|
||||
return;
|
||||
|
||||
request?.Cancel();
|
||||
loadCancellation?.Cancel();
|
||||
request = new GetCommentsRequest(type, id.Value, Sort.Value, currentPage++);
|
||||
request = new GetCommentsRequest(id.Value, type.Value, Sort.Value, currentPage++, 0);
|
||||
request.Success += onSuccess;
|
||||
api.Queue(request);
|
||||
api.PerformAsync(request);
|
||||
}
|
||||
|
||||
private void clearComments()
|
||||
{
|
||||
currentPage = 1;
|
||||
deletedChildrenPlaceholder.DeletedCount.Value = 0;
|
||||
deletedCommentsCounter.Count.Value = 0;
|
||||
moreButton.Show();
|
||||
moreButton.IsLoading = true;
|
||||
content.Clear();
|
||||
}
|
||||
@ -162,29 +170,17 @@ namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
loadCancellation = new CancellationTokenSource();
|
||||
|
||||
var page = new FillFlowContainer
|
||||
LoadComponentAsync(new CommentsPage(response)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
};
|
||||
|
||||
foreach (var c in response.Comments)
|
||||
{
|
||||
if (c.IsTopLevel)
|
||||
{
|
||||
page.Add(new DrawableComment(c)
|
||||
{
|
||||
ShowDeleted = { BindTarget = ShowDeleted }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
LoadComponentAsync(page, loaded =>
|
||||
ShowDeleted = { BindTarget = ShowDeleted },
|
||||
Sort = { BindTarget = Sort },
|
||||
Type = { BindTarget = type },
|
||||
CommentableId = { BindTarget = id }
|
||||
}, loaded =>
|
||||
{
|
||||
content.Add(loaded);
|
||||
|
||||
deletedChildrenPlaceholder.DeletedCount.Value += response.Comments.Count(c => c.IsDeleted && c.IsTopLevel);
|
||||
deletedCommentsCounter.Count.Value += response.Comments.Count(c => c.IsDeleted && c.IsTopLevel);
|
||||
|
||||
if (response.HasMore)
|
||||
{
|
||||
@ -194,10 +190,12 @@ namespace osu.Game.Overlays.Comments
|
||||
moreButton.Current.Value = response.TopLevelCount - loadedTopLevelComments;
|
||||
moreButton.IsLoading = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
moreButton.Hide();
|
||||
}
|
||||
|
||||
commentCounter.Current.Value = response.Total;
|
||||
|
||||
moreButton.FadeTo(response.HasMore ? 1 : 0);
|
||||
}, loadCancellation.Token);
|
||||
}
|
||||
|
||||
|
@ -16,8 +16,6 @@ namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
public class CommentsHeader : CompositeDrawable
|
||||
{
|
||||
private const int font_size = 14;
|
||||
|
||||
public readonly Bindable<CommentsSortCriteria> Sort = new Bindable<CommentsSortCriteria>();
|
||||
public readonly BindableBool ShowDeleted = new BindableBool();
|
||||
|
||||
@ -40,29 +38,11 @@ namespace osu.Game.Overlays.Comments
|
||||
Padding = new MarginPadding { Horizontal = 50 },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
new OverlaySortTabControl<CommentsSortCriteria>
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(10, 0),
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Font = OsuFont.GetFont(size: font_size),
|
||||
Text = @"Sort by"
|
||||
},
|
||||
new SortTabControl
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Current = Sort
|
||||
}
|
||||
}
|
||||
Current = Sort
|
||||
},
|
||||
new ShowDeletedButton
|
||||
{
|
||||
@ -106,7 +86,7 @@ namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Font = OsuFont.GetFont(size: font_size),
|
||||
Font = OsuFont.GetFont(size: 12),
|
||||
Text = @"Show deleted"
|
||||
}
|
||||
},
|
||||
@ -126,4 +106,12 @@ namespace osu.Game.Overlays.Comments
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum CommentsSortCriteria
|
||||
{
|
||||
[System.ComponentModel.Description(@"Recent")]
|
||||
New,
|
||||
Old,
|
||||
Top
|
||||
}
|
||||
}
|
||||
|
161
osu.Game/Overlays/Comments/CommentsPage.cs
Normal file
161
osu.Game/Overlays/Comments/CommentsPage.cs
Normal file
@ -0,0 +1,161 @@
|
||||
// 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.Containers;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using System.Linq;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
public class CommentsPage : CompositeDrawable
|
||||
{
|
||||
public readonly BindableBool ShowDeleted = new BindableBool();
|
||||
public readonly Bindable<CommentsSortCriteria> Sort = new Bindable<CommentsSortCriteria>();
|
||||
public readonly Bindable<CommentableType> Type = new Bindable<CommentableType>();
|
||||
public readonly BindableLong CommentableId = new BindableLong();
|
||||
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
private readonly CommentBundle commentBundle;
|
||||
private FillFlowContainer flow;
|
||||
|
||||
public CommentsPage(CommentBundle commentBundle)
|
||||
{
|
||||
this.commentBundle = commentBundle;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colourProvider.Background5
|
||||
},
|
||||
flow = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
}
|
||||
});
|
||||
|
||||
if (!commentBundle.Comments.Any())
|
||||
{
|
||||
flow.Add(new NoCommentsPlaceholder());
|
||||
return;
|
||||
}
|
||||
|
||||
AppendComments(commentBundle);
|
||||
}
|
||||
|
||||
private DrawableComment getDrawableComment(Comment comment)
|
||||
{
|
||||
if (CommentDictionary.TryGetValue(comment.Id, out var existing))
|
||||
return existing;
|
||||
|
||||
return CommentDictionary[comment.Id] = new DrawableComment(comment)
|
||||
{
|
||||
ShowDeleted = { BindTarget = ShowDeleted },
|
||||
Sort = { BindTarget = Sort },
|
||||
RepliesRequested = onCommentRepliesRequested
|
||||
};
|
||||
}
|
||||
|
||||
private void onCommentRepliesRequested(DrawableComment drawableComment, int page)
|
||||
{
|
||||
var request = new GetCommentsRequest(CommentableId.Value, Type.Value, Sort.Value, page, drawableComment.Comment.Id);
|
||||
|
||||
request.Success += response => Schedule(() => AppendComments(response));
|
||||
|
||||
api.PerformAsync(request);
|
||||
}
|
||||
|
||||
protected readonly Dictionary<long, DrawableComment> CommentDictionary = new Dictionary<long, DrawableComment>();
|
||||
|
||||
/// <summary>
|
||||
/// Appends retrieved comments to the subtree rooted of comments in this page.
|
||||
/// </summary>
|
||||
/// <param name="bundle">The bundle of comments to add.</param>
|
||||
protected void AppendComments([NotNull] CommentBundle bundle)
|
||||
{
|
||||
var orphaned = new List<Comment>();
|
||||
|
||||
foreach (var comment in bundle.Comments.Concat(bundle.IncludedComments))
|
||||
{
|
||||
// Exclude possible duplicated comments.
|
||||
if (CommentDictionary.ContainsKey(comment.Id))
|
||||
continue;
|
||||
|
||||
addNewComment(comment);
|
||||
}
|
||||
|
||||
// Comments whose parents were seen later than themselves can now be added.
|
||||
foreach (var o in orphaned)
|
||||
addNewComment(o);
|
||||
|
||||
void addNewComment(Comment comment)
|
||||
{
|
||||
var drawableComment = getDrawableComment(comment);
|
||||
|
||||
if (comment.ParentId == null)
|
||||
{
|
||||
// Comments that have no parent are added as top-level comments to the flow.
|
||||
flow.Add(drawableComment);
|
||||
}
|
||||
else if (CommentDictionary.TryGetValue(comment.ParentId.Value, out var parentDrawable))
|
||||
{
|
||||
// The comment's parent has already been seen, so the parent<-> child links can be added.
|
||||
comment.ParentComment = parentDrawable.Comment;
|
||||
parentDrawable.Replies.Add(drawableComment);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The comment's parent has not been seen yet, so keep it orphaned for the time being. This can occur if the comments arrive out of order.
|
||||
// Since this comment has now been seen, any further children can be added to it without being orphaned themselves.
|
||||
orphaned.Add(comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class NoCommentsPlaceholder : CompositeDrawable
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
Height = 80;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colourProvider.Background4
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Margin = new MarginPadding { Left = 50 },
|
||||
Text = @"No comments yet."
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -14,6 +14,8 @@ namespace osu.Game.Overlays.Comments
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
Height = 20;
|
||||
|
||||
IdleColour = colourProvider.Background2;
|
||||
HoverColour = colourProvider.Background1;
|
||||
ChevronIconColour = colourProvider.Foreground1;
|
||||
|
@ -12,51 +12,56 @@ using osu.Game.Graphics.Sprites;
|
||||
|
||||
namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
public class DeletedChildrenPlaceholder : FillFlowContainer
|
||||
public class DeletedCommentsCounter : CompositeDrawable
|
||||
{
|
||||
public readonly BindableBool ShowDeleted = new BindableBool();
|
||||
public readonly BindableInt DeletedCount = new BindableInt();
|
||||
|
||||
public readonly BindableInt Count = new BindableInt();
|
||||
|
||||
private readonly SpriteText countText;
|
||||
|
||||
public DeletedChildrenPlaceholder()
|
||||
public DeletedCommentsCounter()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Direction = FillDirection.Horizontal;
|
||||
Spacing = new Vector2(3, 0);
|
||||
Margin = new MarginPadding { Vertical = 10, Left = 80 };
|
||||
Children = new Drawable[]
|
||||
|
||||
InternalChild = new FillFlowContainer
|
||||
{
|
||||
new SpriteIcon
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(3, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Icon = FontAwesome.Solid.Trash,
|
||||
Size = new Vector2(14),
|
||||
},
|
||||
countText = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
|
||||
new SpriteIcon
|
||||
{
|
||||
Icon = FontAwesome.Solid.Trash,
|
||||
Size = new Vector2(14),
|
||||
},
|
||||
countText = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
DeletedCount.BindValueChanged(_ => updateDisplay(), true);
|
||||
ShowDeleted.BindValueChanged(_ => updateDisplay(), true);
|
||||
base.LoadComplete();
|
||||
|
||||
Count.BindValueChanged(_ => updateDisplay(), true);
|
||||
ShowDeleted.BindValueChanged(_ => updateDisplay(), true);
|
||||
}
|
||||
|
||||
private void updateDisplay()
|
||||
{
|
||||
if (DeletedCount.Value != 0)
|
||||
if (!ShowDeleted.Value && Count.Value != 0)
|
||||
{
|
||||
countText.Text = @"deleted comment".ToQuantity(DeletedCount.Value);
|
||||
this.FadeTo(ShowDeleted.Value ? 0 : 1);
|
||||
countText.Text = @"deleted comment".ToQuantity(Count.Value);
|
||||
Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
Hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -12,11 +12,16 @@ using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Utils;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using System.Linq;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.Chat;
|
||||
using osu.Framework.Allocation;
|
||||
using osuTK.Graphics;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
@ -25,24 +30,37 @@ namespace osu.Game.Overlays.Comments
|
||||
private const int avatar_size = 40;
|
||||
private const int margin = 10;
|
||||
|
||||
public Action<DrawableComment, int> RepliesRequested;
|
||||
|
||||
public readonly Comment Comment;
|
||||
|
||||
public readonly BindableBool ShowDeleted = new BindableBool();
|
||||
public readonly Bindable<CommentsSortCriteria> Sort = new Bindable<CommentsSortCriteria>();
|
||||
private readonly Dictionary<long, Comment> loadedReplies = new Dictionary<long, Comment>();
|
||||
|
||||
public readonly BindableList<DrawableComment> Replies = new BindableList<DrawableComment>();
|
||||
|
||||
private readonly BindableBool childrenExpanded = new BindableBool(true);
|
||||
|
||||
private int currentPage;
|
||||
|
||||
private FillFlowContainer childCommentsVisibilityContainer;
|
||||
private readonly Comment comment;
|
||||
private FillFlowContainer childCommentsContainer;
|
||||
private LoadMoreCommentsButton loadMoreCommentsButton;
|
||||
private ShowMoreButton showMoreButton;
|
||||
private RepliesButton repliesButton;
|
||||
private ChevronButton chevronButton;
|
||||
private DeletedCommentsCounter deletedCommentsCounter;
|
||||
|
||||
public DrawableComment(Comment comment)
|
||||
{
|
||||
this.comment = comment;
|
||||
Comment = comment;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
LinkFlowContainer username;
|
||||
FillFlowContainer childCommentsContainer;
|
||||
DeletedChildrenPlaceholder deletedChildrenPlaceholder;
|
||||
FillFlowContainer info;
|
||||
LinkFlowContainer message;
|
||||
GridContainer content;
|
||||
@ -50,234 +68,296 @@ namespace osu.Game.Overlays.Comments
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
InternalChild = new FillFlowContainer
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
new FillFlowContainer
|
||||
{
|
||||
new Container
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding(margin) { Left = margin + 5 },
|
||||
Child = content = new GridContainer
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
ColumnDimensions = new[]
|
||||
Padding = new MarginPadding(margin) { Left = margin + 5 },
|
||||
Child = content = new GridContainer
|
||||
{
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension(),
|
||||
},
|
||||
RowDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.AutoSize)
|
||||
},
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[]
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
ColumnDimensions = new[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension(),
|
||||
},
|
||||
RowDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.AutoSize)
|
||||
},
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Margin = new MarginPadding { Horizontal = margin },
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(5, 0),
|
||||
Children = new Drawable[]
|
||||
new FillFlowContainer
|
||||
{
|
||||
new Container
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Margin = new MarginPadding { Horizontal = margin },
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(5, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Width = 40,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Child = votePill = new VotePill(comment)
|
||||
new Container
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
}
|
||||
},
|
||||
new UpdateableAvatar(comment.User)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(avatar_size),
|
||||
Masking = true,
|
||||
CornerRadius = avatar_size / 2f,
|
||||
CornerExponent = 2,
|
||||
},
|
||||
}
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Spacing = new Vector2(0, 3),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(7, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true))
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Width = 40,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Child = votePill = new VotePill(Comment)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
},
|
||||
new ParentUsername(comment),
|
||||
new OsuSpriteText
|
||||
{
|
||||
Alpha = comment.IsDeleted ? 1 : 0,
|
||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
|
||||
Text = @"deleted",
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
}
|
||||
}
|
||||
},
|
||||
message = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14))
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding { Right = 40 }
|
||||
},
|
||||
info = new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(10, 0),
|
||||
Colour = OsuColour.Gray(0.7f),
|
||||
Children = new Drawable[]
|
||||
},
|
||||
new UpdateableAvatar(Comment.User)
|
||||
{
|
||||
new OsuSpriteText
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(avatar_size),
|
||||
Masking = true,
|
||||
CornerRadius = avatar_size / 2f,
|
||||
CornerExponent = 2,
|
||||
},
|
||||
}
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Spacing = new Vector2(0, 3),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(7, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Font = OsuFont.GetFont(size: 12),
|
||||
Text = HumanizerUtils.Humanize(comment.CreatedAt)
|
||||
},
|
||||
new RepliesButton(comment.RepliesCount)
|
||||
username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true))
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
},
|
||||
new ParentUsername(Comment),
|
||||
new OsuSpriteText
|
||||
{
|
||||
Alpha = Comment.IsDeleted ? 1 : 0,
|
||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
|
||||
Text = @"deleted",
|
||||
}
|
||||
}
|
||||
},
|
||||
message = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14))
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding { Right = 40 }
|
||||
},
|
||||
info = new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(10, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Expanded = { BindTarget = childrenExpanded }
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Font = OsuFont.GetFont(size: 12),
|
||||
Colour = OsuColour.Gray(0.7f),
|
||||
Text = HumanizerUtils.Humanize(Comment.CreatedAt)
|
||||
},
|
||||
repliesButton = new RepliesButton(Comment.RepliesCount)
|
||||
{
|
||||
Expanded = { BindTarget = childrenExpanded }
|
||||
},
|
||||
loadMoreCommentsButton = new LoadMoreCommentsButton
|
||||
{
|
||||
Action = () => RepliesRequested(this, ++currentPage)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
childCommentsVisibilityContainer = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
},
|
||||
childCommentsVisibilityContainer = new FillFlowContainer
|
||||
{
|
||||
childCommentsContainer = new FillFlowContainer
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Padding = new MarginPadding { Left = 20 },
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical
|
||||
},
|
||||
deletedChildrenPlaceholder = new DeletedChildrenPlaceholder
|
||||
{
|
||||
ShowDeleted = { BindTarget = ShowDeleted }
|
||||
childCommentsContainer = new FillFlowContainer
|
||||
{
|
||||
Padding = new MarginPadding { Left = 20 },
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical
|
||||
},
|
||||
deletedCommentsCounter = new DeletedCommentsCounter
|
||||
{
|
||||
ShowDeleted = { BindTarget = ShowDeleted }
|
||||
},
|
||||
showMoreButton = new ShowMoreButton
|
||||
{
|
||||
Action = () => RepliesRequested(this, ++currentPage)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
chevronButton = new ChevronButton
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
Margin = new MarginPadding { Right = 30, Top = margin },
|
||||
Expanded = { BindTarget = childrenExpanded },
|
||||
Alpha = 0
|
||||
}
|
||||
};
|
||||
|
||||
deletedChildrenPlaceholder.DeletedCount.Value = comment.DeletedChildrenCount;
|
||||
|
||||
if (comment.UserId.HasValue)
|
||||
username.AddUserLink(comment.User);
|
||||
if (Comment.UserId.HasValue)
|
||||
username.AddUserLink(Comment.User);
|
||||
else
|
||||
username.AddText(comment.LegacyName);
|
||||
username.AddText(Comment.LegacyName);
|
||||
|
||||
if (comment.EditedAt.HasValue)
|
||||
if (Comment.EditedAt.HasValue)
|
||||
{
|
||||
info.Add(new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Font = OsuFont.GetFont(size: 12),
|
||||
Text = $@"edited {HumanizerUtils.Humanize(comment.EditedAt.Value)} by {comment.EditedUser.Username}"
|
||||
Text = $@"edited {HumanizerUtils.Humanize(Comment.EditedAt.Value)} by {Comment.EditedUser.Username}"
|
||||
});
|
||||
}
|
||||
|
||||
if (comment.HasMessage)
|
||||
if (Comment.HasMessage)
|
||||
{
|
||||
var formattedSource = MessageFormatter.FormatText(comment.GetMessage);
|
||||
var formattedSource = MessageFormatter.FormatText(Comment.Message);
|
||||
message.AddLinks(formattedSource.Text, formattedSource.Links);
|
||||
}
|
||||
|
||||
if (comment.IsDeleted)
|
||||
if (Comment.IsDeleted)
|
||||
{
|
||||
content.FadeColour(OsuColour.Gray(0.5f));
|
||||
votePill.Hide();
|
||||
}
|
||||
|
||||
if (comment.IsTopLevel)
|
||||
if (Comment.IsTopLevel)
|
||||
{
|
||||
AddInternal(new Container
|
||||
AddInternal(new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 1.5f,
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
Child = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.Gray(0.1f)
|
||||
}
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 1.5f,
|
||||
Colour = OsuColour.Gray(0.1f)
|
||||
});
|
||||
|
||||
if (comment.ChildComments.Any())
|
||||
{
|
||||
AddInternal(new ChevronButton(comment)
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
Margin = new MarginPadding { Right = 30, Top = margin },
|
||||
Expanded = { BindTarget = childrenExpanded }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
comment.ChildComments.ForEach(c => childCommentsContainer.Add(new DrawableComment(c)
|
||||
if (Replies.Any())
|
||||
onRepliesAdded(Replies);
|
||||
|
||||
Replies.CollectionChanged += (_, args) =>
|
||||
{
|
||||
ShowDeleted = { BindTarget = ShowDeleted }
|
||||
}));
|
||||
switch (args.Action)
|
||||
{
|
||||
case NotifyCollectionChangedAction.Add:
|
||||
onRepliesAdded(args.NewItems.Cast<DrawableComment>());
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotSupportedException(@"You can only add replies to this list. Other actions are not supported.");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
ShowDeleted.BindValueChanged(show =>
|
||||
{
|
||||
if (comment.IsDeleted)
|
||||
if (Comment.IsDeleted)
|
||||
this.FadeTo(show.NewValue ? 1 : 0);
|
||||
}, true);
|
||||
childrenExpanded.BindValueChanged(expanded => childCommentsVisibilityContainer.FadeTo(expanded.NewValue ? 1 : 0), true);
|
||||
|
||||
updateButtonsState();
|
||||
|
||||
base.LoadComplete();
|
||||
}
|
||||
|
||||
public bool ContainsReply(long replyId) => loadedReplies.ContainsKey(replyId);
|
||||
|
||||
private void onRepliesAdded(IEnumerable<DrawableComment> replies)
|
||||
{
|
||||
var page = createRepliesPage(replies);
|
||||
|
||||
if (LoadState == LoadState.Loading)
|
||||
{
|
||||
addRepliesPage(page, replies);
|
||||
return;
|
||||
}
|
||||
|
||||
LoadComponentAsync(page, loaded => addRepliesPage(loaded, replies));
|
||||
}
|
||||
|
||||
private void addRepliesPage(FillFlowContainer<DrawableComment> page, IEnumerable<DrawableComment> replies)
|
||||
{
|
||||
childCommentsContainer.Add(page);
|
||||
|
||||
var newReplies = replies.Select(reply => reply.Comment);
|
||||
newReplies.ForEach(reply => loadedReplies.Add(reply.Id, reply));
|
||||
deletedCommentsCounter.Count.Value += newReplies.Count(reply => reply.IsDeleted);
|
||||
updateButtonsState();
|
||||
}
|
||||
|
||||
private FillFlowContainer<DrawableComment> createRepliesPage(IEnumerable<DrawableComment> replies) => new FillFlowContainer<DrawableComment>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = replies.ToList()
|
||||
};
|
||||
|
||||
private void updateButtonsState()
|
||||
{
|
||||
var loadedReplesCount = loadedReplies.Count;
|
||||
var hasUnloadedReplies = loadedReplesCount != Comment.RepliesCount;
|
||||
|
||||
loadMoreCommentsButton.FadeTo(hasUnloadedReplies && loadedReplesCount == 0 ? 1 : 0);
|
||||
showMoreButton.FadeTo(hasUnloadedReplies && loadedReplesCount > 0 ? 1 : 0);
|
||||
repliesButton.FadeTo(loadedReplesCount != 0 ? 1 : 0);
|
||||
|
||||
if (Comment.IsTopLevel)
|
||||
chevronButton.FadeTo(loadedReplesCount != 0 ? 1 : 0);
|
||||
|
||||
showMoreButton.IsLoading = loadMoreCommentsButton.IsLoading = false;
|
||||
}
|
||||
|
||||
private class ChevronButton : ShowChildrenButton
|
||||
{
|
||||
private readonly SpriteIcon icon;
|
||||
|
||||
public ChevronButton(Comment comment)
|
||||
public ChevronButton()
|
||||
{
|
||||
Alpha = comment.IsTopLevel && comment.ChildComments.Any() ? 1 : 0;
|
||||
Child = icon = new SpriteIcon
|
||||
{
|
||||
Size = new Vector2(12),
|
||||
Colour = OsuColour.Gray(0.7f)
|
||||
};
|
||||
}
|
||||
|
||||
@ -296,7 +376,6 @@ namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
this.count = count;
|
||||
|
||||
Alpha = count == 0 ? 0 : 1;
|
||||
Child = text = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
|
||||
@ -305,10 +384,34 @@ namespace osu.Game.Overlays.Comments
|
||||
|
||||
protected override void OnExpandedChanged(ValueChangedEvent<bool> expanded)
|
||||
{
|
||||
text.Text = $@"{(expanded.NewValue ? "[+]" : "[-]")} replies ({count})";
|
||||
text.Text = $@"{(expanded.NewValue ? "[-]" : "[+]")} replies ({count})";
|
||||
}
|
||||
}
|
||||
|
||||
private class LoadMoreCommentsButton : GetCommentRepliesButton
|
||||
{
|
||||
public LoadMoreCommentsButton()
|
||||
{
|
||||
IdleColour = OsuColour.Gray(0.7f);
|
||||
HoverColour = Color4.White;
|
||||
}
|
||||
|
||||
protected override string GetText() => @"[+] load replies";
|
||||
}
|
||||
|
||||
private class ShowMoreButton : GetCommentRepliesButton
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
Margin = new MarginPadding { Vertical = 10, Left = 80 };
|
||||
IdleColour = colourProvider.Light2;
|
||||
HoverColour = colourProvider.Light1;
|
||||
}
|
||||
|
||||
protected override string GetText() => @"Show More";
|
||||
}
|
||||
|
||||
private class ParentUsername : FillFlowContainer, IHasTooltip
|
||||
{
|
||||
public string TooltipText => getParentMessage();
|
||||
@ -343,7 +446,7 @@ namespace osu.Game.Overlays.Comments
|
||||
if (parentComment == null)
|
||||
return string.Empty;
|
||||
|
||||
return parentComment.HasMessage ? parentComment.GetMessage : parentComment.IsDeleted ? @"deleted" : string.Empty;
|
||||
return parentComment.HasMessage ? parentComment.Message : parentComment.IsDeleted ? @"deleted" : string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
45
osu.Game/Overlays/Comments/GetCommentRepliesButton.cs
Normal file
45
osu.Game/Overlays/Comments/GetCommentRepliesButton.cs
Normal file
@ -0,0 +1,45 @@
|
||||
// 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.Graphics;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using System.Collections.Generic;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
public abstract class GetCommentRepliesButton : LoadingButton
|
||||
{
|
||||
private const int duration = 200;
|
||||
|
||||
protected override IEnumerable<Drawable> EffectTargets => new[] { text };
|
||||
|
||||
private OsuSpriteText text;
|
||||
|
||||
protected GetCommentRepliesButton()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
LoadingAnimationSize = new Vector2(8);
|
||||
}
|
||||
|
||||
protected override Drawable CreateContent() => new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Child = text = new OsuSpriteText
|
||||
{
|
||||
AlwaysPresent = true,
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
|
||||
Text = GetText()
|
||||
}
|
||||
};
|
||||
|
||||
protected abstract string GetText();
|
||||
|
||||
protected override void OnLoadStarted() => text.FadeOut(duration, Easing.OutQuint);
|
||||
|
||||
protected override void OnLoadFinished() => text.FadeIn(duration, Easing.OutQuint);
|
||||
}
|
||||
}
|
@ -3,8 +3,9 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Bindables;
|
||||
using osuTK.Graphics;
|
||||
using osu.Game.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
@ -15,20 +16,18 @@ namespace osu.Game.Overlays.Comments
|
||||
protected ShowChildrenButton()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
IdleColour = OsuColour.Gray(0.7f);
|
||||
HoverColour = Color4.White;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
Action = Expanded.Toggle;
|
||||
|
||||
Expanded.BindValueChanged(OnExpandedChanged, true);
|
||||
base.LoadComplete();
|
||||
}
|
||||
|
||||
protected abstract void OnExpandedChanged(ValueChangedEvent<bool> expanded);
|
||||
|
||||
protected override bool OnClick(ClickEvent e)
|
||||
{
|
||||
Expanded.Value = !Expanded.Value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,110 +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 osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics;
|
||||
using osuTK;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
public class SortTabControl : OsuTabControl<CommentsSortCriteria>
|
||||
{
|
||||
protected override Dropdown<CommentsSortCriteria> CreateDropdown() => null;
|
||||
|
||||
protected override TabItem<CommentsSortCriteria> CreateTabItem(CommentsSortCriteria value) => new SortTabItem(value);
|
||||
|
||||
protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(5, 0),
|
||||
};
|
||||
|
||||
public SortTabControl()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
private class SortTabItem : TabItem<CommentsSortCriteria>
|
||||
{
|
||||
public SortTabItem(CommentsSortCriteria value)
|
||||
: base(value)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Child = new TabButton(value) { Active = { BindTarget = Active } };
|
||||
}
|
||||
|
||||
protected override void OnActivated()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnDeactivated()
|
||||
{
|
||||
}
|
||||
|
||||
private class TabButton : HeaderButton
|
||||
{
|
||||
public readonly BindableBool Active = new BindableBool();
|
||||
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; }
|
||||
|
||||
private readonly SpriteText text;
|
||||
|
||||
public TabButton(CommentsSortCriteria value)
|
||||
{
|
||||
Add(text = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 14),
|
||||
Text = value.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
Active.BindValueChanged(active =>
|
||||
{
|
||||
updateBackgroundState();
|
||||
|
||||
text.Font = text.Font.With(weight: active.NewValue ? FontWeight.Bold : FontWeight.Medium);
|
||||
text.Colour = active.NewValue ? colourProvider.Light1 : Color4.White;
|
||||
}, true);
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
updateBackgroundState();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e) => updateBackgroundState();
|
||||
|
||||
private void updateBackgroundState()
|
||||
{
|
||||
if (Active.Value || IsHovered)
|
||||
ShowBackground();
|
||||
else
|
||||
HideBackground();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum CommentsSortCriteria
|
||||
{
|
||||
New,
|
||||
Old,
|
||||
Top
|
||||
}
|
||||
}
|
@ -33,6 +33,9 @@ namespace osu.Game.Overlays.Comments
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; }
|
||||
|
||||
private readonly Comment comment;
|
||||
private Box background;
|
||||
private Box hoverLayer;
|
||||
@ -68,7 +71,7 @@ namespace osu.Game.Overlays.Comments
|
||||
base.LoadComplete();
|
||||
isVoted.Value = comment.IsVoted;
|
||||
votesCount.Value = comment.VotesCount;
|
||||
isVoted.BindValueChanged(voted => background.Colour = voted.NewValue ? AccentColour : OsuColour.Gray(0.05f), true);
|
||||
isVoted.BindValueChanged(voted => background.Colour = voted.NewValue ? AccentColour : colourProvider.Background6, true);
|
||||
votesCount.BindValueChanged(count => votesCounter.Text = $"+{count.NewValue}", true);
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,6 @@ using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osuTK;
|
||||
@ -114,13 +113,13 @@ namespace osu.Game.Overlays.Dialog
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.FromHex(@"221a21"),
|
||||
Colour = Color4Extensions.FromHex(@"221a21"),
|
||||
},
|
||||
new Triangles
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
ColourLight = OsuColour.FromHex(@"271e26"),
|
||||
ColourDark = OsuColour.FromHex(@"1e171e"),
|
||||
ColourLight = Color4Extensions.FromHex(@"271e26"),
|
||||
ColourDark = Color4Extensions.FromHex(@"1e171e"),
|
||||
TriangleScale = 4,
|
||||
},
|
||||
},
|
||||
|
@ -1,7 +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.Game.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Overlays.Dialog
|
||||
@ -11,7 +11,7 @@ namespace osu.Game.Overlays.Dialog
|
||||
public PopupDialogButton()
|
||||
{
|
||||
Height = 50;
|
||||
BackgroundColour = OsuColour.FromHex(@"150e14");
|
||||
BackgroundColour = Color4Extensions.FromHex(@"150e14");
|
||||
TextSize = 18;
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Direct
|
||||
public DownloadProgressBar(BeatmapSetInfo beatmapSet)
|
||||
: base(beatmapSet)
|
||||
{
|
||||
AddInternal(progressBar = new ProgressBar
|
||||
AddInternal(progressBar = new InteractionDisabledProgressBar
|
||||
{
|
||||
Height = 0,
|
||||
Alpha = 0,
|
||||
@ -64,5 +64,11 @@ namespace osu.Game.Overlays.Direct
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
private class InteractionDisabledProgressBar : ProgressBar
|
||||
{
|
||||
public override bool HandlePositionalInput => false;
|
||||
public override bool HandleNonPositionalInput => false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Online.API.Requests;
|
||||
@ -16,7 +17,7 @@ namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
private DirectRulesetSelector rulesetSelector;
|
||||
|
||||
protected override Color4 BackgroundColour => OsuColour.FromHex(@"384552");
|
||||
protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"384552");
|
||||
protected override DirectSortCriteria DefaultTab => DirectSortCriteria.Ranked;
|
||||
protected override BeatmapSearchCategory DefaultCategory => BeatmapSearchCategory.Leaderboard;
|
||||
|
||||
@ -34,14 +35,13 @@ namespace osu.Game.Overlays.Direct
|
||||
|
||||
public enum DirectSortCriteria
|
||||
{
|
||||
Relevance,
|
||||
Title,
|
||||
Artist,
|
||||
Creator,
|
||||
Difficulty,
|
||||
Ranked,
|
||||
Rating,
|
||||
Plays,
|
||||
Favourites,
|
||||
Relevance,
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.ComponentModel;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
@ -13,7 +14,7 @@ namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
public class Header : SearchableListHeader<DirectTab>
|
||||
{
|
||||
protected override Color4 BackgroundColour => OsuColour.FromHex(@"252f3a");
|
||||
protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"252f3a");
|
||||
|
||||
protected override DirectTab DefaultTab => DirectTab.Search;
|
||||
protected override Drawable CreateHeaderText() => new OsuSpriteText { Text = @"osu!direct", Font = OsuFont.GetFont(size: 25) };
|
||||
|
@ -45,7 +45,7 @@ namespace osu.Game.Overlays.Direct
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OsuGame game, BeatmapManager beatmaps)
|
||||
{
|
||||
if (BeatmapSet.Value.OnlineInfo.Availability?.DownloadDisabled ?? false)
|
||||
if (BeatmapSet.Value?.OnlineInfo?.Availability?.DownloadDisabled ?? false)
|
||||
{
|
||||
button.Enabled.Value = false;
|
||||
button.TooltipText = "this beatmap is currently not available for download.";
|
||||
@ -62,7 +62,7 @@ namespace osu.Game.Overlays.Direct
|
||||
break;
|
||||
|
||||
case DownloadState.LocallyAvailable:
|
||||
game.PresentBeatmap(BeatmapSet.Value);
|
||||
game?.PresentBeatmap(BeatmapSet.Value);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -42,7 +42,7 @@ namespace osu.Game.Overlays.Direct
|
||||
|
||||
private Color4 hoverColour;
|
||||
private readonly SpriteIcon icon;
|
||||
private readonly LoadingAnimation loadingAnimation;
|
||||
private readonly LoadingSpinner loadingSpinner;
|
||||
|
||||
private const float transition_duration = 500;
|
||||
|
||||
@ -53,12 +53,12 @@ namespace osu.Game.Overlays.Direct
|
||||
if (value)
|
||||
{
|
||||
icon.FadeTo(0.5f, transition_duration, Easing.OutQuint);
|
||||
loadingAnimation.Show();
|
||||
loadingSpinner.Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
icon.FadeTo(1, transition_duration, Easing.OutQuint);
|
||||
loadingAnimation.Hide();
|
||||
loadingSpinner.Hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -76,7 +76,7 @@ namespace osu.Game.Overlays.Direct
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Icon = FontAwesome.Solid.Play,
|
||||
},
|
||||
loadingAnimation = new LoadingAnimation
|
||||
loadingSpinner = new LoadingSpinner
|
||||
{
|
||||
Size = new Vector2(15),
|
||||
},
|
||||
@ -85,13 +85,12 @@ namespace osu.Game.Overlays.Direct
|
||||
Playing.ValueChanged += playingStateChanged;
|
||||
}
|
||||
|
||||
private PreviewTrackManager previewTrackManager;
|
||||
[Resolved]
|
||||
private PreviewTrackManager previewTrackManager { get; set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colour, PreviewTrackManager previewTrackManager)
|
||||
private void load(OsuColour colour)
|
||||
{
|
||||
this.previewTrackManager = previewTrackManager;
|
||||
|
||||
hoverColour = colour.Yellow;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
||||
using Humanizer;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Threading;
|
||||
@ -27,15 +28,16 @@ namespace osu.Game.Overlays
|
||||
{
|
||||
private const float panel_padding = 10f;
|
||||
|
||||
private RulesetStore rulesets;
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
private readonly FillFlowContainer resultCountsContainer;
|
||||
private readonly OsuSpriteText resultCountsText;
|
||||
private FillFlowContainer<DirectPanel> panels;
|
||||
|
||||
protected override Color4 BackgroundColour => OsuColour.FromHex(@"485e74");
|
||||
protected override Color4 TrianglesColourLight => OsuColour.FromHex(@"465b71");
|
||||
protected override Color4 TrianglesColourDark => OsuColour.FromHex(@"3f5265");
|
||||
protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"485e74");
|
||||
protected override Color4 TrianglesColourLight => Color4Extensions.FromHex(@"465b71");
|
||||
protected override Color4 TrianglesColourDark => Color4Extensions.FromHex(@"3f5265");
|
||||
|
||||
protected override SearchableListHeader<DirectTab> CreateHeader() => new Header();
|
||||
protected override SearchableListFilterControl<DirectSortCriteria, BeatmapSearchCategory> CreateFilterControl() => new FilterControl();
|
||||
@ -161,11 +163,8 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, RulesetStore rulesets, PreviewTrackManager previewTrackManager)
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
this.rulesets = rulesets;
|
||||
this.previewTrackManager = previewTrackManager;
|
||||
|
||||
resultCountsContainer.Colour = colours.Yellow;
|
||||
}
|
||||
|
||||
@ -234,7 +233,9 @@ namespace osu.Game.Overlays
|
||||
private readonly Bindable<string> currentQuery = new Bindable<string>(string.Empty);
|
||||
|
||||
private ScheduledDelegate queryChangedDebounce;
|
||||
private PreviewTrackManager previewTrackManager;
|
||||
|
||||
[Resolved]
|
||||
private PreviewTrackManager previewTrackManager { get; set; }
|
||||
|
||||
private void queueUpdateSearch(bool queryTextChanged = false)
|
||||
{
|
||||
|
@ -18,11 +18,11 @@ namespace osu.Game.Overlays
|
||||
protected IAPIProvider API { get; private set; }
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider;
|
||||
protected readonly OverlayColourProvider ColourProvider;
|
||||
|
||||
protected FullscreenOverlay(OverlayColourScheme colourScheme)
|
||||
{
|
||||
colourProvider = new OverlayColourProvider(colourScheme);
|
||||
ColourProvider = new OverlayColourProvider(colourScheme);
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
RelativePositionAxes = Axes.Both;
|
||||
@ -43,10 +43,10 @@ namespace osu.Game.Overlays
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Waves.FirstWaveColour = colourProvider.Light4;
|
||||
Waves.SecondWaveColour = colourProvider.Light3;
|
||||
Waves.ThirdWaveColour = colourProvider.Dark4;
|
||||
Waves.FourthWaveColour = colourProvider.Dark3;
|
||||
Waves.FirstWaveColour = ColourProvider.Light4;
|
||||
Waves.SecondWaveColour = ColourProvider.Light3;
|
||||
Waves.ThirdWaveColour = ColourProvider.Dark4;
|
||||
Waves.FourthWaveColour = ColourProvider.Dark3;
|
||||
}
|
||||
|
||||
public override void Show()
|
||||
|
25
osu.Game/Overlays/Home/Friends/FriendsBundle.cs
Normal file
25
osu.Game/Overlays/Home/Friends/FriendsBundle.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.
|
||||
|
||||
namespace osu.Game.Overlays.Home.Friends
|
||||
{
|
||||
public class FriendsBundle
|
||||
{
|
||||
public FriendsOnlineStatus Status { get; }
|
||||
|
||||
public int Count { get; }
|
||||
|
||||
public FriendsBundle(FriendsOnlineStatus status, int count)
|
||||
{
|
||||
Status = status;
|
||||
Count = count;
|
||||
}
|
||||
}
|
||||
|
||||
public enum FriendsOnlineStatus
|
||||
{
|
||||
All,
|
||||
Online,
|
||||
Offline
|
||||
}
|
||||
}
|
26
osu.Game/Overlays/Home/Friends/FriendsOnlineStatusControl.cs
Normal file
26
osu.Game/Overlays/Home/Friends/FriendsOnlineStatusControl.cs
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Overlays.Home.Friends
|
||||
{
|
||||
public class FriendsOnlineStatusControl : OverlayStreamControl<FriendsBundle>
|
||||
{
|
||||
protected override OverlayStreamItem<FriendsBundle> CreateStreamItem(FriendsBundle value) => new FriendsOnlineStatusItem(value);
|
||||
|
||||
public void Populate(List<User> users)
|
||||
{
|
||||
var userCount = users.Count;
|
||||
var onlineUsersCount = users.Count(user => user.IsOnline);
|
||||
|
||||
AddItem(new FriendsBundle(FriendsOnlineStatus.All, userCount));
|
||||
AddItem(new FriendsBundle(FriendsOnlineStatus.Online, onlineUsersCount));
|
||||
AddItem(new FriendsBundle(FriendsOnlineStatus.Offline, userCount - onlineUsersCount));
|
||||
|
||||
Current.Value = Items.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
39
osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs
Normal file
39
osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs
Normal file
@ -0,0 +1,39 @@
|
||||
// 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.Graphics;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Home.Friends
|
||||
{
|
||||
public class FriendsOnlineStatusItem : OverlayStreamItem<FriendsBundle>
|
||||
{
|
||||
public FriendsOnlineStatusItem(FriendsBundle value)
|
||||
: base(value)
|
||||
{
|
||||
}
|
||||
|
||||
protected override string MainText => Value.Status.ToString();
|
||||
|
||||
protected override string AdditionalText => Value.Count.ToString();
|
||||
|
||||
protected override Color4 GetBarColour(OsuColour colours)
|
||||
{
|
||||
switch (Value.Status)
|
||||
{
|
||||
case FriendsOnlineStatus.All:
|
||||
return Color4.White;
|
||||
|
||||
case FriendsOnlineStatus.Online:
|
||||
return colours.GreenLight;
|
||||
|
||||
case FriendsOnlineStatus.Offline:
|
||||
return Color4.Black;
|
||||
|
||||
default:
|
||||
throw new ArgumentException($@"{Value.Status} status does not provide a colour in {nameof(GetBarColour)}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
45
osu.Game/Overlays/Home/Friends/UserListToolbar.cs
Normal file
45
osu.Game/Overlays/Home/Friends/UserListToolbar.cs
Normal file
@ -0,0 +1,45 @@
|
||||
// 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.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osuTK;
|
||||
using osu.Framework.Bindables;
|
||||
|
||||
namespace osu.Game.Overlays.Home.Friends
|
||||
{
|
||||
public class UserListToolbar : CompositeDrawable
|
||||
{
|
||||
public Bindable<UserSortCriteria> SortCriteria => sortControl.Current;
|
||||
|
||||
public Bindable<OverlayPanelDisplayStyle> DisplayStyle => styleControl.Current;
|
||||
|
||||
private readonly UserSortTabControl sortControl;
|
||||
private readonly OverlayPanelDisplayStyleControl styleControl;
|
||||
|
||||
public UserListToolbar()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
AddInternal(new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(10, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
sortControl = new UserSortTabControl
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
styleControl = new OverlayPanelDisplayStyleControl
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
19
osu.Game/Overlays/Home/Friends/UserSortTabControl.cs
Normal file
19
osu.Game/Overlays/Home/Friends/UserSortTabControl.cs
Normal file
@ -0,0 +1,19 @@
|
||||
// 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.Overlays.Home.Friends
|
||||
{
|
||||
public class UserSortTabControl : OverlaySortTabControl<UserSortCriteria>
|
||||
{
|
||||
}
|
||||
|
||||
public enum UserSortCriteria
|
||||
{
|
||||
[Description(@"Recently Active")]
|
||||
LastVisit,
|
||||
Rank,
|
||||
Username
|
||||
}
|
||||
}
|
@ -66,13 +66,12 @@ namespace osu.Game.Overlays.KeyBinding
|
||||
CornerRadius = padding;
|
||||
}
|
||||
|
||||
private KeyBindingStore store;
|
||||
[Resolved]
|
||||
private KeyBindingStore store { get; set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, KeyBindingStore store)
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
this.store = store;
|
||||
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Radius = 2,
|
||||
|
@ -126,14 +126,14 @@ namespace osu.Game.Overlays
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.FromHex(@"05262f"),
|
||||
Colour = Color4Extensions.FromHex(@"05262f"),
|
||||
},
|
||||
new Triangles
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
TriangleScale = 2,
|
||||
ColourDark = OsuColour.FromHex(@"04222b"),
|
||||
ColourLight = OsuColour.FromHex(@"052933"),
|
||||
ColourDark = Color4Extensions.FromHex(@"04222b"),
|
||||
ColourLight = Color4Extensions.FromHex(@"052933"),
|
||||
},
|
||||
innerSpin = new Sprite
|
||||
{
|
||||
|
@ -30,6 +30,8 @@ namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
public class ModSelectOverlay : WaveOverlayContainer
|
||||
{
|
||||
public const float HEIGHT = 510;
|
||||
|
||||
protected readonly TriangleButton DeselectAllButton;
|
||||
protected readonly TriangleButton CustomiseButton;
|
||||
protected readonly TriangleButton CloseButton;
|
||||
@ -47,7 +49,7 @@ namespace osu.Game.Overlays.Mods
|
||||
|
||||
protected readonly Container ModSettingsContainer;
|
||||
|
||||
protected readonly Bindable<IReadOnlyList<Mod>> SelectedMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
||||
public readonly Bindable<IReadOnlyList<Mod>> SelectedMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
||||
|
||||
private Bindable<Dictionary<ModType, IReadOnlyList<Mod>>> availableMods;
|
||||
|
||||
@ -61,12 +63,13 @@ namespace osu.Game.Overlays.Mods
|
||||
|
||||
public ModSelectOverlay()
|
||||
{
|
||||
Waves.FirstWaveColour = OsuColour.FromHex(@"19b0e2");
|
||||
Waves.SecondWaveColour = OsuColour.FromHex(@"2280a2");
|
||||
Waves.ThirdWaveColour = OsuColour.FromHex(@"005774");
|
||||
Waves.FourthWaveColour = OsuColour.FromHex(@"003a4e");
|
||||
Waves.FirstWaveColour = Color4Extensions.FromHex(@"19b0e2");
|
||||
Waves.SecondWaveColour = Color4Extensions.FromHex(@"2280a2");
|
||||
Waves.ThirdWaveColour = Color4Extensions.FromHex(@"005774");
|
||||
Waves.FourthWaveColour = Color4Extensions.FromHex(@"003a4e");
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
Height = 510;
|
||||
Padding = new MarginPadding { Horizontal = -OsuScreen.HORIZONTAL_OVERFLOW_PADDING };
|
||||
|
||||
Children = new Drawable[]
|
||||
@ -85,8 +88,7 @@ namespace osu.Game.Overlays.Mods
|
||||
new Triangles
|
||||
{
|
||||
TriangleScale = 5,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = Height, //set the height from the start to ensure correct triangle density.
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
ColourLight = new Color4(53, 66, 82, 255),
|
||||
ColourDark = new Color4(41, 54, 70, 255),
|
||||
},
|
||||
@ -321,14 +323,13 @@ namespace osu.Game.Overlays.Mods
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OsuColour colours, AudioManager audio, Bindable<IReadOnlyList<Mod>> selectedMods, OsuGameBase osu)
|
||||
private void load(OsuColour colours, AudioManager audio, OsuGameBase osu)
|
||||
{
|
||||
LowMultiplierColour = colours.Red;
|
||||
HighMultiplierColour = colours.Green;
|
||||
UnrankedLabel.Colour = colours.Blue;
|
||||
|
||||
availableMods = osu.AvailableMods.GetBoundCopy();
|
||||
SelectedMods.BindTo(selectedMods);
|
||||
|
||||
sampleOn = audio.Samples.Get(@"UI/check-on");
|
||||
sampleOff = audio.Samples.Get(@"UI/check-off");
|
||||
|
44
osu.Game/Overlays/Music/Playlist.cs
Normal file
44
osu.Game/Overlays/Music/Playlist.cs
Normal file
@ -0,0 +1,44 @@
|
||||
// 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 osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.Music
|
||||
{
|
||||
public class Playlist : OsuRearrangeableListContainer<BeatmapSetInfo>
|
||||
{
|
||||
public Action<BeatmapSetInfo> RequestSelection;
|
||||
|
||||
public readonly Bindable<BeatmapSetInfo> SelectedSet = new Bindable<BeatmapSetInfo>();
|
||||
|
||||
public new MarginPadding Padding
|
||||
{
|
||||
get => base.Padding;
|
||||
set => base.Padding = value;
|
||||
}
|
||||
|
||||
public void Filter(string searchTerm) => ((SearchContainer<RearrangeableListItem<BeatmapSetInfo>>)ListContainer).SearchTerm = searchTerm;
|
||||
|
||||
public BeatmapSetInfo FirstVisibleSet => Items.FirstOrDefault(i => ((PlaylistItem)ItemMap[i]).MatchingFilter);
|
||||
|
||||
protected override OsuRearrangeableListItem<BeatmapSetInfo> CreateOsuDrawable(BeatmapSetInfo item) => new PlaylistItem(item)
|
||||
{
|
||||
SelectedSet = { BindTarget = SelectedSet },
|
||||
RequestSelection = set => RequestSelection?.Invoke(set)
|
||||
};
|
||||
|
||||
protected override FillFlowContainer<RearrangeableListItem<BeatmapSetInfo>> CreateListFillFlowContainer() => new SearchContainer<RearrangeableListItem<BeatmapSetInfo>>
|
||||
{
|
||||
Spacing = new Vector2(0, 3),
|
||||
LayoutDuration = 200,
|
||||
LayoutEasing = Easing.OutQuint,
|
||||
};
|
||||
}
|
||||
}
|
@ -4,8 +4,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
@ -14,105 +14,74 @@ using osu.Framework.Localisation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Music
|
||||
{
|
||||
public class PlaylistItem : Container, IFilterable, IDraggable
|
||||
public class PlaylistItem : OsuRearrangeableListItem<BeatmapSetInfo>, IFilterable
|
||||
{
|
||||
private const float fade_duration = 100;
|
||||
public readonly Bindable<BeatmapSetInfo> SelectedSet = new Bindable<BeatmapSetInfo>();
|
||||
|
||||
private Color4 hoverColour;
|
||||
private Color4 artistColour;
|
||||
public Action<BeatmapSetInfo> RequestSelection;
|
||||
|
||||
private SpriteIcon handle;
|
||||
private TextFlowContainer text;
|
||||
private IEnumerable<Drawable> titleSprites;
|
||||
private ILocalisedBindableString titleBind;
|
||||
private ILocalisedBindableString artistBind;
|
||||
|
||||
public readonly BeatmapSetInfo BeatmapSetInfo;
|
||||
private ILocalisedBindableString title;
|
||||
private ILocalisedBindableString artist;
|
||||
|
||||
public Action<BeatmapSetInfo> OnSelect;
|
||||
private Color4 selectedColour;
|
||||
private Color4 artistColour;
|
||||
|
||||
public bool IsDraggable { get; private set; }
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e)
|
||||
public PlaylistItem(BeatmapSetInfo item)
|
||||
: base(item)
|
||||
{
|
||||
IsDraggable = handle.IsHovered;
|
||||
return base.OnMouseDown(e);
|
||||
}
|
||||
Padding = new MarginPadding { Left = 5 };
|
||||
|
||||
protected override void OnMouseUp(MouseUpEvent e)
|
||||
{
|
||||
IsDraggable = false;
|
||||
base.OnMouseUp(e);
|
||||
}
|
||||
|
||||
private bool selected;
|
||||
|
||||
public bool Selected
|
||||
{
|
||||
get => selected;
|
||||
set
|
||||
{
|
||||
if (value == selected) return;
|
||||
|
||||
selected = value;
|
||||
|
||||
FinishTransforms(true);
|
||||
foreach (Drawable s in titleSprites)
|
||||
s.FadeColour(Selected ? hoverColour : Color4.White, fade_duration);
|
||||
}
|
||||
}
|
||||
|
||||
public PlaylistItem(BeatmapSetInfo setInfo)
|
||||
{
|
||||
BeatmapSetInfo = setInfo;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Padding = new MarginPadding { Top = 3, Bottom = 3 };
|
||||
FilterTerms = item.Metadata.SearchableTerms;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, LocalisationManager localisation)
|
||||
{
|
||||
hoverColour = colours.Yellow;
|
||||
selectedColour = colours.Yellow;
|
||||
artistColour = colours.Gray9;
|
||||
HandleColour = colours.Gray5;
|
||||
|
||||
var metadata = BeatmapSetInfo.Metadata;
|
||||
FilterTerms = metadata.SearchableTerms;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
handle = new PlaylistItemHandle
|
||||
{
|
||||
Colour = colours.Gray5
|
||||
},
|
||||
text = new OsuTextFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding { Left = 20 },
|
||||
ContentIndent = 10f,
|
||||
},
|
||||
};
|
||||
|
||||
titleBind = localisation.GetLocalisedString(new LocalisedString((metadata.TitleUnicode, metadata.Title)));
|
||||
artistBind = localisation.GetLocalisedString(new LocalisedString((metadata.ArtistUnicode, metadata.Artist)));
|
||||
|
||||
artistBind.BindValueChanged(_ => recreateText(), true);
|
||||
title = localisation.GetLocalisedString(new LocalisedString((Model.Metadata.TitleUnicode, Model.Metadata.Title)));
|
||||
artist = localisation.GetLocalisedString(new LocalisedString((Model.Metadata.ArtistUnicode, Model.Metadata.Artist)));
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
artist.BindValueChanged(_ => recreateText(), true);
|
||||
|
||||
SelectedSet.BindValueChanged(set =>
|
||||
{
|
||||
if (set.OldValue?.Equals(Model) != true && set.NewValue?.Equals(Model) != true)
|
||||
return;
|
||||
|
||||
foreach (Drawable s in titleSprites)
|
||||
s.FadeColour(set.NewValue.Equals(Model) ? selectedColour : Color4.White, FADE_DURATION);
|
||||
}, true);
|
||||
}
|
||||
|
||||
protected override Drawable CreateContent() => text = new OsuTextFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
};
|
||||
|
||||
private void recreateText()
|
||||
{
|
||||
text.Clear();
|
||||
|
||||
//space after the title to put a space between the title and artist
|
||||
titleSprites = text.AddText(titleBind.Value + @" ", sprite => sprite.Font = OsuFont.GetFont(weight: FontWeight.Regular)).OfType<SpriteText>();
|
||||
titleSprites = text.AddText(title.Value + @" ", sprite => sprite.Font = OsuFont.GetFont(weight: FontWeight.Regular)).OfType<SpriteText>();
|
||||
|
||||
text.AddText(artistBind.Value, sprite =>
|
||||
text.AddText(artist.Value, sprite =>
|
||||
{
|
||||
sprite.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold);
|
||||
sprite.Colour = artistColour;
|
||||
@ -120,25 +89,13 @@ namespace osu.Game.Overlays.Music
|
||||
});
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
handle.FadeIn(fade_duration);
|
||||
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
handle.FadeOut(fade_duration);
|
||||
}
|
||||
|
||||
protected override bool OnClick(ClickEvent e)
|
||||
{
|
||||
OnSelect?.Invoke(BeatmapSetInfo);
|
||||
RequestSelection?.Invoke(Model);
|
||||
return true;
|
||||
}
|
||||
|
||||
public IEnumerable<string> FilterTerms { get; private set; }
|
||||
public IEnumerable<string> FilterTerms { get; }
|
||||
|
||||
private bool matching = true;
|
||||
|
||||
@ -156,28 +113,5 @@ namespace osu.Game.Overlays.Music
|
||||
}
|
||||
|
||||
public bool FilteringActive { get; set; }
|
||||
|
||||
private class PlaylistItemHandle : SpriteIcon
|
||||
{
|
||||
public PlaylistItemHandle()
|
||||
{
|
||||
Anchor = Anchor.CentreLeft;
|
||||
Origin = Anchor.CentreLeft;
|
||||
Size = new Vector2(12);
|
||||
Icon = FontAwesome.Solid.Bars;
|
||||
Alpha = 0f;
|
||||
Margin = new MarginPadding { Left = 5 };
|
||||
}
|
||||
|
||||
public override bool HandlePositionalInput => IsPresent;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IDraggable : IDrawable
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether this <see cref="IDraggable"/> can be dragged in its current state.
|
||||
/// </summary>
|
||||
bool IsDraggable { get; }
|
||||
}
|
||||
}
|
||||
|
@ -1,268 +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;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.Music
|
||||
{
|
||||
public class PlaylistList : CompositeDrawable
|
||||
{
|
||||
public Action<BeatmapSetInfo> Selected;
|
||||
|
||||
private readonly ItemsScrollContainer items;
|
||||
|
||||
public PlaylistList()
|
||||
{
|
||||
InternalChild = items = new ItemsScrollContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Selected = set => Selected?.Invoke(set),
|
||||
};
|
||||
}
|
||||
|
||||
public new MarginPadding Padding
|
||||
{
|
||||
get => base.Padding;
|
||||
set => base.Padding = value;
|
||||
}
|
||||
|
||||
public BeatmapSetInfo FirstVisibleSet => items.FirstVisibleSet;
|
||||
|
||||
public void Filter(string searchTerm) => items.SearchTerm = searchTerm;
|
||||
|
||||
private class ItemsScrollContainer : OsuScrollContainer
|
||||
{
|
||||
public Action<BeatmapSetInfo> Selected;
|
||||
|
||||
private readonly SearchContainer search;
|
||||
private readonly FillFlowContainer<PlaylistItem> items;
|
||||
|
||||
private readonly IBindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
|
||||
|
||||
private IBindableList<BeatmapSetInfo> beatmaps;
|
||||
|
||||
[Resolved]
|
||||
private MusicController musicController { get; set; }
|
||||
|
||||
public ItemsScrollContainer()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
search = new SearchContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
items = new ItemSearchContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IBindable<WorkingBeatmap> beatmap)
|
||||
{
|
||||
beatmaps = musicController.BeatmapSets.GetBoundCopy();
|
||||
beatmaps.ItemsAdded += i => i.ForEach(addBeatmapSet);
|
||||
beatmaps.ItemsRemoved += i => i.ForEach(removeBeatmapSet);
|
||||
beatmaps.ForEach(addBeatmapSet);
|
||||
|
||||
beatmapBacking.BindTo(beatmap);
|
||||
beatmapBacking.ValueChanged += _ => Scheduler.AddOnce(updateSelectedSet);
|
||||
}
|
||||
|
||||
private void addBeatmapSet(BeatmapSetInfo obj)
|
||||
{
|
||||
if (obj == draggedItem?.BeatmapSetInfo) return;
|
||||
|
||||
Schedule(() => items.Insert(items.Count - 1, new PlaylistItem(obj) { OnSelect = set => Selected?.Invoke(set) }));
|
||||
}
|
||||
|
||||
private void removeBeatmapSet(BeatmapSetInfo obj)
|
||||
{
|
||||
if (obj == draggedItem?.BeatmapSetInfo) return;
|
||||
|
||||
Schedule(() =>
|
||||
{
|
||||
var itemToRemove = items.FirstOrDefault(i => i.BeatmapSetInfo.ID == obj.ID);
|
||||
if (itemToRemove != null)
|
||||
items.Remove(itemToRemove);
|
||||
});
|
||||
}
|
||||
|
||||
private void updateSelectedSet()
|
||||
{
|
||||
foreach (PlaylistItem s in items.Children)
|
||||
{
|
||||
s.Selected = s.BeatmapSetInfo.ID == beatmapBacking.Value.BeatmapSetInfo?.ID;
|
||||
if (s.Selected)
|
||||
ScrollIntoView(s);
|
||||
}
|
||||
}
|
||||
|
||||
public string SearchTerm
|
||||
{
|
||||
get => search.SearchTerm;
|
||||
set => search.SearchTerm = value;
|
||||
}
|
||||
|
||||
public BeatmapSetInfo FirstVisibleSet => items.FirstOrDefault(i => i.MatchingFilter)?.BeatmapSetInfo;
|
||||
|
||||
private Vector2 nativeDragPosition;
|
||||
private PlaylistItem draggedItem;
|
||||
|
||||
private int? dragDestination;
|
||||
|
||||
protected override bool OnDragStart(DragStartEvent e)
|
||||
{
|
||||
nativeDragPosition = e.ScreenSpaceMousePosition;
|
||||
draggedItem = items.FirstOrDefault(d => d.IsDraggable);
|
||||
return draggedItem != null || base.OnDragStart(e);
|
||||
}
|
||||
|
||||
protected override void OnDrag(DragEvent e)
|
||||
{
|
||||
nativeDragPosition = e.ScreenSpaceMousePosition;
|
||||
|
||||
if (draggedItem == null)
|
||||
base.OnDrag(e);
|
||||
}
|
||||
|
||||
protected override void OnDragEnd(DragEndEvent e)
|
||||
{
|
||||
nativeDragPosition = e.ScreenSpaceMousePosition;
|
||||
|
||||
if (draggedItem == null)
|
||||
{
|
||||
base.OnDragEnd(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dragDestination != null)
|
||||
musicController.ChangeBeatmapSetPosition(draggedItem.BeatmapSetInfo, dragDestination.Value);
|
||||
|
||||
draggedItem = null;
|
||||
dragDestination = null;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (draggedItem == null)
|
||||
return;
|
||||
|
||||
updateScrollPosition();
|
||||
updateDragPosition();
|
||||
}
|
||||
|
||||
private void updateScrollPosition()
|
||||
{
|
||||
const float start_offset = 10;
|
||||
const double max_power = 50;
|
||||
const double exp_base = 1.05;
|
||||
|
||||
var localPos = ToLocalSpace(nativeDragPosition);
|
||||
|
||||
if (localPos.Y < start_offset)
|
||||
{
|
||||
if (Current <= 0)
|
||||
return;
|
||||
|
||||
var power = Math.Min(max_power, Math.Abs(start_offset - localPos.Y));
|
||||
ScrollBy(-(float)Math.Pow(exp_base, power));
|
||||
}
|
||||
else if (localPos.Y > DrawHeight - start_offset)
|
||||
{
|
||||
if (IsScrolledToEnd())
|
||||
return;
|
||||
|
||||
var power = Math.Min(max_power, Math.Abs(DrawHeight - start_offset - localPos.Y));
|
||||
ScrollBy((float)Math.Pow(exp_base, power));
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDragPosition()
|
||||
{
|
||||
var itemsPos = items.ToLocalSpace(nativeDragPosition);
|
||||
|
||||
int srcIndex = (int)items.GetLayoutPosition(draggedItem);
|
||||
|
||||
// Find the last item with position < mouse position. Note we can't directly use
|
||||
// the item positions as they are being transformed
|
||||
float heightAccumulator = 0;
|
||||
int dstIndex = 0;
|
||||
|
||||
for (; dstIndex < items.Count; dstIndex++)
|
||||
{
|
||||
// Using BoundingBox here takes care of scale, paddings, etc...
|
||||
heightAccumulator += items[dstIndex].BoundingBox.Height;
|
||||
if (heightAccumulator > itemsPos.Y)
|
||||
break;
|
||||
}
|
||||
|
||||
dstIndex = Math.Clamp(dstIndex, 0, items.Count - 1);
|
||||
|
||||
if (srcIndex == dstIndex)
|
||||
return;
|
||||
|
||||
if (srcIndex < dstIndex)
|
||||
{
|
||||
for (int i = srcIndex + 1; i <= dstIndex; i++)
|
||||
items.SetLayoutPosition(items[i], i - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = dstIndex; i < srcIndex; i++)
|
||||
items.SetLayoutPosition(items[i], i + 1);
|
||||
}
|
||||
|
||||
items.SetLayoutPosition(draggedItem, dstIndex);
|
||||
dragDestination = dstIndex;
|
||||
}
|
||||
|
||||
private class ItemSearchContainer : FillFlowContainer<PlaylistItem>, IHasFilterableChildren
|
||||
{
|
||||
public IEnumerable<string> FilterTerms => Array.Empty<string>();
|
||||
|
||||
public bool MatchingFilter
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
InvalidateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
public bool FilteringActive
|
||||
{
|
||||
set { }
|
||||
}
|
||||
|
||||
public IEnumerable<IFilterable> FilterableChildren => Children;
|
||||
|
||||
public ItemSearchContainer()
|
||||
{
|
||||
LayoutDuration = 200;
|
||||
LayoutEasing = Easing.OutQuint;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -21,17 +21,22 @@ namespace osu.Game.Overlays.Music
|
||||
private const float transition_duration = 600;
|
||||
private const float playlist_height = 510;
|
||||
|
||||
public IBindableList<BeatmapSetInfo> BeatmapSets => beatmapSets;
|
||||
|
||||
private readonly BindableList<BeatmapSetInfo> beatmapSets = new BindableList<BeatmapSetInfo>();
|
||||
|
||||
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
|
||||
private BeatmapManager beatmaps;
|
||||
|
||||
[Resolved]
|
||||
private BeatmapManager beatmaps { get; set; }
|
||||
|
||||
private FilterControl filter;
|
||||
private PlaylistList list;
|
||||
private Playlist list;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, Bindable<WorkingBeatmap> beatmap, BeatmapManager beatmaps)
|
||||
private void load(OsuColour colours, Bindable<WorkingBeatmap> beatmap)
|
||||
{
|
||||
this.beatmap.BindTo(beatmap);
|
||||
this.beatmaps = beatmaps;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@ -53,11 +58,11 @@ namespace osu.Game.Overlays.Music
|
||||
Colour = colours.Gray3,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
list = new PlaylistList
|
||||
list = new Playlist
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Top = 95, Bottom = 10, Right = 10 },
|
||||
Selected = itemSelected,
|
||||
RequestSelection = itemSelected
|
||||
},
|
||||
filter = new FilterControl
|
||||
{
|
||||
@ -82,6 +87,14 @@ namespace osu.Game.Overlays.Music
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
list.Items.BindTo(beatmapSets);
|
||||
beatmap.BindValueChanged(working => list.SelectedSet.Value = working.NewValue.BeatmapSetInfo, true);
|
||||
}
|
||||
|
||||
protected override void PopIn()
|
||||
{
|
||||
filter.Search.HoldFocus = true;
|
||||
|
@ -25,7 +25,16 @@ namespace osu.Game.Overlays
|
||||
[Resolved]
|
||||
private BeatmapManager beatmaps { get; set; }
|
||||
|
||||
public IBindableList<BeatmapSetInfo> BeatmapSets => beatmapSets;
|
||||
public IBindableList<BeatmapSetInfo> BeatmapSets
|
||||
{
|
||||
get
|
||||
{
|
||||
if (LoadState < LoadState.Ready)
|
||||
throw new InvalidOperationException($"{nameof(BeatmapSets)} should not be accessed before the music controller is loaded.");
|
||||
|
||||
return beatmapSets;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Point in time after which the current track will be restarted on triggering a "previous track" action.
|
||||
@ -54,16 +63,18 @@ namespace osu.Game.Overlays
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
beatmapSets.AddRange(beatmaps.GetAllUsableBeatmapSets().OrderBy(_ => RNG.Next()));
|
||||
beatmaps.ItemAdded += handleBeatmapAdded;
|
||||
beatmaps.ItemRemoved += handleBeatmapRemoved;
|
||||
|
||||
beatmapSets.AddRange(beatmaps.GetAllUsableBeatmapSets().OrderBy(_ => RNG.Next()));
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
beatmap.BindValueChanged(beatmapChanged, true);
|
||||
mods.BindValueChanged(_ => ResetTrackAdjustments(), true);
|
||||
base.LoadComplete();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -82,11 +93,16 @@ namespace osu.Game.Overlays
|
||||
/// </summary>
|
||||
public bool IsPlaying => current?.Track.IsRunning ?? false;
|
||||
|
||||
private void handleBeatmapAdded(BeatmapSetInfo set) =>
|
||||
Schedule(() => beatmapSets.Add(set));
|
||||
private void handleBeatmapAdded(BeatmapSetInfo set) => Schedule(() =>
|
||||
{
|
||||
if (!beatmapSets.Contains(set))
|
||||
beatmapSets.Add(set);
|
||||
});
|
||||
|
||||
private void handleBeatmapRemoved(BeatmapSetInfo set) =>
|
||||
Schedule(() => beatmapSets.RemoveAll(s => s.ID == set.ID));
|
||||
private void handleBeatmapRemoved(BeatmapSetInfo set) => Schedule(() =>
|
||||
{
|
||||
beatmapSets.RemoveAll(s => s.ID == set.ID);
|
||||
});
|
||||
|
||||
private ScheduledDelegate seekDelegate;
|
||||
|
||||
@ -196,7 +212,7 @@ namespace osu.Game.Overlays
|
||||
if (!instant)
|
||||
queuedDirection = TrackChangeDirection.Next;
|
||||
|
||||
var playable = BeatmapSets.SkipWhile(i => i.ID != current.BeatmapSetInfo.ID).Skip(1).FirstOrDefault() ?? BeatmapSets.FirstOrDefault();
|
||||
var playable = BeatmapSets.SkipWhile(i => i.ID != current.BeatmapSetInfo.ID).ElementAtOrDefault(1) ?? BeatmapSets.FirstOrDefault();
|
||||
|
||||
if (playable != null)
|
||||
{
|
||||
|
@ -75,7 +75,7 @@ namespace osu.Game.Overlays.News
|
||||
Left = 25,
|
||||
Bottom = 50,
|
||||
},
|
||||
Font = OsuFont.GetFont(Typeface.Exo, 24, FontWeight.Bold),
|
||||
Font = OsuFont.GetFont(Typeface.Torus, 24, FontWeight.Bold),
|
||||
Text = info.Title,
|
||||
},
|
||||
new OsuSpriteText
|
||||
@ -87,7 +87,7 @@ namespace osu.Game.Overlays.News
|
||||
Left = 25,
|
||||
Bottom = 30,
|
||||
},
|
||||
Font = OsuFont.GetFont(Typeface.Exo, 16, FontWeight.Bold),
|
||||
Font = OsuFont.GetFont(Typeface.Torus, 16, FontWeight.Bold),
|
||||
Text = "by " + info.Author
|
||||
}
|
||||
};
|
||||
@ -148,7 +148,7 @@ namespace osu.Game.Overlays.News
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Font = OsuFont.GetFont(Typeface.Exo, 12, FontWeight.Black, false, false),
|
||||
Font = OsuFont.GetFont(Typeface.Torus, 12, FontWeight.Bold, false, false),
|
||||
Text = date.ToString("d MMM yyy").ToUpper(),
|
||||
Margin = new MarginPadding
|
||||
{
|
||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Overlays.News
|
||||
|
||||
private NewsHeaderTitle title;
|
||||
|
||||
public readonly Bindable<string> Current = new Bindable<string>(null);
|
||||
public readonly Bindable<string> Post = new Bindable<string>(null);
|
||||
|
||||
public Action ShowFrontPage;
|
||||
|
||||
@ -22,13 +22,13 @@ namespace osu.Game.Overlays.News
|
||||
{
|
||||
TabControl.AddItem(front_page_string);
|
||||
|
||||
TabControl.Current.ValueChanged += e =>
|
||||
Current.ValueChanged += e =>
|
||||
{
|
||||
if (e.NewValue == front_page_string)
|
||||
ShowFrontPage?.Invoke();
|
||||
};
|
||||
|
||||
Current.ValueChanged += showPost;
|
||||
Post.ValueChanged += showPost;
|
||||
}
|
||||
|
||||
private void showPost(ValueChangedEvent<string> e)
|
||||
@ -39,13 +39,13 @@ namespace osu.Game.Overlays.News
|
||||
if (e.NewValue != null)
|
||||
{
|
||||
TabControl.AddItem(e.NewValue);
|
||||
TabControl.Current.Value = e.NewValue;
|
||||
Current.Value = e.NewValue;
|
||||
|
||||
title.IsReadingPost = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
TabControl.Current.Value = front_page_string;
|
||||
Current.Value = front_page_string;
|
||||
title.IsReadingPost = false;
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ namespace osu.Game.Overlays
|
||||
},
|
||||
};
|
||||
|
||||
header.Current.BindTo(Current);
|
||||
header.Post.BindTo(Current);
|
||||
Current.TriggerChange();
|
||||
}
|
||||
|
||||
|
@ -84,13 +84,13 @@ namespace osu.Game.Overlays.Notifications
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = titleText.ToUpperInvariant(),
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Black)
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold)
|
||||
},
|
||||
countDrawable = new OsuSpriteText
|
||||
{
|
||||
Text = "3",
|
||||
Colour = colours.Yellow,
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Black)
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold)
|
||||
},
|
||||
}
|
||||
},
|
||||
|
@ -58,6 +58,9 @@ namespace osu.Game.Overlays
|
||||
[Resolved]
|
||||
private Bindable<WorkingBeatmap> beatmap { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; }
|
||||
|
||||
public NowPlayingOverlay()
|
||||
{
|
||||
Width = 400;
|
||||
@ -65,7 +68,7 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@ -182,14 +185,15 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
playlist.State.ValueChanged += s => playlistButton.FadeColour(s.NewValue == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
playlist.BeatmapSets.BindTo(musicController.BeatmapSets);
|
||||
playlist.State.BindValueChanged(s => playlistButton.FadeColour(s.NewValue == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint), true);
|
||||
|
||||
beatmap.BindDisabledChanged(beatmapDisabledChanged, true);
|
||||
|
||||
musicController.TrackChanged += trackChanged;
|
||||
|
@ -53,7 +53,7 @@ namespace osu.Game.Overlays.OSD
|
||||
{
|
||||
Padding = new MarginPadding(10),
|
||||
Name = "Description",
|
||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Black),
|
||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold),
|
||||
Spacing = new Vector2(1, 0),
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
|
@ -50,14 +50,29 @@ namespace osu.Game.Overlays
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Gray,
|
||||
},
|
||||
title = CreateTitle().With(title =>
|
||||
new Container
|
||||
{
|
||||
title.Margin = new MarginPadding
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Horizontal = UserProfileOverlay.CONTENT_X_MARGIN,
|
||||
Vertical = 10,
|
||||
Left = UserProfileOverlay.CONTENT_X_MARGIN
|
||||
};
|
||||
})
|
||||
},
|
||||
Children = new[]
|
||||
{
|
||||
title = CreateTitle().With(title =>
|
||||
{
|
||||
title.Anchor = Anchor.CentreLeft;
|
||||
title.Origin = Anchor.CentreLeft;
|
||||
}),
|
||||
CreateTitleContent().With(content =>
|
||||
{
|
||||
content.Anchor = Anchor.CentreRight;
|
||||
content.Origin = Anchor.CentreRight;
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -75,10 +90,16 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
protected virtual Drawable CreateContent() => Drawable.Empty();
|
||||
protected virtual Drawable CreateContent() => Empty();
|
||||
|
||||
[NotNull]
|
||||
protected virtual Drawable CreateBackground() => Drawable.Empty();
|
||||
protected virtual Drawable CreateBackground() => Empty();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="Drawable"/> on the opposite side of the <see cref="ScreenTitle"/>. Used mostly to create <see cref="OverlayRulesetSelector"/>.
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
protected virtual Drawable CreateTitleContent() => Empty();
|
||||
|
||||
protected abstract ScreenTitle CreateTitle();
|
||||
}
|
||||
|
101
osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs
Normal file
101
osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs
Normal file
@ -0,0 +1,101 @@
|
||||
// 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.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osuTK;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Framework.Allocation;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
public class OverlayPanelDisplayStyleControl : OsuTabControl<OverlayPanelDisplayStyle>
|
||||
{
|
||||
protected override Dropdown<OverlayPanelDisplayStyle> CreateDropdown() => null;
|
||||
|
||||
protected override TabItem<OverlayPanelDisplayStyle> CreateTabItem(OverlayPanelDisplayStyle value) => new PanelDisplayTabItem(value);
|
||||
|
||||
protected override bool AddEnumEntriesAutomatically => false;
|
||||
|
||||
public OverlayPanelDisplayStyleControl()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
AddTabItem(new PanelDisplayTabItem(OverlayPanelDisplayStyle.Card)
|
||||
{
|
||||
Icon = FontAwesome.Solid.Square
|
||||
});
|
||||
AddTabItem(new PanelDisplayTabItem(OverlayPanelDisplayStyle.List)
|
||||
{
|
||||
Icon = FontAwesome.Solid.Bars
|
||||
});
|
||||
}
|
||||
|
||||
protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal
|
||||
};
|
||||
|
||||
private class PanelDisplayTabItem : TabItem<OverlayPanelDisplayStyle>, IHasTooltip
|
||||
{
|
||||
public IconUsage Icon
|
||||
{
|
||||
set => icon.Icon = value;
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; }
|
||||
|
||||
public string TooltipText => $@"{Value} view";
|
||||
|
||||
private readonly SpriteIcon icon;
|
||||
|
||||
public PanelDisplayTabItem(OverlayPanelDisplayStyle value)
|
||||
: base(value)
|
||||
{
|
||||
Size = new Vector2(11);
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
icon = new SpriteIcon
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fit
|
||||
},
|
||||
new HoverClickSounds()
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnActivated() => updateState();
|
||||
|
||||
protected override void OnDeactivated() => updateState();
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
updateState();
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
updateState();
|
||||
base.OnHoverLost(e);
|
||||
}
|
||||
|
||||
private void updateState() => icon.Colour = Active.Value || IsHovered ? colourProvider.Light1 : Color4.White;
|
||||
}
|
||||
}
|
||||
|
||||
public enum OverlayPanelDisplayStyle
|
||||
{
|
||||
Card,
|
||||
List
|
||||
}
|
||||
}
|
28
osu.Game/Overlays/OverlayRulesetSelector.cs
Normal file
28
osu.Game/Overlays/OverlayRulesetSelector.cs
Normal file
@ -0,0 +1,28 @@
|
||||
// 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.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
public class OverlayRulesetSelector : RulesetSelector
|
||||
{
|
||||
public OverlayRulesetSelector()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
protected override TabItem<RulesetInfo> CreateTabItem(RulesetInfo value) => new OverlayRulesetTabItem(value);
|
||||
|
||||
protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(25, 0),
|
||||
};
|
||||
}
|
||||
}
|
97
osu.Game/Overlays/OverlayRulesetTabItem.cs
Normal file
97
osu.Game/Overlays/OverlayRulesetTabItem.cs
Normal file
@ -0,0 +1,97 @@
|
||||
// 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.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK.Graphics;
|
||||
using osuTK;
|
||||
using osu.Framework.Allocation;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
public class OverlayRulesetTabItem : TabItem<RulesetInfo>
|
||||
{
|
||||
private Color4 accentColour;
|
||||
|
||||
protected virtual Color4 AccentColour
|
||||
{
|
||||
get => accentColour;
|
||||
set
|
||||
{
|
||||
accentColour = value;
|
||||
text.FadeColour(value, 120, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
|
||||
protected override Container<Drawable> Content { get; }
|
||||
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; }
|
||||
|
||||
private readonly OsuSpriteText text;
|
||||
|
||||
public OverlayRulesetTabItem(RulesetInfo value)
|
||||
: base(value)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
Content = new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(3, 0),
|
||||
Child = text = new OsuSpriteText
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Text = value.Name,
|
||||
}
|
||||
},
|
||||
new HoverClickSounds()
|
||||
});
|
||||
|
||||
Enabled.Value = true;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
Enabled.BindValueChanged(_ => updateState(), true);
|
||||
}
|
||||
|
||||
public override bool PropagatePositionalInputSubTree => Enabled.Value && !Active.Value && base.PropagatePositionalInputSubTree;
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
base.OnHover(e);
|
||||
updateState();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
base.OnHoverLost(e);
|
||||
updateState();
|
||||
}
|
||||
|
||||
protected override void OnActivated() => updateState();
|
||||
|
||||
protected override void OnDeactivated() => updateState();
|
||||
|
||||
private void updateState()
|
||||
{
|
||||
text.Font = text.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Medium);
|
||||
AccentColour = Enabled.Value ? getActiveColour() : colourProvider.Foreground1;
|
||||
}
|
||||
|
||||
private Color4 getActiveColour() => IsHovered || Active.Value ? Color4.White : colourProvider.Highlight1;
|
||||
}
|
||||
}
|
170
osu.Game/Overlays/OverlaySortTabControl.cs
Normal file
170
osu.Game/Overlays/OverlaySortTabControl.cs
Normal file
@ -0,0 +1,170 @@
|
||||
// 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.Graphics.Containers;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics;
|
||||
using osuTK;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osuTK.Graphics;
|
||||
using osu.Game.Overlays.Comments;
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
using osu.Framework.Extensions;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
public class OverlaySortTabControl<T> : CompositeDrawable, IHasCurrentValue<T>
|
||||
{
|
||||
private readonly BindableWithCurrent<T> current = new BindableWithCurrent<T>();
|
||||
|
||||
public Bindable<T> Current
|
||||
{
|
||||
get => current.Current;
|
||||
set => current.Current = value;
|
||||
}
|
||||
|
||||
public OverlaySortTabControl()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
AddInternal(new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(10, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Font = OsuFont.GetFont(size: 12),
|
||||
Text = @"Sort by"
|
||||
},
|
||||
CreateControl().With(c =>
|
||||
{
|
||||
c.Anchor = Anchor.CentreLeft;
|
||||
c.Origin = Anchor.CentreLeft;
|
||||
c.Current = current;
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
protected virtual SortTabControl CreateControl() => new SortTabControl();
|
||||
|
||||
protected class SortTabControl : OsuTabControl<T>
|
||||
{
|
||||
protected override Dropdown<T> CreateDropdown() => null;
|
||||
|
||||
protected override TabItem<T> CreateTabItem(T value) => new SortTabItem(value);
|
||||
|
||||
protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(5, 0),
|
||||
};
|
||||
|
||||
public SortTabControl()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
}
|
||||
}
|
||||
|
||||
protected class SortTabItem : TabItem<T>
|
||||
{
|
||||
public SortTabItem(T value)
|
||||
: base(value)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Child = CreateTabButton(value);
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
protected virtual TabButton CreateTabButton(T value) => new TabButton(value)
|
||||
{
|
||||
Active = { BindTarget = Active }
|
||||
};
|
||||
|
||||
protected override void OnActivated()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnDeactivated()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
protected class TabButton : HeaderButton
|
||||
{
|
||||
public readonly BindableBool Active = new BindableBool();
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
protected virtual Color4 ContentColour
|
||||
{
|
||||
set => text.Colour = value;
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; }
|
||||
|
||||
private readonly SpriteText text;
|
||||
private readonly FillFlowContainer content;
|
||||
|
||||
public TabButton(T value)
|
||||
{
|
||||
base.Content.Add(content = new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(3, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
text = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Font = OsuFont.GetFont(size: 12),
|
||||
Text = (value as Enum)?.GetDescription() ?? value.ToString()
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
Active.BindValueChanged(_ => UpdateState(), true);
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
UpdateState();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e) => UpdateState();
|
||||
|
||||
protected virtual void UpdateState()
|
||||
{
|
||||
if (Active.Value || IsHovered)
|
||||
ShowBackground();
|
||||
else
|
||||
HideBackground();
|
||||
|
||||
ContentColour = Active.Value && !IsHovered ? colourProvider.Light1 : Color4.White;
|
||||
|
||||
text.Font = text.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Medium);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
56
osu.Game/Overlays/OverlayStreamControl.cs
Normal file
56
osu.Game/Overlays/OverlayStreamControl.cs
Normal file
@ -0,0 +1,56 @@
|
||||
// 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.Graphics;
|
||||
using osu.Framework.Input.Events;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
public abstract class OverlayStreamControl<T> : TabControl<T>
|
||||
{
|
||||
protected OverlayStreamControl()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
}
|
||||
|
||||
public void Populate(List<T> streams) => streams.ForEach(AddItem);
|
||||
|
||||
protected override Dropdown<T> CreateDropdown() => null;
|
||||
|
||||
protected override TabItem<T> CreateTabItem(T value) => CreateStreamItem(value).With(item =>
|
||||
{
|
||||
item.SelectedItem.BindTo(Current);
|
||||
});
|
||||
|
||||
[NotNull]
|
||||
protected abstract OverlayStreamItem<T> CreateStreamItem(T value);
|
||||
|
||||
protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
AllowMultiline = true,
|
||||
};
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
foreach (var streamBadge in TabContainer.Children.OfType<OverlayStreamItem<T>>())
|
||||
streamBadge.UserHoveringArea = true;
|
||||
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
foreach (var streamBadge in TabContainer.Children.OfType<OverlayStreamItem<T>>())
|
||||
streamBadge.UserHoveringArea = false;
|
||||
|
||||
base.OnHoverLost(e);
|
||||
}
|
||||
}
|
||||
}
|
140
osu.Game/Overlays/OverlayStreamItem.cs
Normal file
140
osu.Game/Overlays/OverlayStreamItem.cs
Normal file
@ -0,0 +1,140 @@
|
||||
// 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.Graphics;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
public abstract class OverlayStreamItem<T> : TabItem<T>
|
||||
{
|
||||
public readonly Bindable<T> SelectedItem = new Bindable<T>();
|
||||
|
||||
private bool userHoveringArea;
|
||||
|
||||
public bool UserHoveringArea
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value == userHoveringArea)
|
||||
return;
|
||||
|
||||
userHoveringArea = value;
|
||||
updateState();
|
||||
}
|
||||
}
|
||||
|
||||
private FillFlowContainer<SpriteText> text;
|
||||
private ExpandingBar expandingBar;
|
||||
|
||||
protected OverlayStreamItem(T value)
|
||||
: base(value)
|
||||
{
|
||||
Height = 60;
|
||||
Width = 100;
|
||||
Padding = new MarginPadding(5);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider, OsuColour colours)
|
||||
{
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
text = new FillFlowContainer<SpriteText>
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Margin = new MarginPadding { Top = 6 },
|
||||
Children = new[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = MainText,
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = AdditionalText,
|
||||
Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular),
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = InfoText,
|
||||
Font = OsuFont.GetFont(size: 10),
|
||||
Colour = colourProvider.Foreground1
|
||||
},
|
||||
}
|
||||
},
|
||||
expandingBar = new ExpandingBar
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Colour = GetBarColour(colours),
|
||||
ExpandedSize = 4,
|
||||
CollapsedSize = 2,
|
||||
Expanded = true
|
||||
},
|
||||
new HoverClickSounds()
|
||||
});
|
||||
|
||||
SelectedItem.BindValueChanged(_ => updateState(), true);
|
||||
}
|
||||
|
||||
protected abstract string MainText { get; }
|
||||
|
||||
protected abstract string AdditionalText { get; }
|
||||
|
||||
protected virtual string InfoText => string.Empty;
|
||||
|
||||
protected abstract Color4 GetBarColour(OsuColour colours);
|
||||
|
||||
protected override void OnActivated() => updateState();
|
||||
|
||||
protected override void OnDeactivated() => updateState();
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
updateState();
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
updateState();
|
||||
base.OnHoverLost(e);
|
||||
}
|
||||
|
||||
private void updateState()
|
||||
{
|
||||
// highlighted regardless if we are hovered
|
||||
bool textHighlighted = IsHovered;
|
||||
bool barExpanded = IsHovered;
|
||||
|
||||
if (SelectedItem.Value == null)
|
||||
{
|
||||
// at listing, all badges are highlighted when user is not hovering any badge.
|
||||
textHighlighted |= !userHoveringArea;
|
||||
barExpanded |= !userHoveringArea;
|
||||
}
|
||||
else
|
||||
{
|
||||
// bar is always expanded when active
|
||||
barExpanded |= Active.Value;
|
||||
|
||||
// text is highlighted only when hovered or active (but not if in selection mode)
|
||||
textHighlighted |= Active.Value && !userHoveringArea;
|
||||
}
|
||||
|
||||
expandingBar.Expanded = barExpanded;
|
||||
text.FadeTo(textHighlighted ? 1 : 0.5f, 100, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
@ -33,16 +33,16 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
iconColour = colours.GreySeafoamLighter;
|
||||
iconColour = colourProvider.Foreground1;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colours.GreySeafoamDark,
|
||||
Colour = colourProvider.Background4
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
@ -82,7 +82,7 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
else
|
||||
{
|
||||
topLinkContainer.AddText("Joined ");
|
||||
topLinkContainer.AddText(new DrawableDate(user.JoinDate), embolden);
|
||||
topLinkContainer.AddText(new DrawableDate(user.JoinDate, italic: false), embolden);
|
||||
}
|
||||
|
||||
addSpacer(topLinkContainer);
|
||||
@ -95,7 +95,7 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
else if (user.LastVisit.HasValue)
|
||||
{
|
||||
topLinkContainer.AddText("Last seen ");
|
||||
topLinkContainer.AddText(new DrawableDate(user.LastVisit.Value), embolden);
|
||||
topLinkContainer.AddText(new DrawableDate(user.LastVisit.Value, italic: false), embolden);
|
||||
|
||||
addSpacer(topLinkContainer);
|
||||
}
|
||||
@ -111,34 +111,42 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
topLinkContainer.AddText("Contributed ");
|
||||
topLinkContainer.AddLink($@"{user.PostCount:#,##0} forum posts", $"https://osu.ppy.sh/users/{user.Id}/posts", creationParameters: embolden);
|
||||
|
||||
string websiteWithoutProtcol = user.Website;
|
||||
string websiteWithoutProtocol = user.Website;
|
||||
|
||||
if (!string.IsNullOrEmpty(websiteWithoutProtcol))
|
||||
if (!string.IsNullOrEmpty(websiteWithoutProtocol))
|
||||
{
|
||||
if (Uri.TryCreate(websiteWithoutProtcol, UriKind.Absolute, out var uri))
|
||||
if (Uri.TryCreate(websiteWithoutProtocol, UriKind.Absolute, out var uri))
|
||||
{
|
||||
websiteWithoutProtcol = uri.Host + uri.PathAndQuery + uri.Fragment;
|
||||
websiteWithoutProtcol = websiteWithoutProtcol.TrimEnd('/');
|
||||
websiteWithoutProtocol = uri.Host + uri.PathAndQuery + uri.Fragment;
|
||||
websiteWithoutProtocol = websiteWithoutProtocol.TrimEnd('/');
|
||||
}
|
||||
}
|
||||
|
||||
tryAddInfo(FontAwesome.Solid.MapMarker, user.Location);
|
||||
tryAddInfo(OsuIcon.Heart, user.Interests);
|
||||
tryAddInfo(FontAwesome.Solid.Suitcase, user.Occupation);
|
||||
bottomLinkContainer.NewLine();
|
||||
bool anyInfoAdded = false;
|
||||
|
||||
anyInfoAdded |= tryAddInfo(FontAwesome.Solid.MapMarker, user.Location);
|
||||
anyInfoAdded |= tryAddInfo(OsuIcon.Heart, user.Interests);
|
||||
anyInfoAdded |= tryAddInfo(FontAwesome.Solid.Suitcase, user.Occupation);
|
||||
|
||||
if (anyInfoAdded)
|
||||
bottomLinkContainer.NewLine();
|
||||
|
||||
if (!string.IsNullOrEmpty(user.Twitter))
|
||||
tryAddInfo(FontAwesome.Brands.Twitter, "@" + user.Twitter, $@"https://twitter.com/{user.Twitter}");
|
||||
tryAddInfo(FontAwesome.Brands.Discord, user.Discord);
|
||||
tryAddInfo(FontAwesome.Brands.Skype, user.Skype, @"skype:" + user.Skype + @"?chat");
|
||||
tryAddInfo(FontAwesome.Brands.Lastfm, user.Lastfm, $@"https://last.fm/users/{user.Lastfm}");
|
||||
tryAddInfo(FontAwesome.Solid.Link, websiteWithoutProtcol, user.Website);
|
||||
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Twitter, "@" + user.Twitter, $@"https://twitter.com/{user.Twitter}");
|
||||
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Discord, user.Discord);
|
||||
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Skype, user.Skype, @"skype:" + user.Skype + @"?chat");
|
||||
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Lastfm, user.Lastfm, $@"https://last.fm/users/{user.Lastfm}");
|
||||
anyInfoAdded |= tryAddInfo(FontAwesome.Solid.Link, websiteWithoutProtocol, user.Website);
|
||||
|
||||
// If no information was added to the bottomLinkContainer, hide it to avoid unwanted padding
|
||||
bottomLinkContainer.Alpha = anyInfoAdded ? 1 : 0;
|
||||
}
|
||||
|
||||
private void addSpacer(OsuTextFlowContainer textFlow) => textFlow.AddArbitraryDrawable(new Container { Width = 15 });
|
||||
|
||||
private void tryAddInfo(IconUsage icon, string content, string link = null)
|
||||
private bool tryAddInfo(IconUsage icon, string content, string link = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(content)) return;
|
||||
if (string.IsNullOrEmpty(content)) return false;
|
||||
|
||||
// newlines could be contained in API returned user content.
|
||||
content = content.Replace("\n", " ");
|
||||
@ -155,6 +163,7 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
bottomLinkContainer.AddText(" " + content, embolden);
|
||||
|
||||
addSpacer(bottomLinkContainer);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void embolden(SpriteText text) => text.Font = text.Font.With(weight: FontWeight.Bold);
|
||||
|
@ -7,7 +7,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Overlays.Profile.Header.Components;
|
||||
using osu.Game.Users;
|
||||
using osuTK;
|
||||
@ -28,7 +27,7 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, TextureStore textures)
|
||||
private void load(OverlayColourProvider colourProvider, TextureStore textures)
|
||||
{
|
||||
Container<Drawable> hiddenDetailContainer;
|
||||
Container<Drawable> expandedDetailContainer;
|
||||
@ -38,7 +37,7 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colours.GreySeafoam
|
||||
Colour = colourProvider.Background4
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
@ -119,12 +118,12 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
hiddenDetailGlobal = new OverlinedInfoContainer
|
||||
{
|
||||
Title = "Global Ranking",
|
||||
LineColour = colours.Yellow
|
||||
LineColour = colourProvider.Highlight1
|
||||
},
|
||||
hiddenDetailCountry = new OverlinedInfoContainer
|
||||
{
|
||||
Title = "Country Ranking",
|
||||
LineColour = colours.Yellow
|
||||
LineColour = colourProvider.Highlight1
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Header.Components
|
||||
@ -25,10 +24,10 @@ namespace osu.Game.Overlays.Profile.Header.Components
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
IdleColour = colours.GreySeafoamLight;
|
||||
HoverColour = colours.GreySeafoamLight.Darken(0.2f);
|
||||
IdleColour = colourProvider.Background2;
|
||||
HoverColour = colourProvider.Background2.Lighten(0.2f);
|
||||
|
||||
Child = icon = new SpriteIcon
|
||||
{
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user