mirror of
https://github.com/osukey/osukey.git
synced 2025-08-05 07:33:55 +09:00
Merge branch 'master' into history-graph
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 };
|
||||
@ -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)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
TooltipText = name;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Height = 24f;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@ -113,7 +113,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,7 +122,7 @@ 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"),
|
||||
},
|
||||
@ -130,7 +131,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.Centre,
|
||||
Icon = icon,
|
||||
Size = new Vector2(13),
|
||||
Size = new Vector2(12),
|
||||
Colour = OsuColour.FromHex(@"f7dd55"),
|
||||
Scale = new Vector2(0.8f),
|
||||
},
|
||||
@ -139,7 +140,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),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
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);
|
||||
|
||||
|
@ -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 = getVideoSuffixText(),
|
||||
Font = OsuFont.GetFont(size: 11, weight: FontWeight.Bold)
|
||||
Font = OsuFont.GetFont(size: text_size - 2, weight: FontWeight.Bold)
|
||||
},
|
||||
};
|
||||
this.FadeIn(200);
|
||||
|
@ -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
|
||||
|
@ -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.Linq;
|
||||
@ -45,7 +45,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
|
||||
private readonly FavouriteButton favouriteButton;
|
||||
private readonly FillFlowContainer fadeContent;
|
||||
private readonly LoadingAnimation loading;
|
||||
private readonly LoadingSpinner loading;
|
||||
private readonly BeatmapSetHeader beatmapSetHeader;
|
||||
|
||||
[Cached(typeof(IBindable<RulesetInfo>))]
|
||||
@ -144,12 +144,15 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
},
|
||||
}
|
||||
},
|
||||
artist = new OsuSpriteText { Font = OsuFont.GetFont(size: 20, weight: FontWeight.Medium, italics: true) },
|
||||
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,
|
||||
Margin = new MarginPadding { Top = 20 },
|
||||
Child = author = new AuthorInfo(),
|
||||
},
|
||||
beatmapAvailability = new BeatmapAvailability(),
|
||||
@ -176,7 +179,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
},
|
||||
}
|
||||
},
|
||||
loading = new LoadingAnimation
|
||||
loading = new LoadingSpinner
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
|
@ -3,25 +3,23 @@
|
||||
|
||||
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.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
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;
|
||||
@ -41,15 +39,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
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[]
|
||||
{
|
||||
@ -135,6 +125,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
var setHasLeaderboard = b.NewValue?.OnlineInfo?.Status > 0;
|
||||
successRate.Alpha = setHasLeaderboard ? 1 : 0;
|
||||
unrankedPlaceholder.Alpha = setHasLeaderboard ? 0 : 1;
|
||||
Height = setHasLeaderboard ? 270 : base_height;
|
||||
};
|
||||
}
|
||||
|
||||
@ -176,8 +167,8 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = title,
|
||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Black),
|
||||
Margin = new MarginPadding { Top = 20 },
|
||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold),
|
||||
Margin = new MarginPadding { Top = 15 },
|
||||
},
|
||||
textFlow = new OsuTextFlowContainer
|
||||
{
|
||||
|
@ -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;
|
||||
@ -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)
|
||||
|
@ -17,13 +17,13 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
{
|
||||
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 = 5;
|
||||
CornerRadius = 4;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
@ -46,7 +46,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
{
|
||||
Vertical = 10,
|
||||
Left = 10,
|
||||
Right = 25,
|
||||
Right = 30,
|
||||
},
|
||||
Children = new Drawable[]
|
||||
{
|
||||
|
@ -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,7 +22,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
public class ScoreTable : TableContainer
|
||||
{
|
||||
private const float horizontal_inset = 20;
|
||||
private const float row_height = 25;
|
||||
private const float row_height = 22;
|
||||
private const int text_size = 12;
|
||||
|
||||
private readonly FillFlowContainer backgroundFlow;
|
||||
@ -63,7 +63,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
return;
|
||||
|
||||
for (int i = 0; i < value.Count; i++)
|
||||
backgroundFlow.Add(new ScoreTableRowBackground(i, value[i]));
|
||||
backgroundFlow.Add(new ScoreTableRowBackground(i, value[i], row_height));
|
||||
|
||||
Columns = createHeaders(value[0]);
|
||||
Content = value.Select((s, i) => createContent(i, s)).ToArray().ToRectangular();
|
||||
@ -77,17 +77,20 @@ 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.Distributed, minSize: 60, maxSize: 70)),
|
||||
new TableColumn("player", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 150)),
|
||||
new TableColumn("max combo", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 70, maxSize: 110))
|
||||
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.SortedStatistics)
|
||||
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.Add(new TableColumn(score.SortedStatistics.LastOrDefault().Key.GetDescription(), Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 45, maxSize: 95)));
|
||||
|
||||
columns.AddRange(new[]
|
||||
{
|
||||
new TableColumn("pp", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 40, maxSize: 70)),
|
||||
new TableColumn("pp", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 30)),
|
||||
new TableColumn("mods", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)),
|
||||
});
|
||||
|
||||
@ -96,6 +99,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
|
||||
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 +111,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
},
|
||||
new UpdateableRank(score.Rank)
|
||||
{
|
||||
Size = new Vector2(30, 20)
|
||||
Size = new Vector2(28, 14)
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
@ -120,35 +126,19 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
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.SortedStatistics)
|
||||
{
|
||||
|
@ -22,13 +22,13 @@ 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 = 5;
|
||||
Masking = true;
|
||||
|
@ -5,7 +5,6 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK;
|
||||
using System.Linq;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
@ -13,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;
|
||||
|
||||
@ -31,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]
|
||||
@ -76,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
|
||||
@ -121,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
|
||||
@ -160,21 +157,12 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
}
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
CornerRadius = 5,
|
||||
Child = loading = new DimmedLoadingLayer(iconScale: 0.8f)
|
||||
{
|
||||
Alpha = 0,
|
||||
},
|
||||
}
|
||||
loading = new LoadingLayer()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -191,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);
|
||||
@ -233,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;
|
||||
}
|
||||
|
||||
@ -247,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);
|
||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
private const float bottom_columns_min_width = 45;
|
||||
|
||||
private readonly FontUsage smallFont = OsuFont.GetFont(size: 16);
|
||||
private readonly FontUsage largeFont = OsuFont.GetFont(size: 22);
|
||||
private readonly FontUsage largeFont = OsuFont.GetFont(size: 22, weight: FontWeight.Light);
|
||||
|
||||
private readonly TextColumn totalScoreColumn;
|
||||
private readonly TextColumn accuracyColumn;
|
||||
@ -47,7 +47,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(10, 8),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
@ -117,6 +116,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
public InfoColumn(string title, Drawable content, float? minWidth = null)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Margin = new MarginPadding { Vertical = 5 };
|
||||
|
||||
InternalChild = new GridContainer
|
||||
{
|
||||
@ -128,7 +128,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
RowDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension(GridSizeMode.Absolute, 4),
|
||||
new Dimension(GridSizeMode.Absolute, 2),
|
||||
new Dimension(GridSizeMode.AutoSize)
|
||||
},
|
||||
Content = new[]
|
||||
@ -138,21 +138,24 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
text = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold),
|
||||
Text = title.ToUpper()
|
||||
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 }
|
||||
}
|
||||
},
|
||||
new Drawable[]
|
||||
{
|
||||
separator = new Box
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Anchor = Anchor.TopLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 2
|
||||
}
|
||||
Height = 2,
|
||||
},
|
||||
},
|
||||
new[]
|
||||
{
|
||||
content
|
||||
// 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 })
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -194,9 +197,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
|
||||
})
|
||||
{
|
||||
}
|
||||
|
@ -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;
|
||||
@ -12,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;
|
||||
|
||||
@ -24,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()
|
||||
@ -67,7 +67,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(70),
|
||||
Masking = true,
|
||||
CornerRadius = 5,
|
||||
CornerRadius = 4,
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
@ -92,11 +92,24 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
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: 10)
|
||||
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
|
||||
{
|
||||
@ -112,9 +125,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
};
|
||||
}
|
||||
|
||||
public int ScorePosition
|
||||
public int? ScorePosition
|
||||
{
|
||||
set => rankText.Text = $"#{value}";
|
||||
set => rankText.Text = value == null ? "-" : $"#{value}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -126,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);
|
||||
|
@ -65,7 +65,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Text = "Success Rate",
|
||||
Font = OsuFont.GetFont(size: 13)
|
||||
Font = OsuFont.GetFont(size: 12)
|
||||
},
|
||||
successRate = new Bar
|
||||
{
|
||||
@ -82,7 +82,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopCentre,
|
||||
Font = OsuFont.GetFont(size: 13),
|
||||
Font = OsuFont.GetFont(size: 12),
|
||||
},
|
||||
},
|
||||
new OsuSpriteText
|
||||
@ -90,7 +90,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
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 },
|
||||
},
|
||||
},
|
||||
|
@ -13,6 +13,7 @@ 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;
|
||||
|
||||
@ -25,7 +26,8 @@ namespace osu.Game.Overlays
|
||||
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>();
|
||||
|
||||
@ -39,6 +41,7 @@ namespace osu.Game.Overlays
|
||||
{
|
||||
OsuScrollContainer scroll;
|
||||
Info info;
|
||||
CommentsSection comments;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@ -50,29 +53,33 @@ namespace osu.Game.Overlays
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
ScrollbarVisible = false,
|
||||
Child = new ReverseChildIDFillFlowContainer<Drawable>
|
||||
Child = new ReverseChildIDFillFlowContainer<BeatmapSetLayoutSection>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 20),
|
||||
Children = new Drawable[]
|
||||
Children = new[]
|
||||
{
|
||||
new ReverseChildIDFillFlowContainer<Drawable>
|
||||
new BeatmapSetLayoutSection
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
Child = new ReverseChildIDFillFlowContainer<Drawable>
|
||||
{
|
||||
Header = new Header(),
|
||||
info = new Info()
|
||||
}
|
||||
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()
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -80,6 +87,7 @@ namespace osu.Game.Overlays
|
||||
|
||||
Header.BeatmapSet.BindTo(beatmapSet);
|
||||
info.BeatmapSet.BindTo(beatmapSet);
|
||||
comments.BeatmapSet.BindTo(beatmapSet);
|
||||
|
||||
Header.Picker.Beatmap.ValueChanged += b =>
|
||||
{
|
||||
@ -90,10 +98,8 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetStore rulesets)
|
||||
private void load()
|
||||
{
|
||||
this.rulesets = rulesets;
|
||||
|
||||
background.Colour = ColourProvider.Background6;
|
||||
}
|
||||
|
||||
@ -144,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
|
||||
@ -123,10 +123,11 @@ namespace osu.Game.Overlays.Changelog
|
||||
});
|
||||
}
|
||||
|
||||
title.AddText(" by ", t =>
|
||||
title.AddText("by ", t =>
|
||||
{
|
||||
t.Font = fontMedium;
|
||||
t.Font = fontMedium.With(italics: true);
|
||||
t.Colour = entryColour;
|
||||
t.Padding = new MarginPadding { Left = 10 };
|
||||
});
|
||||
|
||||
if (entry.GithubUser.UserId != null)
|
||||
@ -137,7 +138,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
Id = entry.GithubUser.UserId.Value
|
||||
}, t =>
|
||||
{
|
||||
t.Font = fontMedium;
|
||||
t.Font = fontMedium.With(italics: true);
|
||||
t.Colour = entryColour;
|
||||
});
|
||||
}
|
||||
@ -145,7 +146,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
title.AddLink(entry.GithubUser.DisplayName, entry.GithubUser.GithubUrl, t =>
|
||||
{
|
||||
t.Font = fontMedium;
|
||||
t.Font = fontMedium.With(italics: true);
|
||||
t.Colour = entryColour;
|
||||
});
|
||||
}
|
||||
@ -153,7 +154,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
title.AddText(entry.GithubUser.DisplayName, t =>
|
||||
{
|
||||
t.Font = fontSmall;
|
||||
t.Font = fontMedium.With(italics: true);
|
||||
t.Colour = entryColour;
|
||||
});
|
||||
}
|
||||
@ -162,7 +163,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 +172,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;
|
||||
|
||||
@ -22,6 +24,8 @@ namespace osu.Game.Overlays.Changelog
|
||||
|
||||
private const string listing_string = "listing";
|
||||
|
||||
private Box streamsBackground;
|
||||
|
||||
public ChangelogHeader()
|
||||
{
|
||||
TabControl.AddItem(listing_string);
|
||||
@ -40,6 +44,12 @@ namespace osu.Game.Overlays.Changelog
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
streamsBackground.Colour = colourProvider.Background5;
|
||||
}
|
||||
|
||||
private ChangelogHeaderTitle title;
|
||||
|
||||
private void showBuild(ValueChangedEvent<APIChangelogBuild> e)
|
||||
@ -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 UpdateStreamBadgeArea()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -3,8 +3,6 @@
|
||||
|
||||
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;
|
||||
@ -16,99 +14,81 @@ 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;
|
||||
private readonly APIUpdateStream stream;
|
||||
|
||||
private FillFlowContainer<SpriteText> text;
|
||||
private ExpandingBar expandingBar;
|
||||
|
||||
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);
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
sampleClick = audio.Samples.Get(@"UI/generic-select-soft");
|
||||
sampleHover = audio.Samples.Get(@"UI/generic-hover-soft");
|
||||
Size = new Vector2(stream.IsFeatured ? badge_width * 2 : badge_width, 60);
|
||||
Padding = new MarginPadding(5);
|
||||
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
text = new FillFlowContainer<SpriteText>
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Margin = new MarginPadding { Top = 6 },
|
||||
Children = new[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = stream.DisplayName,
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Black),
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = stream.LatestBuild.DisplayVersion,
|
||||
Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular),
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = stream.LatestBuild.Users > 0 ? $"{"user".ToQuantity(stream.LatestBuild.Users, "N0")} online" : null,
|
||||
Font = OsuFont.GetFont(size: 10),
|
||||
Colour = colourProvider.Foreground1
|
||||
},
|
||||
}
|
||||
},
|
||||
expandingBar = new ExpandingBar
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Colour = stream.Colour,
|
||||
ExpandedSize = 4,
|
||||
CollapsedSize = 2,
|
||||
Expanded = true
|
||||
},
|
||||
new HoverClickSounds()
|
||||
});
|
||||
|
||||
SelectedTab.BindValueChanged(_ => updateState(), true);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -120,38 +100,41 @@ namespace osu.Game.Overlays.Changelog
|
||||
|
||||
private void updateState()
|
||||
{
|
||||
// Expand based on the local state
|
||||
bool shouldExpand = Active.Value || IsHovered;
|
||||
// highlighted regardless if we are hovered
|
||||
bool textHighlighted = IsHovered;
|
||||
bool barExpanded = IsHovered;
|
||||
|
||||
// Expand based on whether no build is selected and the badge area is hovered
|
||||
shouldExpand |= SelectedTab.Value == null && !externalDimRequested;
|
||||
|
||||
if (shouldExpand)
|
||||
if (SelectedTab.Value == null)
|
||||
{
|
||||
expandingBar.Expand();
|
||||
fadeContainer.FadeTo(1, transition_duration);
|
||||
// at listing, all badges are highlighted when user is not hovering any badge.
|
||||
textHighlighted |= !userHoveringArea;
|
||||
barExpanded |= !userHoveringArea;
|
||||
}
|
||||
else
|
||||
{
|
||||
expandingBar.Collapse();
|
||||
fadeContainer.FadeTo(0.5f, transition_duration);
|
||||
// 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;
|
||||
}
|
||||
|
||||
text.FadeTo(externalDimRequested && !IsHovered ? 0.5f : 1, transition_duration);
|
||||
expandingBar.Expanded = barExpanded;
|
||||
text.FadeTo(textHighlighted ? 1 : 0.5f, transition_duration, Easing.OutQuint);
|
||||
}
|
||||
|
||||
private bool externalDimRequested;
|
||||
private bool userHoveringArea;
|
||||
|
||||
public void EnableDim()
|
||||
public bool UserHoveringArea
|
||||
{
|
||||
externalDimRequested = true;
|
||||
updateState();
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == userHoveringArea)
|
||||
return;
|
||||
|
||||
public void DisableDim()
|
||||
{
|
||||
externalDimRequested = false;
|
||||
updateState();
|
||||
userHoveringArea = value;
|
||||
updateState();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,9 +6,7 @@ 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
|
||||
{
|
||||
@ -18,52 +16,36 @@ namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
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)
|
||||
foreach (var updateStream in streams)
|
||||
AddItem(updateStream);
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
foreach (UpdateStreamBadge streamBadge in TabContainer.Children.OfType<UpdateStreamBadge>())
|
||||
streamBadge.EnableDim();
|
||||
foreach (var streamBadge in TabContainer.Children.OfType<UpdateStreamBadge>())
|
||||
streamBadge.UserHoveringArea = true;
|
||||
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
foreach (UpdateStreamBadge streamBadge in TabContainer.Children.OfType<UpdateStreamBadge>())
|
||||
streamBadge.DisableDim();
|
||||
foreach (var streamBadge in TabContainer.Children.OfType<UpdateStreamBadge>())
|
||||
streamBadge.UserHoveringArea = false;
|
||||
|
||||
base.OnHoverLost(e);
|
||||
}
|
||||
|
||||
protected override TabFillFlowContainer CreateTabFlow()
|
||||
protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
|
||||
{
|
||||
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;
|
||||
}
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
AllowMultiline = true,
|
||||
};
|
||||
|
||||
protected override Dropdown<APIUpdateStream> CreateDropdown() => null;
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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.
|
||||
|
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
241
osu.Game/Overlays/Comments/CommentEditor.cs
Normal file
241
osu.Game/Overlays/Comments/CommentEditor.cs
Normal file
@ -0,0 +1,241 @@
|
||||
// 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 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -18,8 +18,8 @@ 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();
|
||||
@ -127,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;
|
||||
@ -147,12 +147,12 @@ 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.PerformAsync(request);
|
||||
}
|
||||
@ -172,7 +172,10 @@ namespace osu.Game.Overlays.Comments
|
||||
|
||||
LoadComponentAsync(new CommentsPage(response)
|
||||
{
|
||||
ShowDeleted = { BindTarget = ShowDeleted }
|
||||
ShowDeleted = { BindTarget = ShowDeleted },
|
||||
Sort = { BindTarget = Sort },
|
||||
Type = { BindTarget = type },
|
||||
CommentableId = { BindTarget = id }
|
||||
}, loaded =>
|
||||
{
|
||||
content.Add(loaded);
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -9,14 +9,25 @@ 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)
|
||||
{
|
||||
@ -26,8 +37,6 @@ namespace osu.Game.Overlays.Comments
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
FillFlowContainer flow;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
@ -52,14 +61,74 @@ namespace osu.Game.Overlays.Comments
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var c in commentBundle.Comments)
|
||||
AppendComments(commentBundle);
|
||||
}
|
||||
|
||||
private DrawableComment getDrawableComment(Comment comment)
|
||||
{
|
||||
if (CommentDictionary.TryGetValue(comment.Id, out var existing))
|
||||
return existing;
|
||||
|
||||
return CommentDictionary[comment.Id] = new DrawableComment(comment)
|
||||
{
|
||||
if (c.IsTopLevel)
|
||||
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)
|
||||
{
|
||||
flow.Add(new DrawableComment(c)
|
||||
{
|
||||
ShowDeleted = { BindTarget = ShowDeleted }
|
||||
});
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
DeletedCommentsCounter deletedCommentsCounter;
|
||||
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
|
||||
},
|
||||
deletedCommentsCounter = new DeletedCommentsCounter
|
||||
{
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
deletedCommentsCounter.Count.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.Message);
|
||||
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();
|
||||
|
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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,14 +34,13 @@ namespace osu.Game.Overlays.Direct
|
||||
|
||||
public enum DirectSortCriteria
|
||||
{
|
||||
Relevance,
|
||||
Title,
|
||||
Artist,
|
||||
Creator,
|
||||
Difficulty,
|
||||
Ranked,
|
||||
Rating,
|
||||
Plays,
|
||||
Favourites,
|
||||
Relevance,
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,8 @@ 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;
|
||||
@ -155,11 +156,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;
|
||||
}
|
||||
|
||||
@ -228,7 +226,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)
|
||||
{
|
||||
|
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,
|
||||
|
@ -12,17 +12,12 @@ using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.Music
|
||||
{
|
||||
public class Playlist : RearrangeableListContainer<BeatmapSetInfo>
|
||||
public class Playlist : OsuRearrangeableListContainer<BeatmapSetInfo>
|
||||
{
|
||||
public Action<BeatmapSetInfo> RequestSelection;
|
||||
|
||||
public readonly Bindable<BeatmapSetInfo> SelectedSet = new Bindable<BeatmapSetInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// Whether any item is currently being dragged. Used to hide other items' drag handles.
|
||||
/// </summary>
|
||||
private readonly BindableBool playlistDragActive = new BindableBool();
|
||||
|
||||
public new MarginPadding Padding
|
||||
{
|
||||
get => base.Padding;
|
||||
@ -33,15 +28,12 @@ namespace osu.Game.Overlays.Music
|
||||
|
||||
public BeatmapSetInfo FirstVisibleSet => Items.FirstOrDefault(i => ((PlaylistItem)ItemMap[i]).MatchingFilter);
|
||||
|
||||
protected override RearrangeableListItem<BeatmapSetInfo> CreateDrawable(BeatmapSetInfo item) => new PlaylistItem(item)
|
||||
protected override OsuRearrangeableListItem<BeatmapSetInfo> CreateOsuDrawable(BeatmapSetInfo item) => new PlaylistItem(item)
|
||||
{
|
||||
SelectedSet = { BindTarget = SelectedSet },
|
||||
PlaylistDragActive = { BindTarget = playlistDragActive },
|
||||
RequestSelection = set => RequestSelection?.Invoke(set)
|
||||
};
|
||||
|
||||
protected override ScrollContainer<Drawable> CreateScrollContainer() => new OsuScrollContainer();
|
||||
|
||||
protected override FillFlowContainer<RearrangeableListItem<BeatmapSetInfo>> CreateListFillFlowContainer() => new SearchContainer<RearrangeableListItem<BeatmapSetInfo>>
|
||||
{
|
||||
Spacing = new Vector2(0, 3),
|
||||
|
@ -14,36 +14,28 @@ 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 : RearrangeableListItem<BeatmapSetInfo>, IFilterable
|
||||
public class PlaylistItem : OsuRearrangeableListItem<BeatmapSetInfo>, IFilterable
|
||||
{
|
||||
private const float fade_duration = 100;
|
||||
|
||||
public BindableBool PlaylistDragActive = new BindableBool();
|
||||
|
||||
public readonly Bindable<BeatmapSetInfo> SelectedSet = new Bindable<BeatmapSetInfo>();
|
||||
|
||||
public Action<BeatmapSetInfo> RequestSelection;
|
||||
|
||||
private PlaylistItemHandle handle;
|
||||
private TextFlowContainer text;
|
||||
private IEnumerable<Drawable> titleSprites;
|
||||
private ILocalisedBindableString titleBind;
|
||||
private ILocalisedBindableString artistBind;
|
||||
|
||||
private Color4 hoverColour;
|
||||
private ILocalisedBindableString title;
|
||||
private ILocalisedBindableString artist;
|
||||
|
||||
private Color4 selectedColour;
|
||||
private Color4 artistColour;
|
||||
|
||||
public PlaylistItem(BeatmapSetInfo item)
|
||||
: base(item)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
Padding = new MarginPadding { Left = 5 };
|
||||
|
||||
FilterTerms = item.Metadata.SearchableTerms;
|
||||
@ -52,66 +44,44 @@ namespace osu.Game.Overlays.Music
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, LocalisationManager localisation)
|
||||
{
|
||||
hoverColour = colours.Yellow;
|
||||
selectedColour = colours.Yellow;
|
||||
artistColour = colours.Gray9;
|
||||
HandleColour = colours.Gray5;
|
||||
|
||||
InternalChild = new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
handle = new PlaylistItemHandle
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Size = new Vector2(12),
|
||||
Colour = colours.Gray5,
|
||||
AlwaysPresent = true,
|
||||
Alpha = 0
|
||||
},
|
||||
text = new OsuTextFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding { Left = 5 },
|
||||
},
|
||||
}
|
||||
},
|
||||
ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
|
||||
RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }
|
||||
};
|
||||
|
||||
titleBind = localisation.GetLocalisedString(new LocalisedString((Model.Metadata.TitleUnicode, Model.Metadata.Title)));
|
||||
artistBind = localisation.GetLocalisedString(new LocalisedString((Model.Metadata.ArtistUnicode, Model.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 != Model && set.NewValue != Model)
|
||||
if (set.OldValue?.Equals(Model) != true && set.NewValue?.Equals(Model) != true)
|
||||
return;
|
||||
|
||||
foreach (Drawable s in titleSprites)
|
||||
s.FadeColour(set.NewValue == Model ? hoverColour : Color4.White, fade_duration);
|
||||
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;
|
||||
@ -125,31 +95,6 @@ namespace osu.Game.Overlays.Music
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool OnDragStart(DragStartEvent e)
|
||||
{
|
||||
if (!base.OnDragStart(e))
|
||||
return false;
|
||||
|
||||
PlaylistDragActive.Value = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnDragEnd(DragEndEvent e)
|
||||
{
|
||||
PlaylistDragActive.Value = false;
|
||||
base.OnDragEnd(e);
|
||||
}
|
||||
|
||||
protected override bool IsDraggableAt(Vector2 screenSpacePos) => handle.HandlingDrag;
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
handle.UpdateHoverState(IsDragged || !PlaylistDragActive.Value);
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e) => handle.UpdateHoverState(false);
|
||||
|
||||
public IEnumerable<string> FilterTerms { get; }
|
||||
|
||||
private bool matching = true;
|
||||
@ -168,44 +113,5 @@ namespace osu.Game.Overlays.Music
|
||||
}
|
||||
|
||||
public bool FilteringActive { get; set; }
|
||||
|
||||
private class PlaylistItemHandle : SpriteIcon
|
||||
{
|
||||
public bool HandlingDrag { get; private set; }
|
||||
private bool isHovering;
|
||||
|
||||
public PlaylistItemHandle()
|
||||
{
|
||||
Icon = FontAwesome.Solid.Bars;
|
||||
}
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e)
|
||||
{
|
||||
base.OnMouseDown(e);
|
||||
|
||||
HandlingDrag = true;
|
||||
UpdateHoverState(isHovering);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void OnMouseUp(MouseUpEvent e)
|
||||
{
|
||||
base.OnMouseUp(e);
|
||||
|
||||
HandlingDrag = false;
|
||||
UpdateHoverState(isHovering);
|
||||
}
|
||||
|
||||
public void UpdateHoverState(bool hovering)
|
||||
{
|
||||
isHovering = hovering;
|
||||
|
||||
if (isHovering || HandlingDrag)
|
||||
this.FadeIn(fade_duration);
|
||||
else
|
||||
this.FadeOut(fade_duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,16 +26,17 @@ namespace osu.Game.Overlays.Music
|
||||
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 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[]
|
||||
{
|
||||
@ -74,8 +75,6 @@ namespace osu.Game.Overlays.Music
|
||||
},
|
||||
};
|
||||
|
||||
list.Items.BindTo(beatmapSets);
|
||||
|
||||
filter.Search.OnCommit = (sender, newText) =>
|
||||
{
|
||||
BeatmapInfo toSelect = list.FirstVisibleSet?.Beatmaps?.FirstOrDefault();
|
||||
@ -86,7 +85,13 @@ namespace osu.Game.Overlays.Music
|
||||
beatmap.Value.Track.Restart();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
list.Items.BindTo(beatmapSets);
|
||||
beatmap.BindValueChanged(working => list.SelectedSet.Value = working.NewValue.BeatmapSetInfo, 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;
|
||||
|
||||
|
@ -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,15 +185,15 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
playlist.BeatmapSets.BindTo(musicController.BeatmapSets);
|
||||
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;
|
||||
|
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
|
||||
}
|
||||
}
|
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Framework.Allocation;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections
|
||||
{
|
||||
@ -16,9 +17,10 @@ namespace osu.Game.Overlays.Profile.Sections
|
||||
|
||||
public readonly BindableInt Current = new BindableInt();
|
||||
|
||||
private readonly OsuSpriteText counter;
|
||||
private OsuSpriteText counter;
|
||||
|
||||
public CounterPill()
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Alpha = 0;
|
||||
@ -28,14 +30,15 @@ namespace osu.Game.Overlays.Profile.Sections
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.Gray(0.05f)
|
||||
Colour = colourProvider.Background6
|
||||
},
|
||||
counter = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Margin = new MarginPadding { Horizontal = 10, Vertical = 5 },
|
||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold)
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold),
|
||||
Colour = colourProvider.Foreground1
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -54,7 +57,7 @@ namespace osu.Game.Overlays.Profile.Sections
|
||||
return;
|
||||
}
|
||||
|
||||
counter.Text = value.NewValue.ToString();
|
||||
counter.Text = value.NewValue.ToString("N0");
|
||||
this.FadeIn(duration, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
@ -22,10 +21,9 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
public class DrawableProfileScore : CompositeDrawable
|
||||
{
|
||||
private const int height = 40;
|
||||
private const int performance_width = 80;
|
||||
private const int performance_width = 100;
|
||||
|
||||
private const float performance_background_shear = 0.45f;
|
||||
private static readonly float performance_background_width = performance_width + (height / 4f * MathF.Tan(performance_background_shear));
|
||||
|
||||
protected readonly ScoreInfo Score;
|
||||
|
||||
@ -53,7 +51,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Left = 10, Right = performance_width + 30 },
|
||||
Padding = new MarginPadding { Left = 20, Right = performance_width },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
@ -62,7 +60,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
Origin = Anchor.CentreLeft,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(8, 0),
|
||||
Spacing = new Vector2(10, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new UpdateableRank(Score.Rank)
|
||||
@ -85,7 +83,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(5, 0),
|
||||
Spacing = new Vector2(15, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
@ -108,16 +106,21 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(15),
|
||||
Children = new[]
|
||||
Children = new Drawable[]
|
||||
{
|
||||
CreateRightContent().With(c =>
|
||||
new Container
|
||||
{
|
||||
c.Anchor = Anchor.CentreRight;
|
||||
c.Origin = Anchor.CentreRight;
|
||||
}),
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding { Horizontal = 10, Vertical = 5 },
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Child = CreateRightContent()
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
@ -140,14 +143,13 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
Width = performance_width,
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Children = new[]
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = performance_background_width,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Height = 0.5f,
|
||||
Colour = colourProvider.Background4,
|
||||
Shear = new Vector2(-performance_background_shear, 0),
|
||||
@ -157,20 +159,29 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
RelativePositionAxes = Axes.Y,
|
||||
Width = performance_background_width,
|
||||
Height = -0.5f,
|
||||
Position = new Vector2(0, 1),
|
||||
Colour = colourProvider.Background4,
|
||||
Shear = new Vector2(performance_background_shear, 0),
|
||||
EdgeSmoothness = new Vector2(2, 0),
|
||||
},
|
||||
createDrawablePerformance().With(d =>
|
||||
new Container
|
||||
{
|
||||
d.Anchor = Anchor.Centre;
|
||||
d.Origin = Anchor.Centre;
|
||||
})
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Vertical = 5,
|
||||
Left = 30,
|
||||
Right = 20
|
||||
},
|
||||
Child = createDrawablePerformance().With(d =>
|
||||
{
|
||||
d.Anchor = Anchor.Centre;
|
||||
d.Origin = Anchor.Centre;
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -180,11 +191,18 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
[NotNull]
|
||||
protected virtual Drawable CreateRightContent() => CreateDrawableAccuracy();
|
||||
|
||||
protected OsuSpriteText CreateDrawableAccuracy() => new OsuSpriteText
|
||||
protected Drawable CreateDrawableAccuracy() => new Container
|
||||
{
|
||||
Text = Score.DisplayAccuracy,
|
||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
|
||||
Colour = colours.Yellow,
|
||||
Width = 65,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Child = new OsuSpriteText
|
||||
{
|
||||
Text = Score.DisplayAccuracy,
|
||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
|
||||
Colour = colours.Yellow,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft
|
||||
}
|
||||
};
|
||||
|
||||
private Drawable createDrawablePerformance()
|
||||
|
@ -6,6 +6,7 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Scoring;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
{
|
||||
@ -23,25 +24,28 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new Drawable[]
|
||||
Spacing = new Vector2(10, 0),
|
||||
Children = new[]
|
||||
{
|
||||
CreateDrawableAccuracy(),
|
||||
new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Width = 60,
|
||||
Child = CreateDrawableAccuracy()
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
|
||||
Text = $"{Score.PP * weight:0}pp",
|
||||
},
|
||||
Width = 50,
|
||||
Child = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
|
||||
Text = $"{Score.PP * weight:0}pp",
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
new OsuSpriteText
|
||||
|
@ -11,23 +11,23 @@ namespace osu.Game.Overlays.Rankings
|
||||
{
|
||||
public class RankingsOverlayHeader : TabControlOverlayHeader<RankingsScope>
|
||||
{
|
||||
public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
||||
public readonly Bindable<Country> Country = new Bindable<Country>();
|
||||
public Bindable<RulesetInfo> Ruleset => rulesetSelector.Current;
|
||||
|
||||
public Bindable<Country> Country => countryFilter.Current;
|
||||
|
||||
private OverlayRulesetSelector rulesetSelector;
|
||||
private CountryFilter countryFilter;
|
||||
|
||||
protected override ScreenTitle CreateTitle() => new RankingsTitle
|
||||
{
|
||||
Scope = { BindTarget = Current }
|
||||
};
|
||||
|
||||
protected override Drawable CreateTitleContent() => new OverlayRulesetSelector
|
||||
{
|
||||
Current = Ruleset
|
||||
};
|
||||
protected override Drawable CreateTitleContent() => rulesetSelector = new OverlayRulesetSelector();
|
||||
|
||||
protected override Drawable CreateContent() => new CountryFilter
|
||||
{
|
||||
Current = Country
|
||||
};
|
||||
protected override Drawable CreateContent() => countryFilter = new CountryFilter();
|
||||
|
||||
protected override Drawable CreateBackground() => new OverlayHeaderBackground(@"Headers/rankings");
|
||||
|
||||
private class RankingsTitle : ScreenTitle
|
||||
{
|
||||
|
@ -37,7 +37,7 @@ namespace osu.Game.Overlays.Rankings
|
||||
|
||||
private SpotlightSelector selector;
|
||||
private Container content;
|
||||
private DimmedLoadingLayer loading;
|
||||
private LoadingLayer loading;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Rankings
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Margin = new MarginPadding { Vertical = 10 }
|
||||
},
|
||||
loading = new DimmedLoadingLayer()
|
||||
loading = new LoadingLayer(content)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -89,7 +89,7 @@ namespace osu.Game.Overlays.Rankings
|
||||
private void getSpotlights()
|
||||
{
|
||||
spotlightsRequest = new GetSpotlightsRequest();
|
||||
spotlightsRequest.Success += response => selector.Spotlights = response.Spotlights;
|
||||
spotlightsRequest.Success += response => Schedule(() => selector.Spotlights = response.Spotlights);
|
||||
api.Queue(spotlightsRequest);
|
||||
}
|
||||
|
||||
@ -151,11 +151,11 @@ namespace osu.Game.Overlays.Rankings
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
spotlightsRequest?.Cancel();
|
||||
getRankingsRequest?.Cancel();
|
||||
cancellationToken?.Cancel();
|
||||
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ using osu.Game.Users;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Graphics.Containers;
|
||||
|
||||
namespace osu.Game.Overlays.Rankings.Tables
|
||||
{
|
||||
@ -30,11 +32,7 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
|
||||
protected override Country GetCountry(CountryStatistics item) => item.Country;
|
||||
|
||||
protected override Drawable CreateFlagContent(CountryStatistics item) => new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: TEXT_SIZE),
|
||||
Text = $@"{item.Country.FullName}",
|
||||
};
|
||||
protected override Drawable CreateFlagContent(CountryStatistics item) => new CountryName(item.Country);
|
||||
|
||||
protected override Drawable[] CreateAdditionalContent(CountryStatistics item) => new Drawable[]
|
||||
{
|
||||
@ -63,5 +61,37 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
Text = $@"{item.Performance / Math.Max(item.ActiveUsers, 1):N0}",
|
||||
}
|
||||
};
|
||||
|
||||
private class CountryName : OsuHoverContainer
|
||||
{
|
||||
protected override IEnumerable<Drawable> EffectTargets => new[] { text };
|
||||
|
||||
[Resolved(canBeNull: true)]
|
||||
private RankingsOverlay rankings { get; set; }
|
||||
|
||||
private readonly OsuSpriteText text;
|
||||
private readonly Country country;
|
||||
|
||||
public CountryName(Country country)
|
||||
{
|
||||
this.country = country;
|
||||
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Add(text = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 12),
|
||||
Text = country.FullName ?? string.Empty,
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
IdleColour = colourProvider.Light2;
|
||||
HoverColour = colourProvider.Content2;
|
||||
|
||||
Action = () => rankings?.ShowCountry(country);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
|
||||
protected sealed override Drawable CreateFlagContent(UserStatistics item)
|
||||
{
|
||||
var username = new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: TEXT_SIZE)) { AutoSizeAxes = Axes.Both };
|
||||
var username = new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: TEXT_SIZE, italics: true)) { AutoSizeAxes = Axes.Both };
|
||||
username.AddUserLink(item.User);
|
||||
return username;
|
||||
}
|
||||
|
@ -9,9 +9,9 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Overlays.Rankings;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API;
|
||||
using System.Threading;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Overlays.Rankings.Tables;
|
||||
|
||||
@ -19,14 +19,15 @@ namespace osu.Game.Overlays
|
||||
{
|
||||
public class RankingsOverlay : FullscreenOverlay
|
||||
{
|
||||
protected readonly Bindable<Country> Country = new Bindable<Country>();
|
||||
protected readonly Bindable<RankingsScope> Scope = new Bindable<RankingsScope>();
|
||||
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
|
||||
protected Bindable<Country> Country => header.Country;
|
||||
|
||||
protected Bindable<RankingsScope> Scope => header.Current;
|
||||
|
||||
private readonly BasicScrollContainer scrollFlow;
|
||||
private readonly Container contentContainer;
|
||||
private readonly DimmedLoadingLayer loading;
|
||||
private readonly LoadingLayer loading;
|
||||
private readonly Box background;
|
||||
private readonly RankingsOverlayHeader header;
|
||||
|
||||
private APIRequest lastRequest;
|
||||
private CancellationTokenSource cancellationToken;
|
||||
@ -54,14 +55,11 @@ namespace osu.Game.Overlays
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new RankingsOverlayHeader
|
||||
header = new RankingsOverlayHeader
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Depth = -float.MaxValue,
|
||||
Country = { BindTarget = Country },
|
||||
Current = { BindTarget = Scope },
|
||||
Ruleset = { BindTarget = ruleset }
|
||||
Depth = -float.MaxValue
|
||||
},
|
||||
new Container
|
||||
{
|
||||
@ -77,7 +75,7 @@ namespace osu.Game.Overlays
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Margin = new MarginPadding { Bottom = 10 }
|
||||
},
|
||||
loading = new DimmedLoadingLayer(),
|
||||
loading = new LoadingLayer(contentContainer),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -92,8 +90,15 @@ namespace osu.Game.Overlays
|
||||
background.Colour = ColourProvider.Background5;
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
private Bindable<RulesetInfo> ruleset { get; set; }
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
header.Ruleset.BindTo(ruleset);
|
||||
|
||||
Country.BindValueChanged(_ =>
|
||||
{
|
||||
// if a country is requested, force performance scope.
|
||||
@ -101,7 +106,7 @@ namespace osu.Game.Overlays
|
||||
Scope.Value = RankingsScope.Performance;
|
||||
|
||||
Scheduler.AddOnce(loadNewContent);
|
||||
}, true);
|
||||
});
|
||||
|
||||
Scope.BindValueChanged(_ =>
|
||||
{
|
||||
@ -110,7 +115,7 @@ namespace osu.Game.Overlays
|
||||
Country.Value = null;
|
||||
|
||||
Scheduler.AddOnce(loadNewContent);
|
||||
}, true);
|
||||
});
|
||||
|
||||
ruleset.BindValueChanged(_ =>
|
||||
{
|
||||
@ -118,9 +123,9 @@ namespace osu.Game.Overlays
|
||||
return;
|
||||
|
||||
Scheduler.AddOnce(loadNewContent);
|
||||
}, true);
|
||||
});
|
||||
|
||||
base.LoadComplete();
|
||||
Scheduler.AddOnce(loadNewContent);
|
||||
}
|
||||
|
||||
public void ShowCountry(Country requested)
|
||||
@ -133,6 +138,12 @@ namespace osu.Game.Overlays
|
||||
Country.Value = requested;
|
||||
}
|
||||
|
||||
public void ShowSpotlights()
|
||||
{
|
||||
Scope.Value = RankingsScope.Spotlights;
|
||||
Show();
|
||||
}
|
||||
|
||||
private void loadNewContent()
|
||||
{
|
||||
loading.Show();
|
||||
@ -158,8 +169,8 @@ namespace osu.Game.Overlays
|
||||
return;
|
||||
}
|
||||
|
||||
request.Success += () => loadContent(createTableFromResponse(request));
|
||||
request.Failure += _ => loadContent(null);
|
||||
request.Success += () => Schedule(() => loadContent(createTableFromResponse(request)));
|
||||
request.Failure += _ => Schedule(() => loadContent(null));
|
||||
|
||||
api.Queue(request);
|
||||
}
|
||||
@ -221,5 +232,13 @@ namespace osu.Game.Overlays
|
||||
contentContainer.Child = loaded;
|
||||
}, (cancellationToken = new CancellationTokenSource()).Token);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
lastRequest?.Cancel();
|
||||
cancellationToken?.Cancel();
|
||||
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ namespace osu.Game.Overlays.SearchableList
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding { Horizontal = WIDTH_PADDING, Bottom = 50 },
|
||||
Padding = new MarginPadding { Horizontal = 10, Bottom = 50 },
|
||||
Direction = FillDirection.Vertical,
|
||||
},
|
||||
},
|
||||
|
@ -14,14 +14,10 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
|
||||
{
|
||||
protected override string Header => "Devices";
|
||||
|
||||
private AudioManager audio;
|
||||
private SettingsDropdown<string> dropdown;
|
||||
[Resolved]
|
||||
private AudioManager audio { get; set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
this.audio = audio;
|
||||
}
|
||||
private SettingsDropdown<string> dropdown;
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
|
@ -22,11 +22,6 @@ namespace osu.Game.Overlays.Settings.Sections.Debug
|
||||
Bindable = frameworkConfig.GetBindable<bool>(FrameworkSetting.ShowLogOverlay)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Performance logging",
|
||||
Bindable = config.GetBindable<bool>(DebugSetting.PerformanceLogging)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Bypass front-to-back render pass",
|
||||
Bindable = config.GetBindable<bool>(DebugSetting.BypassFrontToBackPass)
|
||||
|
@ -29,7 +29,9 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
{
|
||||
private bool bounding = true;
|
||||
private LoginForm form;
|
||||
private OsuColour colours;
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; }
|
||||
|
||||
private UserPanel panel;
|
||||
private UserDropdown dropdown;
|
||||
@ -60,10 +62,8 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(permitNulls: true)]
|
||||
private void load(OsuColour colours, IAPIProvider api)
|
||||
private void load(IAPIProvider api)
|
||||
{
|
||||
this.colours = colours;
|
||||
|
||||
api?.Register(this);
|
||||
}
|
||||
|
||||
@ -95,7 +95,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new LoadingAnimation
|
||||
new LoadingSpinner
|
||||
{
|
||||
State = { Value = Visibility.Visible },
|
||||
Anchor = Anchor.TopCentre,
|
||||
@ -201,7 +201,9 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
private TextBox username;
|
||||
private TextBox password;
|
||||
private ShakeContainer shakeSignIn;
|
||||
private IAPIProvider api;
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
public Action RequestHide;
|
||||
|
||||
@ -214,9 +216,8 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(permitNulls: true)]
|
||||
private void load(IAPIProvider api, OsuConfigManager config, AccountCreationOverlay accountCreation)
|
||||
private void load(OsuConfigManager config, AccountCreationOverlay accountCreation)
|
||||
{
|
||||
this.api = api;
|
||||
Direction = FillDirection.Vertical;
|
||||
Spacing = new Vector2(0, 5);
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
@ -29,7 +29,9 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
private Bindable<Size> sizeFullscreen;
|
||||
private readonly IBindableList<WindowMode> windowModes = new BindableList<WindowMode>();
|
||||
|
||||
private OsuGameBase game;
|
||||
[Resolved]
|
||||
private OsuGameBase game { get; set; }
|
||||
|
||||
private SettingsDropdown<Size> resolutionDropdown;
|
||||
private SettingsDropdown<WindowMode> windowModeDropdown;
|
||||
|
||||
@ -41,10 +43,8 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
private const int transition_duration = 400;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, OsuGameBase game, GameHost host)
|
||||
private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, GameHost host)
|
||||
{
|
||||
this.game = game;
|
||||
|
||||
scalingMode = osuConfig.GetBindable<ScalingMode>(OsuSetting.Scaling);
|
||||
sizeFullscreen = config.GetBindable<Size>(FrameworkSetting.SizeFullscreen);
|
||||
scalingSizeX = osuConfig.GetBindable<float>(OsuSetting.ScalingSizeX);
|
||||
|
@ -4,6 +4,7 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Configuration;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
@ -24,6 +25,11 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
LabelText = "Frame limiter",
|
||||
Bindable = config.GetBindable<FrameSync>(FrameworkSetting.FrameSync)
|
||||
},
|
||||
new SettingsEnumDropdown<ExecutionMode>
|
||||
{
|
||||
LabelText = "Threading mode",
|
||||
Bindable = config.GetBindable<ExecutionMode>(FrameworkSetting.ExecutionMode)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Show FPS",
|
||||
|
@ -24,13 +24,12 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
private readonly Bindable<SkinInfo> dropdownBindable = new Bindable<SkinInfo> { Default = SkinInfo.Default };
|
||||
private readonly Bindable<int> configBindable = new Bindable<int>();
|
||||
|
||||
private SkinManager skins;
|
||||
[Resolved]
|
||||
private SkinManager skins { get; set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config, SkinManager skins)
|
||||
private void load(OsuConfigManager config)
|
||||
{
|
||||
this.skins = skins;
|
||||
|
||||
FlowContent.Spacing = new Vector2(0, 5);
|
||||
Children = new Drawable[]
|
||||
{
|
||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Overlays
|
||||
{
|
||||
public class SocialOverlay : SearchableListOverlay<SocialTab, SocialSortCriteria, SortDirection>
|
||||
{
|
||||
private readonly LoadingAnimation loading;
|
||||
private readonly LoadingSpinner loading;
|
||||
private FillFlowContainer<SocialPanel> panels;
|
||||
|
||||
protected override Color4 BackgroundColour => OsuColour.FromHex(@"60284b");
|
||||
@ -54,7 +54,7 @@ namespace osu.Game.Overlays
|
||||
public SocialOverlay()
|
||||
: base(OverlayColourScheme.Pink)
|
||||
{
|
||||
Add(loading = new LoadingAnimation());
|
||||
Add(loading = new LoadingSpinner());
|
||||
|
||||
Filter.Search.Current.ValueChanged += text =>
|
||||
{
|
||||
|
@ -70,6 +70,7 @@ namespace osu.Game.Overlays.Toolbar
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new ToolbarChangelogButton(),
|
||||
new ToolbarRankingsButton(),
|
||||
new ToolbarDirectButton(),
|
||||
new ToolbarChatButton(),
|
||||
new ToolbarSocialButton(),
|
||||
|
22
osu.Game/Overlays/Toolbar/ToolbarRankingsButton.cs
Normal file
22
osu.Game/Overlays/Toolbar/ToolbarRankingsButton.cs
Normal file
@ -0,0 +1,22 @@
|
||||
// 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.Sprites;
|
||||
|
||||
namespace osu.Game.Overlays.Toolbar
|
||||
{
|
||||
public class ToolbarRankingsButton : ToolbarOverlayToggleButton
|
||||
{
|
||||
public ToolbarRankingsButton()
|
||||
{
|
||||
SetIcon(FontAwesome.Regular.ChartBar);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(RankingsOverlay rankings)
|
||||
{
|
||||
StateContainer = rankings;
|
||||
}
|
||||
}
|
||||
}
|
@ -14,8 +14,25 @@ namespace osu.Game.Overlays.Volume
|
||||
public Func<GlobalAction, bool> ActionRequested;
|
||||
public Func<GlobalAction, float, bool, bool> ScrollActionRequested;
|
||||
|
||||
public bool OnPressed(GlobalAction action) => ActionRequested?.Invoke(action) ?? false;
|
||||
public bool OnScroll(GlobalAction action, float amount, bool isPrecise) => ScrollActionRequested?.Invoke(action, amount, isPrecise) ?? false;
|
||||
public bool OnPressed(GlobalAction action)
|
||||
{
|
||||
// if nothing else handles selection actions in the game, it's safe to let volume be adjusted.
|
||||
switch (action)
|
||||
{
|
||||
case GlobalAction.SelectPrevious:
|
||||
action = GlobalAction.IncreaseVolume;
|
||||
break;
|
||||
|
||||
case GlobalAction.SelectNext:
|
||||
action = GlobalAction.DecreaseVolume;
|
||||
break;
|
||||
}
|
||||
|
||||
return ActionRequested?.Invoke(action) ?? false;
|
||||
}
|
||||
|
||||
public bool OnScroll(GlobalAction action, float amount, bool isPrecise) =>
|
||||
ScrollActionRequested?.Invoke(action, amount, isPrecise) ?? false;
|
||||
|
||||
public void OnReleased(GlobalAction action)
|
||||
{
|
||||
|
@ -11,16 +11,18 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Volume
|
||||
{
|
||||
public class VolumeMeter : Container
|
||||
public class VolumeMeter : Container, IKeyBindingHandler<GlobalAction>
|
||||
{
|
||||
private CircularProgress volumeCircle;
|
||||
private CircularProgress volumeCircleGlow;
|
||||
@ -260,5 +262,28 @@ namespace osu.Game.Overlays.Volume
|
||||
{
|
||||
this.ScaleTo(1f, transition_length, Easing.OutExpo);
|
||||
}
|
||||
|
||||
public bool OnPressed(GlobalAction action)
|
||||
{
|
||||
if (!IsHovered)
|
||||
return false;
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case GlobalAction.SelectPrevious:
|
||||
adjust(1, false);
|
||||
return true;
|
||||
|
||||
case GlobalAction.SelectNext:
|
||||
adjust(-1, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void OnReleased(GlobalAction action)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user