Previously the slider path length would be snapped using the current
beat snap setting on *every* change of the slider path. As it turns out
this is unexpected behaviour in some situations (e.g. when reversing a
path, which is expected to preserve the previous duration, even though
the slider may be technically "unsnapped" at that point in time due to a
different beat snap setting being selected afterwards).
While displaying replays, the colour of the toolbox toggle button would
not match the actual state of the rest of the toolbox, i.e. both buttons
would be white, even though the "playback settings" section was expanded
and as such should have a yellow toggle button.
In the case of the replay player, the failure scenario was as follows:
1. `SettingsToolboxGroup` calls `updateExpanded()` in its BDL to update
the initial state of the toolbox, including the toggle button
colour, by adding a colour fade transform.
2. An ancestor of both the toolbox groups - `PlayerSettingsOverlay`,
which is a `VisibilityContainer` - calls `FinishTransforms(true)` in
its `LoadCompleteAsync()`, therefore instantly applying the colour
from point (1) to the toggle button instantly.
3. However, `IconButton` inherits from `OsuAnimatedButton`. And
`OsuAnimatedButton` changes its colour in `LoadComplete()`, therefore
undoing the instant application from point (2).
This conjunction of circumstances is instrumental to reproducing the
bug, because if the `FinishTransforms(true)` call wasn't there, point
(3) wouldn't matter - the transform would get applied at some
indeterminate point in the future, ignoring the write from
`OsuAnimatedButton`.
As for the fix, move the `updateExpanded()` call in
`SettingsToolboxGroup` to `LoadComplete()` to avoid the above
unfortunate order. Applying initial visual state in `LoadComplete()` is
the idiomatic style of doing things these days anyhow.
Was previously not handled at all, therefore displaying request failures
in the test log output. While that was mostly a red herring and
shouldn't have caused any actual *test* failures, it is still better to
handle this explicitly in a realistic manner.
This has come up multiple times, with mappers citing that they have
muscle memory for mapping based on the centre of the playfield being in
the centre of the window.
The original plan was to have a second toolbar on the right hand side of
the screen to balance the padding, but we're not at that point yet.
Easiest solution is to do what stable does and allow the left-hand
toolbar items to overlap the playfield underneath it.
In edge cases where the user is running at an aspect ratio that causes
overlaps, they can choose to collapse the toolbars down. We can probably
work on this UI/UX a bit more as we update designs to be more friendly
to such cases.
Fixed as per solution at https://github.com/JamesNK/Newtonsoft.Json/issues/874.
Note that due to the use of `JsonExtensionDataAttribute` it's not
feasible to change the actual specification to `JValue` in the
`Dictionary`.
In discussion with the osu-web team, it may be worthwhile to change the cursor
to a string format where parsing is not required at our end. We could already
do this in fact, but there are tests that rely on it being a `JToken` so the
switch to `JValue` seems like the easier path right now.
The beatmap listing content swap-out logic was already a source of
several problems, and several attempts of fixing it were made. But as it
turns out it was terminally broken in several aspects.
* The `BypassAutoSizeAxes` juggling was finicky and ugly, and didn't
really look much different than an instant fade. Therefore, all fade
durations and manipulations of `BypassAutoSizeAxes` are removed.
* The transform sequence juggling the `BypassAutoSizeAxes` manipulations
was enqueued on the content which is being in the process of fading
out. That was partially fixed in 25e38560, but as it turns out, that
only works if `lastContent` is one of the two placeholder drawables
(results not found / supporter required to use filter).
It would not work if `lastContent` is a
`ReverseChildIDFillFlowContainer` with cards from a previous search in
it.
The `lastContent == foundContent` check, last touched in a49a4329, is
terminally broken, as it would always be false. `foundContent` is
mutated when a new card load task is started in `onSearchFinished()`,
which is *before* the aforementioned check.
The code prior to a49a4329 was checking against the two static reused
placeholder drawables which was the correct check to apply, and this
commit reverts to using a variant of that check.
During profile, it was found that the `Completed` delegate was
incorrectly also capturing `lastTrack`, leading to an unexpected
reference chain that led to a memory leak over a long period of time.
This solves the issue by moving the delegate construction to its own
method, where it won't capture the other variables.
`BeatmapListingOverlay.addContentToPlaceholder()`, in order to make
transitions between different beatmap listing content (whether it is
actual cards, or placeholders for no beatmaps found/supporter-specific
filters chosen), would set `BypassAutoSizeAxes = Y` on content as it is
fading out, to make the transition smoother. The property in question
was supposed to be getting restored to `None` on the next show.
In testing scenarios, it sometimes turned out that this wasn't the case,
therefore making the placeholders effectively not show - while they
were present and fully opaque, they would be the only child of
an auto-sized container with `BypassAutoSizeAxes = Y`, so the parent
auto-sized to a zero height, which logically follows from the premise,
but is not what was desired.
This in turn was caused by the fact that the `BypassAutoSizeAxes = Y`
set was scheduled, and sometimes it would be scheduled in such a way
that the drawable would cease to be present on the next frame due to its
alpha being past the cutoff point of 0.0001. Therefore the scheduled set
would not execute until the *next* time the placeholder was shown,
therefore causing the bug.
Fix by ensuring that the placeholder drawables are always present if
their schedulers have any tasks enqueued, on top of the usual checks of
alpha and scale performed via the base implementation.
Specifically, the global `BeatmapInfo` is referenced inside the web
request's success callback, and used to attempt population via methods
which expect non-null beatmap inputs.
Closes#16211.
The task not being cleared in the early return path would cause
`pendingRequestTask` to become stuck as a completed task, and
`queryValue()` would not recreate it due to the null check there,
therefore stalling all lookups forevermore until a game restart.
Currently doesn't really cause any difference, however it may in the
future if we decide the queueing algorithm shouldn't update PlaylistOrder
when an item has been played.