1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-14 20:13:22 +08:00

Add countdown button + popover

This commit is contained in:
Dan Balasescu 2022-03-17 19:05:28 +09:00
parent b76a87e6f8
commit efce471f0b
4 changed files with 246 additions and 118 deletions

View File

@ -8,6 +8,7 @@ using osu.Framework.Audio;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions; using osu.Framework.Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Framework.Utils; using osu.Framework.Utils;
@ -55,15 +56,16 @@ namespace osu.Game.Tests.Visual.Multiplayer
RulesetID = Beatmap.Value.BeatmapInfo.Ruleset.OnlineID RulesetID = Beatmap.Value.BeatmapInfo.Ruleset.OnlineID
}; };
if (button != null) Child = new PopoverContainer
Remove(button);
Add(button = new MultiplayerReadyButton
{ {
Anchor = Anchor.Centre, RelativeSizeAxes = Axes.Both,
Origin = Anchor.Centre, Child = button = new MultiplayerReadyButton
Size = new Vector2(200, 50), {
}); Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(200, 50),
}
};
}); });
[Test] [Test]

View File

@ -9,6 +9,7 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions; using osu.Framework.Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -56,23 +57,27 @@ namespace osu.Game.Tests.Visual.Multiplayer
RulesetID = Beatmap.Value.BeatmapInfo.Ruleset.OnlineID, RulesetID = Beatmap.Value.BeatmapInfo.Ruleset.OnlineID,
}; };
Child = new FillFlowContainer Child = new PopoverContainer
{ {
AutoSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Vertical, Child = new FillFlowContainer
Children = new Drawable[]
{ {
spectateButton = new MultiplayerSpectateButton AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{ {
Anchor = Anchor.Centre, spectateButton = new MultiplayerSpectateButton
Origin = Anchor.Centre, {
Size = new Vector2(200, 50), Anchor = Anchor.Centre,
}, Origin = Anchor.Centre,
readyButton = new MultiplayerReadyButton Size = new Vector2(200, 50),
{ },
Anchor = Anchor.Centre, readyButton = new MultiplayerReadyButton
Origin = Anchor.Centre, {
Size = new Vector2(200, 50), Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(200, 50),
}
} }
} }
}; };

View File

@ -12,6 +12,7 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Audio; using osu.Game.Audio;
@ -100,122 +101,126 @@ namespace osu.Game.Screens.OnlinePlay.Match
{ {
sampleStart = audio.Samples.Get(@"SongSelect/confirm-selection"); sampleStart = audio.Samples.Get(@"SongSelect/confirm-selection");
InternalChildren = new Drawable[] InternalChild = new PopoverContainer
{ {
beatmapAvailabilityTracker, RelativeSizeAxes = Axes.Both,
new MultiplayerRoomSounds(), Children = new Drawable[]
new GridContainer
{ {
RelativeSizeAxes = Axes.Both, beatmapAvailabilityTracker,
RowDimensions = new[] new MultiplayerRoomSounds(),
new GridContainer
{ {
new Dimension(), RelativeSizeAxes = Axes.Both,
new Dimension(GridSizeMode.Absolute, 50) RowDimensions = new[]
},
Content = new[]
{
// Padded main content (drawable room + main content)
new Drawable[]
{ {
new Container new Dimension(),
new Dimension(GridSizeMode.Absolute, 50)
},
Content = new[]
{
// Padded main content (drawable room + main content)
new Drawable[]
{ {
RelativeSizeAxes = Axes.Both, new Container
Padding = new MarginPadding
{ {
Horizontal = WaveOverlayContainer.WIDTH_PADDING, RelativeSizeAxes = Axes.Both,
Bottom = 30 Padding = new MarginPadding
},
Children = new[]
{
mainContent = new GridContainer
{ {
RelativeSizeAxes = Axes.Both, Horizontal = WaveOverlayContainer.WIDTH_PADDING,
RowDimensions = new[] Bottom = 30
},
Children = new[]
{
mainContent = new GridContainer
{ {
new Dimension(GridSizeMode.AutoSize), RelativeSizeAxes = Axes.Both,
new Dimension(GridSizeMode.Absolute, 10) RowDimensions = new[]
},
Content = new[]
{
new Drawable[]
{ {
new DrawableMatchRoom(Room, allowEdit) new Dimension(GridSizeMode.AutoSize),
{ new Dimension(GridSizeMode.Absolute, 10)
OnEdit = () => settingsOverlay.Show(),
SelectedItem = { BindTarget = SelectedItem }
}
}, },
null, Content = new[]
new Drawable[]
{ {
new Container new Drawable[]
{ {
RelativeSizeAxes = Axes.Both, new DrawableMatchRoom(Room, allowEdit)
Children = new[]
{ {
new Container OnEdit = () => settingsOverlay.Show(),
SelectedItem = { BindTarget = SelectedItem }
}
},
null,
new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Children = new[]
{ {
RelativeSizeAxes = Axes.Both, new Container
Masking = true,
CornerRadius = 10,
Child = new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex(@"3e3a44") // Temporary. Masking = true,
CornerRadius = 10,
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex(@"3e3a44") // Temporary.
},
}, },
}, new Container
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(20),
Child = CreateMainContent(),
},
new Container
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Child = userModsSelectOverlay = new UserModSelectOverlay
{ {
SelectedMods = { BindTarget = UserMods }, RelativeSizeAxes = Axes.Both,
IsValidMod = _ => false Padding = new MarginPadding(20),
} Child = CreateMainContent(),
}, },
new Container
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Child = userModsSelectOverlay = new UserModSelectOverlay
{
SelectedMods = { BindTarget = UserMods },
IsValidMod = _ => false
}
},
}
} }
} }
} }
},
new Container
{
RelativeSizeAxes = Axes.Both,
// Resolves 1px masking errors between the settings overlay and the room panel.
Padding = new MarginPadding(-1),
Child = settingsOverlay = CreateRoomSettingsOverlay(Room)
} }
}, },
new Container
{
RelativeSizeAxes = Axes.Both,
// Resolves 1px masking errors between the settings overlay and the room panel.
Padding = new MarginPadding(-1),
Child = settingsOverlay = CreateRoomSettingsOverlay(Room)
}
}, },
}, },
}, // Footer
// Footer new Drawable[]
new Drawable[]
{
new Container
{ {
RelativeSizeAxes = Axes.Both, new Container
Children = new Drawable[]
{ {
new Box RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{ {
RelativeSizeAxes = Axes.Both, new Box
Colour = Color4Extensions.FromHex(@"28242d") // Temporary. {
}, RelativeSizeAxes = Axes.Both,
new Container Colour = Color4Extensions.FromHex(@"28242d") // Temporary.
{ },
RelativeSizeAxes = Axes.Both, new Container
Padding = new MarginPadding(5), {
Child = CreateFooter() RelativeSizeAxes = Axes.Both,
}, Padding = new MarginPadding(5),
Child = CreateFooter()
},
}
} }
} }
} }

View File

@ -4,15 +4,24 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using Humanizer;
using JetBrains.Annotations; using JetBrains.Annotations;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Threading; using osu.Framework.Threading;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.UserInterface;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer;
using osuTK; using osuTK;
@ -30,19 +39,43 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
private Sample sampleReadyAll; private Sample sampleReadyAll;
private Sample sampleUnready; private Sample sampleUnready;
private readonly ReadyButton readyButton; private readonly BindableBool enabled = new BindableBool();
private readonly CountdownButton countdownButton;
private int countReady; private int countReady;
private ScheduledDelegate readySampleDelegate; private ScheduledDelegate readySampleDelegate;
private IBindable<bool> operationInProgress; private IBindable<bool> operationInProgress;
public MultiplayerReadyButton() public MultiplayerReadyButton()
{ {
InternalChild = readyButton = new ReadyButton InternalChild = new GridContainer
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Size = Vector2.One, ColumnDimensions = new[]
Action = onReadyClick, {
Enabled = { Value = true }, new Dimension(),
new Dimension(GridSizeMode.AutoSize)
},
Content = new[]
{
new Drawable[]
{
new ReadyButton
{
RelativeSizeAxes = Axes.Both,
Size = Vector2.One,
Action = onReadyClick,
Enabled = { BindTarget = enabled },
},
countdownButton = new CountdownButton
{
RelativeSizeAxes = Axes.Y,
Size = new Vector2(40, 1),
Alpha = 0,
Action = startCountdown,
Enabled = { BindTarget = enabled }
}
}
}
}; };
} }
@ -111,6 +144,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
}); });
} }
private void startCountdown(TimeSpan duration)
{
}
private void endOperation() private void endOperation()
{ {
clickOperation?.Dispose(); clickOperation?.Dispose();
@ -121,7 +158,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
{ {
if (Room == null) if (Room == null)
{ {
readyButton.Enabled.Value = false; enabled.Value = false;
return; return;
} }
@ -130,7 +167,19 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
int newCountReady = Room.Users.Count(u => u.State == MultiplayerUserState.Ready); int newCountReady = Room.Users.Count(u => u.State == MultiplayerUserState.Ready);
int newCountTotal = Room.Users.Count(u => u.State != MultiplayerUserState.Spectating); int newCountTotal = Room.Users.Count(u => u.State != MultiplayerUserState.Spectating);
readyButton.Enabled.Value = switch (localUser?.State)
{
default:
countdownButton.Alpha = 0;
break;
case MultiplayerUserState.Spectating:
case MultiplayerUserState.Ready:
countdownButton.Alpha = Room.Host?.Equals(localUser) == true ? 1 : 0;
break;
}
enabled.Value =
Room.State == MultiplayerRoomState.Open Room.State == MultiplayerRoomState.Open
&& CurrentPlaylistItem.Value?.ID == Room.Settings.PlaylistItemId && CurrentPlaylistItem.Value?.ID == Room.Settings.PlaylistItemId
&& !Room.Playlist.Single(i => i.ID == Room.Settings.PlaylistItemId).Expired && !Room.Playlist.Single(i => i.ID == Room.Settings.PlaylistItemId).Expired
@ -138,7 +187,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
// When the local user is the host and spectating the match, the "start match" state should be enabled if any users are ready. // When the local user is the host and spectating the match, the "start match" state should be enabled if any users are ready.
if (localUser?.State == MultiplayerUserState.Spectating) if (localUser?.State == MultiplayerUserState.Spectating)
readyButton.Enabled.Value &= Room.Host?.Equals(localUser) == true && newCountReady > 0; enabled.Value &= Room.Host?.Equals(localUser) == true && newCountReady > 0;
if (newCountReady == countReady) if (newCountReady == countReady)
return; return;
@ -269,5 +318,72 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
multiplayerClient.RoomUpdated -= onRoomUpdated; multiplayerClient.RoomUpdated -= onRoomUpdated;
} }
} }
public class CountdownButton : IconButton, IHasPopover
{
private static readonly TimeSpan[] available_delays =
{
TimeSpan.FromSeconds(10),
TimeSpan.FromSeconds(30),
TimeSpan.FromMinutes(1),
TimeSpan.FromMinutes(2)
};
public new Action<TimeSpan> Action;
private readonly Drawable background;
public CountdownButton()
{
Icon = FontAwesome.Solid.CaretDown;
IconScale = new Vector2(0.6f);
Add(background = new Box
{
RelativeSizeAxes = Axes.Both,
Depth = float.MaxValue
});
base.Action = this.ShowPopover;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
background.Colour = colours.Green;
}
public Popover GetPopover()
{
var flow = new FillFlowContainer
{
Width = 200,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(2),
};
foreach (var duration in available_delays)
{
flow.Add(new PopoverButton
{
RelativeSizeAxes = Axes.X,
Text = $"Start match in {duration.Humanize()}",
BackgroundColour = background.Colour,
Action = () =>
{
Action(duration);
this.HidePopover();
}
});
}
return new OsuPopover { Child = flow };
}
public class PopoverButton : OsuButton
{
}
}
} }
} }