Port Main Menu

This commit is contained in:
Ritchie Frodomar 2024-07-14 20:44:13 -04:00
parent 711096b258
commit 3b0c3a2f09
9 changed files with 344 additions and 13 deletions

View file

@ -328,6 +328,9 @@ public sealed class GuiManager : IFontFamilyProvider
foreach (Widget widget in CollapseChildren())
{
if (!widget.IsVisible)
continue;
if (widget is not IMouseHandler)
continue;

View file

@ -804,7 +804,7 @@ public class TextWidget : Widget
);
}
private class MarkupData
private struct MarkupData
{
public int Length;
public Color? ColorOverride;

View file

@ -19,6 +19,8 @@ public partial class Widget
private Point previousAvailableSize;
private Visibility visibility;
public bool IsVisible => this.Visibility == Visibility.Visible && (Parent == null || Parent.IsVisible);
public Visibility Visibility
{
get => visibility;

View file

@ -34,6 +34,27 @@ namespace SociallyDistant.Core.Core
public static readonly string PlayerHomeId = "player";
public static string CreateFormattedDataMarkup(Dictionary<string, string> data)
{
var builder = new StringBuilder();
var isFirst = true;
foreach (string key in data.Keys)
{
if (!isFirst)
builder.AppendLine();
isFirst = false;
builder.Append("<color=#858585>");
builder.Append(key);
builder.Append(":</color> ");
builder.Append(data[key]);
}
return builder.ToString();
}
public static string GetDayOfWeek(DayOfWeek day)
{
return day switch

View file

@ -17,6 +17,7 @@ using SociallyDistant.Core.UI;
using SociallyDistant.Player;
using SociallyDistant.UI.Common;
using SociallyDistant.UI.InfoWidgets;
using SociallyDistant.UI.MainMenu;
using SociallyDistant.UI.Settings;
using SociallyDistant.UI.Shell;
using SociallyDistant.UI.Windowing;
@ -26,7 +27,7 @@ namespace SociallyDistant.UI;
public class GuiController : GameComponent,
IShellContext
{
private readonly IGameContext context;
private readonly SociallyDistantGame context;
private readonly NotificationManager notificationManager;
private readonly FlexPanel mainPanel = new();
private readonly StatusBar statusBar;
@ -45,7 +46,7 @@ public class GuiController : GameComponent,
public StatusBar StatusBar => statusBar;
public IGameContext Context => context;
public GuiController(IGameContext game, PlayerManager playerManager) : base(game.GameInstance)
internal GuiController(SociallyDistantGame game, PlayerManager playerManager) : base(game.GameInstance)
{
this.context = game;
@ -100,22 +101,34 @@ public class GuiController : GameComponent,
private void OnGameModeChanged(GameMode gameMode)
{
trayModel.UpdateGameMode(gameMode);
if (gameMode == GameMode.OnDesktop)
{
this.desktop = new Desktop(desktopController);
this.mainBox.Content = desktop;
mainBox.Content = null;
desktopController.Login();
desktopController.InfoPanelController.ShowClock = true;
}
else
if (gameMode != GameMode.OnDesktop)
{
desktopController.InfoPanelController.ShowClock = false;
desktopController.Logout();
mainBox.Content = null;
desktop?.Dispose();
}
switch (gameMode)
{
case GameMode.OnDesktop:
{
this.desktop = new Desktop(desktopController);
this.mainBox.Content = desktop;
desktopController.Login();
desktopController.InfoPanelController.ShowClock = true;
break;
}
case GameMode.AtLoginScreen:
{
var menu = new LoginScreen(context);
mainBox.Content = menu;
menu.Start();
break;
}
}
}
public override void Update(GameTime gameTime)

View file

@ -0,0 +1,38 @@
using AcidicGUI.ListAdapters;
using AcidicGUI.Widgets;
using SociallyDistant.Core.Modules;
namespace SociallyDistant.UI.MainMenu;
public sealed class LoginListADapter : ListAdapter<ScrollView, LoginUserViewHolder>
{
private readonly DataHelper<IGameData> gameData;
public event Action<IGameData>? OnShowUser;
public LoginListADapter()
{
gameData = new DataHelper<IGameData>(this);
}
public void SetUsers(IEnumerable<IGameData> source)
{
gameData.SetItems(source);
}
protected override LoginUserViewHolder CreateViewHolder(int itemIndex, Box rootWidget)
{
return new LoginUserViewHolder(itemIndex, rootWidget);
}
protected override void UpdateView(LoginUserViewHolder viewHolder)
{
viewHolder.UpdateView(gameData[viewHolder.ItemIndex]);
viewHolder.Callback = ShowUser;
}
private void ShowUser(IGameData user)
{
OnShowUser?.Invoke(user);
}
}

View file

@ -0,0 +1,167 @@
using System.Globalization;
using AcidicGUI.Layout;
using AcidicGUI.TextRendering;
using AcidicGUI.Widgets;
using Microsoft.Xna.Framework;
using SociallyDistant.Core.Core;
using SociallyDistant.Core.Modules;
using SociallyDistant.Core.Shell;
using SociallyDistant.Core.UI.Common;
using SociallyDistant.Core.UI.Effects;
using SociallyDistant.Core.UI.VisualStyles;
namespace SociallyDistant.UI.MainMenu;
public class LoginScreen : Widget
{
private readonly SociallyDistantGame game;
private readonly OverlayWidget overlay = new();
private readonly StackPanel versionArea = new();
private readonly StackPanel mainArea = new();
private readonly TextWidget versionText = new();
private readonly StackPanel usersArea = new();
private readonly Image gameLogo = new();
private readonly TextWidget title = new();
private readonly TextWidget prompt = new();
private readonly Box userBox = new();
private readonly TextButton createNewUserButton = new();
private readonly StackPanel currentUserStack = new();
private readonly Avatar currentUserAvatar = new();
private readonly TextWidget currentUserName = new();
private readonly TextWidget currentUserInfo = new();
private readonly TextButton loginButtonn = new();
private readonly TextButton switchUserButton = new();
private readonly ToolbarIcon userOptionsButton = new();
private readonly StackPanel currentUserInfoStack = new();
private readonly LoginListADapter usersList = new();
private readonly WrapPanel userOptionsArea = new();
private IGameData? currentProfile;
internal LoginScreen(SociallyDistantGame game)
{
currentUserInfo.UseMarkup = true;
currentUserInfo.WordWrapping = true;
userOptionsArea.Direction = Direction.Horizontal;
userOptionsArea.SpacingX = 3;
userOptionsArea.Padding = new Padding(0, 3, 0, 0);
currentUserName.FontWeight = FontWeight.Bold;
currentUserAvatar.AvatarSize = 72;
currentUserStack.Direction = Direction.Horizontal;
createNewUserButton.Text = "Create New User";
switchUserButton.Text = "Switch User";
loginButtonn.Text = "Log in";
userOptionsButton.Icon = MaterialIcons.Settings;
title.FontSize = 36;
prompt.FontSize = 20;
this.game = game;
overlay.Padding = 16;
versionText.UseMarkup = true;
versionArea.VerticalAlignment = VerticalAlignment.Bottom;
versionArea.HorizontalAlignment = HorizontalAlignment.Left;
mainArea.VerticalAlignment = VerticalAlignment.Middle;
mainArea.HorizontalAlignment = HorizontalAlignment.Left;
usersArea.MaximumSize = new Point(391, 320);
usersArea.MinimumSize = new Point(391, 0);
usersArea.SetCustomProperty(WidgetBackgrounds.Overlay);
usersArea.Margin = 12;
Children.Add(overlay);
overlay.ChildWidgets.Add(versionArea);
overlay.ChildWidgets.Add(mainArea);
versionArea.ChildWidgets.Add(gameLogo);
versionArea.ChildWidgets.Add(versionText);
mainArea.ChildWidgets.Add(title);
mainArea.ChildWidgets.Add(prompt);
mainArea.ChildWidgets.Add(usersArea);
usersArea.ChildWidgets.Add(currentUserStack);
usersArea.ChildWidgets.Add(usersList);
mainArea.ChildWidgets.Add(switchUserButton);
mainArea.ChildWidgets.Add(createNewUserButton);
currentUserStack.ChildWidgets.Add(currentUserAvatar);
currentUserStack.ChildWidgets.Add(currentUserInfoStack);
currentUserInfoStack.ChildWidgets.Add(currentUserName);
currentUserInfoStack.ChildWidgets.Add(currentUserInfo);
currentUserInfoStack.ChildWidgets.Add(userOptionsArea);
userOptionsArea.ChildWidgets.Add(loginButtonn);
userOptionsArea.ChildWidgets.Add(userOptionsButton);
switchUserButton.ClickCallback = SwitchUser;
createNewUserButton.ClickCallback = CreateNewUser;
loginButtonn.ClickCallback = LogIn;
}
private async void LogIn()
{
if (currentProfile == null)
return;
await game.StartGame(currentProfile);
}
private void SwitchUser()
{
currentProfile = null;
UpdateView();
}
private async void CreateNewUser()
{
await game.StartCharacterCreator();
}
public void Start()
{
this.RenderEffect = BackgroundBlurWidgetEffect.GetEffect(game);
usersArea.RenderEffect = BackgroundBlurWidgetEffect.GetEffect(game);
versionText.Text = $"version <b>{Application.Instance.Version}</b>";
usersList.OnShowUser += ShowUser;
UpdateView();
}
private void UpdateView()
{
if (currentProfile != null)
{
currentUserStack.Visibility = Visibility.Visible;
switchUserButton.Visibility = Visibility.Visible;
createNewUserButton.Visibility = Visibility.Collapsed;
usersList.Visibility = Visibility.Collapsed;
currentUserName.Text = currentProfile.PlayerInfo.Name;
currentUserInfo.Text = SociallyDistantUtility.CreateFormattedDataMarkup(new Dictionary<string, string>() { { "Last played", currentProfile.PlayerInfo.LastPlayed.ToString(CultureInfo.CurrentCulture) }, { "Mission", currentProfile.PlayerInfo.Comment } });
}
else
{
usersList.SetUsers(game.ContentManager.GetContentOfType<IGameData>().OrderByDescending(x => x.PlayerInfo.LastPlayed));
title.Text = "Welcome";
prompt.Text = "Please log in.";
currentUserStack.Visibility = Visibility.Collapsed;
switchUserButton.Visibility = Visibility.Collapsed;
createNewUserButton.Visibility = Visibility.Visible;
usersList.Visibility = Visibility.Visible;
}
}
private void ShowUser(IGameData user)
{
this.currentProfile = user;
UpdateView();
}
}

View file

@ -0,0 +1,61 @@
using System.Globalization;
using AcidicGUI.CustomProperties;
using AcidicGUI.Layout;
using AcidicGUI.TextRendering;
using AcidicGUI.Widgets;
using SociallyDistant.Core.Core;
using SociallyDistant.Core.Modules;
using SociallyDistant.Core.UI.Common;
namespace SociallyDistant.UI.MainMenu;
public sealed class LoginUserView : Widget
{
private readonly ListItem listItem = new();
private readonly FlexPanel root = new();
private readonly Avatar avatar = new();
private readonly StackPanel textStack = new();
private readonly TextWidget name = new();
private readonly TextWidget info = new();
private IGameData? gameData;
public Action<IGameData>? Callback { get; set; }
public LoginUserView()
{
root.Direction = Direction.Horizontal;
root.Spacing = 6;
name.FontWeight = FontWeight.Bold;
Children.Add(listItem);
listItem.Content = root;
root.ChildWidgets.Add(avatar);
root.ChildWidgets.Add(textStack);
textStack.ChildWidgets.Add(name);
textStack.ChildWidgets.Add(info);
info.WordWrapping = true;
info.UseMarkup = true;
listItem.ClickCallback = OnClick;
avatar.AvatarSize = 48;
}
private void OnClick()
{
if (gameData == null)
return;
this.Callback?.Invoke(gameData);
}
public void UpdateView(IGameData user)
{
this.gameData = user;
name.Text = user.PlayerInfo.Name;
info.Text = SociallyDistantUtility.CreateFormattedDataMarkup(new Dictionary<string, string>() { { "Last played", user.PlayerInfo.LastPlayed.ToString(CultureInfo.CurrentCulture) }, { "Mission", user.PlayerInfo.Comment } });
}
}

View file

@ -0,0 +1,26 @@
using AcidicGUI.ListAdapters;
using AcidicGUI.Widgets;
using SociallyDistant.Core.Modules;
namespace SociallyDistant.UI.MainMenu;
public sealed class LoginUserViewHolder : ViewHolder
{
private readonly LoginUserView view = new();
public Action<IGameData>? Callback
{
get => view.Callback;
set => view.Callback = value;
}
public LoginUserViewHolder(int itemIndex, Box root) : base(itemIndex, root)
{
root.Content = view;
}
public void UpdateView(IGameData user)
{
view.UpdateView(user);
}
}