wip: misskey Welcome screen

This commit is contained in:
こけっち 2022-07-03 22:27:49 +09:00
parent 51966c4472
commit c89bbf757f
No known key found for this signature in database
GPG Key ID: 21460619C5FC4DD1
12 changed files with 485 additions and 66 deletions

View File

@ -167,6 +167,8 @@ namespace osu.Game.Configuration
SetDefault(OsuSetting.DiscordRichPresence, DiscordRichPresenceMode.Full);
SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f);
SetDefault(OsuSetting.MisskeyToken, string.Empty);
}
public IDictionary<OsuSetting, string> GetLoggableState() =>

View File

@ -199,8 +199,9 @@ namespace osu.Game.Online.MisskeyAPI
// The Success callback event is fired on the main thread, so we should wait for that to run before proceeding.
// Without this, we will end up circulating this Connecting loop multiple times and queueing up many web requests
// before actually going online.
while (State.Value > APIState.Offline && State.Value < APIState.Online)
Thread.Sleep(500);
// while (State.Value > APIState.Offline && State.Value < APIState.Online)
// Thread.Sleep(500);
break;
}
@ -264,11 +265,6 @@ namespace osu.Game.Online.MisskeyAPI
// public IHubClientConnector GetHubConnector(string clientName, string endpoint, bool preferMessagePack) =>
// new HubClientConnector(clientName, endpoint, this, versionHash, preferMessagePack);
public IHubClientConnector GetHubConnector(string clientName, string endpoint, bool preferMessagePack = true)
{
throw new NotImplementedException();
}
public RegistrationRequest.RegistrationRequestErrors CreateAccount(string email, string username, string password)
{
Debug.Assert(State.Value == APIState.Offline);
@ -398,11 +394,11 @@ namespace osu.Game.Online.MisskeyAPI
{
lock (queue)
{
if (state.Value == APIState.Offline)
{
request.Fail(new WebException(@"User not logged in"));
return;
}
// if (state.Value == APIState.Offline)
// {
// request.Fail(new WebException(@"User not logged in"));
// return;
// }
queue.Enqueue(request);
}

View File

@ -123,8 +123,16 @@ namespace osu.Game.Online.MisskeyAPI
if (isFailing) return;
Logger.Log($@"Performing request {this}", LoggingTarget.Network);
WebRequest.Perform();
try
{
Logger.Log($@"Performing request {this}", LoggingTarget.Network);
WebRequest.Perform();
}
catch (OperationCanceledException)
{
// ignore this. internally Perform is running async and the fail state may have changed since
// the last check of `isFailing` above.
}
if (isFailing) return;

View File

@ -0,0 +1,124 @@
// 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.
#nullable disable
using System;
using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Online.MisskeyAPI.Requests.Responses;
using osu.Game.Users;
namespace osu.Game.Online.MisskeyAPI
{
public class DummyAPIAccess : Component//, IAPIProvider
{
public const string DUMMY_USER_ID = "1001";
public Bindable<MisskeyAPI.Requests.Responses.I> LocalUser { get; } = new Bindable<MisskeyAPI.Requests.Responses.I>(new MisskeyAPI.Requests.Responses.I
{
Username = @"Dummy",
Id = "DUMMY_USER_ID",
});
public BindableList<MisskeyAPI.Requests.Responses.I> Friends { get; } = new BindableList<MisskeyAPI.Requests.Responses.I>();
public Bindable<UserActivity> Activity { get; } = new Bindable<UserActivity>();
public string AccessToken => "token";
public bool IsLoggedIn => State.Value == APIState.Online;
public string ProvidedUsername => LocalUser.Value.Username;
public string APIEndpointUrl => "http://localhost";
public string WebsiteRootUrl => "http://localhost";
public int APIVersion => int.Parse(DateTime.Now.ToString("yyyyMMdd"));
public Exception LastLoginError { get; private set; }
/// <summary>
/// Provide handling logic for an arbitrary API request.
/// Should return true is a request was handled. If null or false return, the request will be failed with a <see cref="NotSupportedException"/>.
/// </summary>
public Func<APIRequest, bool> HandleRequest;
private readonly Bindable<APIState> state = new Bindable<APIState>(APIState.Online);
private bool shouldFailNextLogin;
/// <summary>
/// The current connectivity state of the API.
/// </summary>
public IBindable<APIState> State => state;
public DummyAPIAccess()
{
}
public virtual void Queue(APIRequest request)
{
Schedule(() =>
{
if (HandleRequest?.Invoke(request) != true)
{
request.Fail(new InvalidOperationException($@"{nameof(DummyAPIAccess)} cannot process this request."));
}
});
}
public void Perform(APIRequest request) => HandleRequest?.Invoke(request);
public Task PerformAsync(APIRequest request)
{
HandleRequest?.Invoke(request);
return Task.CompletedTask;
}
public void Login(string username, string password)
{
state.Value = APIState.Connecting;
if (shouldFailNextLogin)
{
LastLoginError = new APIException("Not powerful enough to login.", new ArgumentException(nameof(shouldFailNextLogin)));
state.Value = APIState.Offline;
shouldFailNextLogin = false;
return;
}
LastLoginError = null;
LocalUser.Value = new MisskeyAPI.Requests.Responses.I
{
Username = username,
Id = "1001",
};
state.Value = APIState.Online;
}
public void Logout()
{
state.Value = APIState.Offline;
}
public IHubClientConnector GetHubConnector(string clientName, string endpoint, bool preferMessagePack) => null;
public RegistrationRequest.RegistrationRequestErrors CreateAccount(string email, string username, string password)
{
Thread.Sleep(200);
return null;
}
public void SetState(APIState newState) => state.Value = newState;
// IBindable<UserActivity> IAPIProvider.Activity => Activity;
public void FailNextLogin() => shouldFailNextLogin = true;
}
}

View File

@ -103,13 +103,13 @@ namespace osu.Game.Online.MisskeyAPI
/// </summary>
void Logout();
/// <summary>
/// Constructs a new <see cref="IHubClientConnector"/>. May be null if not supported.
/// </summary>
/// <param name="clientName">The name of the client this connector connects for, used for logging.</param>
/// <param name="endpoint">The endpoint to the hub.</param>
/// <param name="preferMessagePack">Whether to use MessagePack for serialisation if available on this platform.</param>
IHubClientConnector? GetHubConnector(string clientName, string endpoint, bool preferMessagePack = true);
// /// <summary>
// /// Constructs a new <see cref="IHubClientConnector"/>. May be null if not supported.
// /// </summary>
// /// <param name="clientName">The name of the client this connector connects for, used for logging.</param>
// /// <param name="endpoint">The endpoint to the hub.</param>
// /// <param name="preferMessagePack">Whether to use MessagePack for serialisation if available on this platform.</param>
// IHubClientConnector? GetHubConnector(string clientName, string endpoint, bool preferMessagePack = true);
/// <summary>
/// Create a new user account. This is a blocking operation.

View File

@ -1,18 +1,17 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>, sim1222 <kokt@sim1222.com>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Net.Http;
using osu.Framework.IO.Network;
namespace osu.Game.Online.MisskeyAPI.Requests
{
public class Meta : APIRequest<MisskeyAPI.Requests.Responses.Meta>
public class Meta : APIRequest
{
public string instanceUrl { get; }
public Meta(string instanceUrl)
public Meta()
{
this.instanceUrl = instanceUrl;
}
protected override WebRequest CreateWebRequest()
@ -22,7 +21,7 @@ namespace osu.Game.Online.MisskeyAPI.Requests
return req;
}
public string APIEndpointUrl => $"https://{instanceUrl}";
protected override string Uri => $@"https://misskey.io/api/meta";
protected override string Target => @"meta";
}
}

View File

@ -40,6 +40,7 @@ using osu.Game.Input.Bindings;
using osu.Game.IO;
using osu.Game.Online;
using osu.Game.Online.API;
using osu.Game.Online.MisskeyAPI;
using osu.Game.Online.Chat;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Spectator;
@ -88,9 +89,11 @@ namespace osu.Game
public virtual bool UseDevelopmentServer => DebugUtils.IsDebugBuild;
internal EndpointConfiguration CreateEndpoints() =>
internal Online.EndpointConfiguration CreateEndpoints() =>
UseDevelopmentServer ? new DevelopmentEndpointConfiguration() : new ProductionEndpointConfiguration();
internal Online.MisskeyAPI.EndpointConfiguration CreateMisskeyEndpoints() => new osu.Game.Online.MisskeyAPI.DefaultEndpointConfigration();
public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version();
/// <summary>
@ -142,7 +145,9 @@ namespace osu.Game
protected MusicController MusicController { get; private set; }
protected IAPIProvider API { get; set; }
protected Online.API.IAPIProvider API { get; set; }
protected Online.MisskeyAPI.IAPIProvider MisskeyAPI { get; set; }
protected Storage Storage { get; set; }
@ -257,11 +262,13 @@ namespace osu.Game
dependencies.Cache(SkinManager = new SkinManager(Storage, realm, Host, Resources, Audio, Scheduler));
dependencies.CacheAs<ISkinSource>(SkinManager);
EndpointConfiguration endpoints = CreateEndpoints();
Online.EndpointConfiguration endpoints = CreateEndpoints();
osu.Game.Online.MisskeyAPI.EndpointConfiguration misskeyendpoints = CreateMisskeyEndpoints();
MessageFormatter.WebsiteRootUrl = endpoints.WebsiteRootUrl;
dependencies.CacheAs(API ??= new APIAccess(LocalConfig, endpoints, VersionHash));
dependencies.CacheAs(API ??= new Online.API.APIAccess(LocalConfig, endpoints, VersionHash));
dependencies.CacheAs(MisskeyAPI ??= new Online.MisskeyAPI.APIAccess(LocalConfig, misskeyendpoints, VersionHash));
dependencies.CacheAs(spectatorClient = new OnlineSpectatorClient(endpoints));
dependencies.CacheAs(multiplayerClient = new OnlineMultiplayerClient(endpoints));
@ -314,8 +321,10 @@ namespace osu.Game
dependencies.CacheAs(Beatmap);
// add api components to hierarchy.
if (API is APIAccess apiAccess)
if (API is Online.API.APIAccess apiAccess)
AddInternal(apiAccess);
if (MisskeyAPI is Online.MisskeyAPI.APIAccess misskeyAPIAccess)
AddInternal(misskeyAPIAccess);
AddInternal(spectatorClient);
AddInternal(multiplayerClient);

View File

@ -0,0 +1,48 @@
// Copyright (c) sim1222 <kokt@sim1222.com>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osuTK;
namespace osu.Game.Screens.Misskey.Components
{
public class PopupButton : IconButton
{
public PopupButton()
{
AutoSizeAxes = Axes.Both;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
HoverColour = colours.YellowDark.Opacity(0.6f);
FlashColour = colours.Yellow;
}
protected override void LoadComplete()
{
base.LoadComplete();
// works with AutoSizeAxes above to make buttons autosize with the scale animation.
Content.AutoSizeAxes = Axes.None;
Content.Size = new Vector2(DEFAULT_BUTTON_SIZE);
}
}
// Hou to use
// private IconButton playlistButton;
// playlistButton = new PopupButton
// {
// Origin = Anchor.Centre,
// Anchor = Anchor.CentreRight,
// Position = new Vector2(-bottom_black_area_height / 2, 0),
// Icon = FontAwesome.Solid.Bars,
// Action = togglePlaylist
// },
}

View File

@ -11,12 +11,15 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osuTK.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Logging;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.MisskeyAPI;
using osu.Game.Online.MisskeyAPI.Requests;
using osu.Game.Online.MisskeyAPI.Requests.Responses;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
using osuTK;
using Meta = osu.Game.Online.MisskeyAPI.Requests.Meta;
@ -34,13 +37,17 @@ namespace osu.Game.Screens.Misskey
// [Resolved]
private IAPIProvider api { get; set; }
// private Meta getMeta;
private Online.MisskeyAPI.Requests.Meta request;
[Resolved]
private INotificationOverlay notificationOverlay { get; set; }
[Resolved]
private OsuColour colours { get; set; }
[BackgroundDependencyLoader(true)]
private void load()
private void load(IAPIProvider api, INotificationOverlay notifications)
{
InternalChild = contentContainer = new Container
{
@ -104,14 +111,22 @@ namespace osu.Game.Screens.Misskey
private void insetanceFetch()
{
var getMeta = new Meta(searchTextBox.Text);
request = new Meta();
getMeta.Success += response =>
request.Success += () =>
{
Logger.Log($"{response}");
};
api.Queue(getMeta);
request.Failure += e =>
{
notificationOverlay?.Post(new SimpleNotification
{
Text = e.Message,
Icon = FontAwesome.Solid.Times,
});
};
api.Queue(request);
}
}
}

View File

@ -11,6 +11,8 @@ using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Screens;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Dashboard.Friends;
using osuTK;
using osuTK.Graphics;
@ -18,8 +20,10 @@ namespace osu.Game.Screens.Misskey
{
public class MisskeyScreenSelector : OsuScreen
{
private Box background;
private Container contentContainer;
[Resolved]
private OsuGameBase game { get; set; }
@ -29,48 +33,75 @@ namespace osu.Game.Screens.Misskey
[BackgroundDependencyLoader(true)]
private void load()
{
InternalChild = contentContainer = new Container()
InternalChild = contentContainer = new Container
{
Masking = true,
CornerRadius = 10,
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(0.9f, 0.8f),
Children = new Drawable[]
{
new Box
{
Colour = colours.GreySeaFoamDark,
RelativeSizeAxes = Axes.Both,
},
new Container
{
RelativeSizeAxes = Axes.Both,
//Width = 0.35f,
Anchor = Anchor.TopLeft,
Origin = Anchor.TopLeft,
Name = "List",
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Children = new Drawable[]
{
new BasicButton()
background = new Box
{
Text = "MisskeyLogin",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.X,
Height = 60f,
Width = 0.9f,
Action = () => this.Push(new MisskeyLogin())
RelativeSizeAxes = Axes.Both,
Colour = colours.Gray9
},
new BasicButton()
new FillFlowContainer
{
Text = "MisskeyInstanceSelect",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.X,
Height = 60f,
Width = 0.9f,
Action = () => this.Push(new MisskeyInstanceSelect())
AutoSizeAxes = Axes.Y,
Margin = new MarginPadding { Bottom = 20 },
Children = new Drawable[]
{
//ここに足す
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding
{
Horizontal = 40,
Vertical = 20
},
Child = new OsuButton()
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(500f, 50f),
Text = "MisskeyInstanceSelect",
Action = () => this.Push(new MisskeyInstanceSelect())
}
},
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding
{
Horizontal = 40,
Vertical = 20
},
Child = new OsuButton()
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(500f, 50f),
Text = "Welcome",
Action = () => this.Push(new Welcome())
}
},
}
}
}
}

View File

@ -0,0 +1,187 @@
// Copyright (c) sim1222 <kokt@sim1222.com>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
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.UserInterface;
using osu.Framework.Screens;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays;
using osu.Game.Screens.Misskey.Components;
using osu.Game.Screens.Select;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Screens.Misskey
{
public class Welcome : OsuScreen
{
private Container carouselContainer;
private IconButton aboutButton;
[BackgroundDependencyLoader(true)]
private void load()
{
InternalChild = new Container
{
Masking = true,
CornerRadius = 10,
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Children = new Drawable[]
{
new GridContainer // used for max width implementation
{
Name = "ParrallaxBackgroundShape",
RelativeSizeAxes = Axes.Both,
ColumnDimensions = new[]
{
new Dimension(),
new Dimension(GridSizeMode.Relative, 0.5f, maxSize: 850),
},
Content = new[]
{
new Drawable[]
{
new ParallaxContainer
{
ParallaxAmount = 0.005f,
RelativeSizeAxes = Axes.Both,
Child = new WedgeBackground
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Right = -150 },
},
},
carouselContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding
{
Top = FilterControl.HEIGHT,
Bottom = Footer.HEIGHT
},
Child = new LoadingSpinner(true) { State = { Value = Visibility.Visible } }
}
},
}
},
new Container()
{
Name = "Panel",
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Width = 500f,
Height = 500f,
Margin = new MarginPadding(80),
CornerRadius = 10,
Masking = true,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(60),
Radius = 30,
},
Children = new Drawable[]
{
new Box()
{
Name = "BackGround",
RelativeSizeAxes = Axes.Both,
Colour = Colour4.DarkSlateGray,
Width = 1f,
Height = 1f,
},
new OsuSpriteText()
{
Name = "InsetanceName",
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Margin = new MarginPadding(50),
Text = "Misskey",
Font = new FontUsage(size: 30),
Colour = Colour4.White,
},
aboutButton = new PopupButton
{
Origin = Anchor.TopRight,
Anchor = Anchor.TopRight,
Margin = new MarginPadding(20),
Position = new Vector2(0),
Icon = FontAwesome.Solid.EllipsisH,
// Action = () => OsuMenu.Empty()
// TODO: コンテキストメニューの実装
},
new OsuSpriteText()
{
Name = "InsetanceInfo",
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Margin = new MarginPadding(100),
Width = 400f,
Text = "Misskey.io は、地球で生まれた分散マイクロブログSNSです。Fediverse様々なSNSで構成される宇宙の中に存在するため、他のSNSと相互に繋がっています。\n暫し都会の喧騒から離れて、新しいインターネットにダイブしてみませんか。",
Font = new FontUsage(size: 20),
Colour = Colour4.White,
},
new GridContainer()
{
Name = "Buttons",
RelativeSizeAxes = Axes.Both,
Position = new Vector2(0, 300),
ColumnDimensions = new[]
{
new Dimension(),
new Dimension(GridSizeMode.Relative, 0.5f, maxSize: 850),
},
Content = new[]
{
new Drawable[]
{
new OsuButton()
{
Name = "SignUpButton",
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Width = 100f,
Text = "新規登録"
},
new OsuButton()
{
Name = "SignInButton",
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Width = 100f,
Text = "ログイン"
},
}
},
// TODO: 横棒
// TODO: インスタンス情報の表示(ユーザー数など)
}
}
}
}
};
}
public override void OnResuming(ScreenTransitionEvent e)
{
base.OnResuming(e);
this.FadeIn(250);
this.ScaleTo(1, 250, Easing.OutSine);
}
}
}

View File

@ -22,7 +22,7 @@ namespace osu.Game.Screens.Select
{
RelativeSizeAxes = Axes.Both,
Size = new Vector2(1, 0.5f),
Colour = Color4.Black.Opacity(0.5f),
Colour = Color4.GreenYellow,
Shear = new Vector2(0.15f, 0),
EdgeSmoothness = new Vector2(2, 0),
},
@ -32,7 +32,7 @@ namespace osu.Game.Screens.Select
RelativePositionAxes = Axes.Y,
Size = new Vector2(1, -0.5f),
Position = new Vector2(0, 1),
Colour = Color4.Black.Opacity(0.5f),
Colour = Color4.GreenYellow,
Shear = new Vector2(-0.15f, 0),
EdgeSmoothness = new Vector2(2, 0),
},