1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 10:12:54 +08:00

Implement TabbableOnlineOverlay component

This commit is contained in:
Andrei Zavatski 2021-01-18 21:22:50 +03:00
parent 70420b56d3
commit c6b0f3c247
3 changed files with 116 additions and 123 deletions

View File

@ -2,115 +2,35 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Online.API;
using osu.Game.Overlays.Dashboard;
using osu.Game.Overlays.Dashboard.Friends;
namespace osu.Game.Overlays
{
public class DashboardOverlay : OnlineOverlay<DashboardOverlayHeader>
public class DashboardOverlay : TabbableOnlineOverlay<DashboardOverlayHeader, DashboardOverlayTabs>
{
private CancellationTokenSource cancellationToken;
public DashboardOverlay()
: base(OverlayColourScheme.Purple)
{
}
private readonly IBindable<APIState> apiState = new Bindable<APIState>();
[BackgroundDependencyLoader]
private void load(IAPIProvider api)
{
apiState.BindTo(api.State);
apiState.BindValueChanged(onlineStateChanged, true);
}
protected override void LoadComplete()
{
base.LoadComplete();
Header.Current.BindValueChanged(onTabChanged);
}
protected override DashboardOverlayHeader CreateHeader() => new DashboardOverlayHeader();
private bool displayUpdateRequired = true;
protected override void PopIn()
protected override void CreateDisplayToLoad(DashboardOverlayTabs tab)
{
base.PopIn();
// We don't want to create a new display on every call, only when exiting from fully closed state.
if (displayUpdateRequired)
{
Header.Current.TriggerChange();
displayUpdateRequired = false;
}
}
protected override void PopOutComplete()
{
base.PopOutComplete();
loadDisplay(Empty());
displayUpdateRequired = true;
}
private void loadDisplay(Drawable display)
{
ScrollFlow.ScrollToStart();
LoadComponentAsync(display, loaded =>
{
if (API.IsLoggedIn)
Loading.Hide();
Child = loaded;
}, (cancellationToken = new CancellationTokenSource()).Token);
}
private void onTabChanged(ValueChangedEvent<DashboardOverlayTabs> tab)
{
cancellationToken?.Cancel();
Loading.Show();
if (!API.IsLoggedIn)
{
loadDisplay(Empty());
return;
}
switch (tab.NewValue)
switch (tab)
{
case DashboardOverlayTabs.Friends:
loadDisplay(new FriendDisplay());
LoadDisplay(new FriendDisplay());
break;
case DashboardOverlayTabs.CurrentlyPlaying:
loadDisplay(new CurrentlyPlayingDisplay());
LoadDisplay(new CurrentlyPlayingDisplay());
break;
default:
throw new NotImplementedException($"Display for {tab.NewValue} tab is not implemented");
throw new NotImplementedException($"Display for {tab} tab is not implemented");
}
}
private void onlineStateChanged(ValueChangedEvent<APIState> state) => Schedule(() =>
{
if (State.Value == Visibility.Hidden)
return;
Header.Current.TriggerChange();
});
protected override void Dispose(bool isDisposing)
{
cancellationToken?.Cancel();
base.Dispose(isDisposing);
}
}
}

View File

@ -8,20 +8,18 @@ using osu.Game.Overlays.Rankings;
using osu.Game.Users;
using osu.Game.Rulesets;
using osu.Game.Online.API;
using System.Threading;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.Rankings.Tables;
namespace osu.Game.Overlays
{
public class RankingsOverlay : OnlineOverlay<RankingsOverlayHeader>
public class RankingsOverlay : TabbableOnlineOverlay<RankingsOverlayHeader, RankingsScope>
{
protected Bindable<Country> Country => Header.Country;
protected Bindable<RankingsScope> Scope => Header.Current;
private APIRequest lastRequest;
private CancellationTokenSource cancellationToken;
[Resolved]
private IAPIProvider api { get; set; }
@ -34,11 +32,6 @@ namespace osu.Game.Overlays
{
}
[BackgroundDependencyLoader]
private void load()
{
}
protected override void LoadComplete()
{
base.LoadComplete();
@ -54,6 +47,8 @@ namespace osu.Game.Overlays
Scheduler.AddOnce(loadNewContent);
});
// Unbind events from scope so base class event will not be called
Scope.UnbindEvents();
Scope.BindValueChanged(_ =>
{
// country filtering is only valid for performance scope.
@ -70,8 +65,6 @@ namespace osu.Game.Overlays
Scheduler.AddOnce(loadNewContent);
});
Scheduler.AddOnce(loadNewContent);
}
protected override RankingsOverlayHeader CreateHeader() => new RankingsOverlayHeader();
@ -92,16 +85,13 @@ namespace osu.Game.Overlays
Show();
}
private void loadNewContent()
protected override void CreateDisplayToLoad(RankingsScope tab)
{
Loading.Show();
cancellationToken?.Cancel();
lastRequest?.Cancel();
if (Scope.Value == RankingsScope.Spotlights)
{
loadContent(new SpotlightsLayout
LoadDisplay(new SpotlightsLayout
{
Ruleset = { BindTarget = ruleset }
});
@ -113,12 +103,12 @@ namespace osu.Game.Overlays
if (request == null)
{
loadContent(null);
LoadDisplay(Empty());
return;
}
request.Success += () => Schedule(() => loadContent(createTableFromResponse(request)));
request.Failure += _ => Schedule(() => loadContent(null));
request.Success += () => Schedule(() => LoadDisplay(createTableFromResponse(request)));
request.Failure += _ => Schedule(() => LoadDisplay(Empty()));
api.Queue(request);
}
@ -163,29 +153,11 @@ namespace osu.Game.Overlays
return null;
}
private void loadContent(Drawable content)
{
ScrollFlow.ScrollToStart();
if (content == null)
{
Clear();
Loading.Hide();
return;
}
LoadComponentAsync(content, loaded =>
{
Loading.Hide();
Child = loaded;
}, (cancellationToken = new CancellationTokenSource()).Token);
}
private void loadNewContent() => OnTabChanged(Scope.Value);
protected override void Dispose(bool isDisposing)
{
lastRequest?.Cancel();
cancellationToken?.Cancel();
base.Dispose(isDisposing);
}
}

View 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 System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Online.API;
namespace osu.Game.Overlays
{
public abstract class TabbableOnlineOverlay<THeader, TEnum> : OnlineOverlay<THeader>
where THeader : TabControlOverlayHeader<TEnum>
{
private readonly IBindable<APIState> apiState = new Bindable<APIState>();
private CancellationTokenSource cancellationToken;
private bool displayUpdateRequired = true;
protected TabbableOnlineOverlay(OverlayColourScheme colourScheme)
: base(colourScheme)
{
}
[BackgroundDependencyLoader]
private void load(IAPIProvider api)
{
apiState.BindTo(api.State);
apiState.BindValueChanged(onlineStateChanged, true);
}
protected override void LoadComplete()
{
base.LoadComplete();
Header.Current.BindValueChanged(tab => OnTabChanged(tab.NewValue));
}
protected override void PopIn()
{
base.PopIn();
// We don't want to create a new display on every call, only when exiting from fully closed state.
if (displayUpdateRequired)
{
Header.Current.TriggerChange();
displayUpdateRequired = false;
}
}
protected override void PopOutComplete()
{
base.PopOutComplete();
LoadDisplay(Empty());
displayUpdateRequired = true;
}
protected void LoadDisplay(Drawable display)
{
ScrollFlow.ScrollToStart();
LoadComponentAsync(display, loaded =>
{
if (API.IsLoggedIn)
Loading.Hide();
Child = loaded;
}, (cancellationToken = new CancellationTokenSource()).Token);
}
protected void OnTabChanged(TEnum tab)
{
cancellationToken?.Cancel();
Loading.Show();
if (!API.IsLoggedIn)
{
LoadDisplay(Empty());
return;
}
CreateDisplayToLoad(tab);
}
protected abstract void CreateDisplayToLoad(TEnum tab);
private void onlineStateChanged(ValueChangedEvent<APIState> state) => Schedule(() =>
{
if (State.Value == Visibility.Hidden)
return;
Header.Current.TriggerChange();
});
protected override void Dispose(bool isDisposing)
{
cancellationToken?.Cancel();
base.Dispose(isDisposing);
}
}
}