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.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Framework.Utils;
@ -55,15 +56,16 @@ private void load(GameHost host, AudioManager audio)
RulesetID = Beatmap.Value.BeatmapInfo.Ruleset.OnlineID
};
if (button != null)
Remove(button);
Add(button = new MultiplayerReadyButton
Child = new PopoverContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(200, 50),
});
RelativeSizeAxes = Axes.Both,
Child = button = new MultiplayerReadyButton
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(200, 50),
}
};
});
[Test]

View File

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

View File

@ -12,6 +12,7 @@
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Screens;
using osu.Game.Audio;
@ -100,122 +101,126 @@ private void load(AudioManager audio)
{
sampleStart = audio.Samples.Get(@"SongSelect/confirm-selection");
InternalChildren = new Drawable[]
InternalChild = new PopoverContainer
{
beatmapAvailabilityTracker,
new MultiplayerRoomSounds(),
new GridContainer
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
RelativeSizeAxes = Axes.Both,
RowDimensions = new[]
beatmapAvailabilityTracker,
new MultiplayerRoomSounds(),
new GridContainer
{
new Dimension(),
new Dimension(GridSizeMode.Absolute, 50)
},
Content = new[]
{
// Padded main content (drawable room + main content)
new Drawable[]
RelativeSizeAxes = Axes.Both,
RowDimensions = new[]
{
new Container
new Dimension(),
new Dimension(GridSizeMode.Absolute, 50)
},
Content = new[]
{
// Padded main content (drawable room + main content)
new Drawable[]
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding
new Container
{
Horizontal = WaveOverlayContainer.WIDTH_PADDING,
Bottom = 30
},
Children = new[]
{
mainContent = new GridContainer
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding
{
RelativeSizeAxes = Axes.Both,
RowDimensions = new[]
Horizontal = WaveOverlayContainer.WIDTH_PADDING,
Bottom = 30
},
Children = new[]
{
mainContent = new GridContainer
{
new Dimension(GridSizeMode.AutoSize),
new Dimension(GridSizeMode.Absolute, 10)
},
Content = new[]
{
new Drawable[]
RelativeSizeAxes = Axes.Both,
RowDimensions = new[]
{
new DrawableMatchRoom(Room, allowEdit)
{
OnEdit = () => settingsOverlay.Show(),
SelectedItem = { BindTarget = SelectedItem }
}
new Dimension(GridSizeMode.AutoSize),
new Dimension(GridSizeMode.Absolute, 10)
},
null,
new Drawable[]
Content = new[]
{
new Container
new Drawable[]
{
RelativeSizeAxes = Axes.Both,
Children = new[]
new DrawableMatchRoom(Room, allowEdit)
{
new Container
OnEdit = () => settingsOverlay.Show(),
SelectedItem = { BindTarget = SelectedItem }
}
},
null,
new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Children = new[]
{
RelativeSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 10,
Child = new Box
new Container
{
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
{
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
new Container
{
SelectedMods = { BindTarget = UserMods },
IsValidMod = _ => false
}
},
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 },
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
new Drawable[]
{
new Container
// Footer
new Drawable[]
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
new Container
{
new Box
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex(@"28242d") // Temporary.
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(5),
Child = CreateFooter()
},
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex(@"28242d") // Temporary.
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(5),
Child = CreateFooter()
},
}
}
}
}

View File

@ -4,15 +4,24 @@
using System;
using System.Diagnostics;
using System.Linq;
using Humanizer;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
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.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.UserInterface;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Online.Multiplayer;
using osuTK;
@ -30,19 +39,43 @@ public class MultiplayerReadyButton : MultiplayerRoomComposite
private Sample sampleReadyAll;
private Sample sampleUnready;
private readonly ReadyButton readyButton;
private readonly BindableBool enabled = new BindableBool();
private readonly CountdownButton countdownButton;
private int countReady;
private ScheduledDelegate readySampleDelegate;
private IBindable<bool> operationInProgress;
public MultiplayerReadyButton()
{
InternalChild = readyButton = new ReadyButton
InternalChild = new GridContainer
{
RelativeSizeAxes = Axes.Both,
Size = Vector2.One,
Action = onReadyClick,
Enabled = { Value = true },
ColumnDimensions = new[]
{
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 @@ void startMatch() => Client.StartMatch().ContinueWith(t =>
});
}
private void startCountdown(TimeSpan duration)
{
}
private void endOperation()
{
clickOperation?.Dispose();
@ -121,7 +158,7 @@ private void updateState()
{
if (Room == null)
{
readyButton.Enabled.Value = false;
enabled.Value = false;
return;
}
@ -130,7 +167,19 @@ private void updateState()
int newCountReady = Room.Users.Count(u => u.State == MultiplayerUserState.Ready);
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
&& CurrentPlaylistItem.Value?.ID == Room.Settings.PlaylistItemId
&& !Room.Playlist.Single(i => i.ID == Room.Settings.PlaylistItemId).Expired
@ -138,7 +187,7 @@ private void updateState()
// 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)
readyButton.Enabled.Value &= Room.Host?.Equals(localUser) == true && newCountReady > 0;
enabled.Value &= Room.Host?.Equals(localUser) == true && newCountReady > 0;
if (newCountReady == countReady)
return;
@ -269,5 +318,72 @@ protected override void Dispose(bool isDisposing)
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
{
}
}
}
}