Added profile settings for Syncshells.

This commit is contained in:
CakeAndBanana
2025-10-12 20:04:09 +02:00
parent 02a680f8cc
commit be847c16b8
3 changed files with 182 additions and 8 deletions

View File

@@ -1,4 +1,5 @@
using LightlessSync.API.Dto.Group; using Dalamud.Interface.ImGuiFileDialog;
using LightlessSync.API.Dto.Group;
using LightlessSync.PlayerData.Pairs; using LightlessSync.PlayerData.Pairs;
using LightlessSync.Services.Mediator; using LightlessSync.Services.Mediator;
using LightlessSync.Services.ServerConfiguration; using LightlessSync.Services.ServerConfiguration;
@@ -18,10 +19,11 @@ public class UiFactory
private readonly ServerConfigurationManager _serverConfigManager; private readonly ServerConfigurationManager _serverConfigManager;
private readonly LightlessProfileManager _lightlessProfileManager; private readonly LightlessProfileManager _lightlessProfileManager;
private readonly PerformanceCollectorService _performanceCollectorService; private readonly PerformanceCollectorService _performanceCollectorService;
private readonly FileDialogManager _fileDialogManager;
public UiFactory(ILoggerFactory loggerFactory, LightlessMediator lightlessMediator, ApiController apiController, public UiFactory(ILoggerFactory loggerFactory, LightlessMediator lightlessMediator, ApiController apiController,
UiSharedService uiSharedService, PairManager pairManager, ServerConfigurationManager serverConfigManager, UiSharedService uiSharedService, PairManager pairManager, ServerConfigurationManager serverConfigManager,
LightlessProfileManager lightlessProfileManager, PerformanceCollectorService performanceCollectorService) LightlessProfileManager lightlessProfileManager, PerformanceCollectorService performanceCollectorService, FileDialogManager fileDialogManager)
{ {
_loggerFactory = loggerFactory; _loggerFactory = loggerFactory;
_lightlessMediator = lightlessMediator; _lightlessMediator = lightlessMediator;
@@ -31,12 +33,13 @@ public class UiFactory
_serverConfigManager = serverConfigManager; _serverConfigManager = serverConfigManager;
_lightlessProfileManager = lightlessProfileManager; _lightlessProfileManager = lightlessProfileManager;
_performanceCollectorService = performanceCollectorService; _performanceCollectorService = performanceCollectorService;
_fileDialogManager = fileDialogManager;
} }
public SyncshellAdminUI CreateSyncshellAdminUi(GroupFullInfoDto dto) public SyncshellAdminUI CreateSyncshellAdminUi(GroupFullInfoDto dto)
{ {
return new SyncshellAdminUI(_loggerFactory.CreateLogger<SyncshellAdminUI>(), _lightlessMediator, return new SyncshellAdminUI(_loggerFactory.CreateLogger<SyncshellAdminUI>(), _lightlessMediator,
_apiController, _uiSharedService, _pairManager, dto, _performanceCollectorService, _lightlessProfileManager); _apiController, _uiSharedService, _pairManager, dto, _performanceCollectorService, _lightlessProfileManager, _fileDialogManager);
} }
public StandaloneProfileUi CreateStandaloneProfileUi(Pair pair) public StandaloneProfileUi CreateStandaloneProfileUi(Pair pair)

View File

@@ -25,8 +25,8 @@ public class EditProfileUi : WindowMediatorSubscriberBase
private readonly FileDialogManager _fileDialogManager; private readonly FileDialogManager _fileDialogManager;
private readonly LightlessProfileManager _lightlessProfileManager; private readonly LightlessProfileManager _lightlessProfileManager;
private readonly UiSharedService _uiSharedService; private readonly UiSharedService _uiSharedService;
private bool _adjustedForScollBarsLocalProfile = false; private bool _adjustedForScollBarsLocalProfile = false;
private bool _adjustedForScollBarsOnlineProfile = false; private bool _adjustedForScollBarsOnlineProfile = false;
private string _descriptionText = string.Empty; private string _descriptionText = string.Empty;
private IDalamudTextureWrap? _pfpTextureWrap; private IDalamudTextureWrap? _pfpTextureWrap;
private string _profileDescription = string.Empty; private string _profileDescription = string.Empty;

View File

@@ -1,17 +1,24 @@
using Dalamud.Bindings.ImGui; using Dalamud.Bindings.ImGui;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Interface.Colors; using Dalamud.Interface.Colors;
using Dalamud.Interface.ImGuiFileDialog;
using Dalamud.Interface.Textures.TextureWraps;
using Dalamud.Interface.Utility; using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Utility.Raii;
using LightlessSync.API.Data;
using LightlessSync.API.Data.Enum; using LightlessSync.API.Data.Enum;
using LightlessSync.API.Data.Extensions; using LightlessSync.API.Data.Extensions;
using LightlessSync.API.Dto.Group; using LightlessSync.API.Dto.Group;
using LightlessSync.API.Dto.User;
using LightlessSync.PlayerData.Pairs; using LightlessSync.PlayerData.Pairs;
using LightlessSync.Services; using LightlessSync.Services;
using LightlessSync.Services.Mediator; using LightlessSync.Services.Mediator;
using LightlessSync.WebAPI; using LightlessSync.WebAPI;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using System.Globalization; using System.Globalization;
using System.Numerics;
namespace LightlessSync.UI; namespace LightlessSync.UI;
@@ -22,8 +29,17 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
private readonly bool _isOwner = false; private readonly bool _isOwner = false;
private readonly List<string> _oneTimeInvites = []; private readonly List<string> _oneTimeInvites = [];
private readonly PairManager _pairManager; private readonly PairManager _pairManager;
private readonly LightlessProfileManager _lightlessProfileManager;
private readonly FileDialogManager _fileDialogManager;
private readonly UiSharedService _uiSharedService; private readonly UiSharedService _uiSharedService;
private List<BannedGroupUserDto> _bannedUsers = []; private List<BannedGroupUserDto> _bannedUsers = [];
private bool _adjustedForScollBarsLocalProfile = false;
private bool _adjustedForScollBarsOnlineProfile = false;
private string _descriptionText = string.Empty;
private IDalamudTextureWrap? _pfpTextureWrap;
private string _profileDescription = string.Empty;
private byte[] _profileImage = [];
private bool _showFileDialogError = false;
private int _multiInvites; private int _multiInvites;
private string _newPassword; private string _newPassword;
private bool _pwChangeSuccess; private bool _pwChangeSuccess;
@@ -32,13 +48,16 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
private int _pruneDays = 14; private int _pruneDays = 14;
public SyncshellAdminUI(ILogger<SyncshellAdminUI> logger, LightlessMediator mediator, ApiController apiController, public SyncshellAdminUI(ILogger<SyncshellAdminUI> logger, LightlessMediator mediator, ApiController apiController,
UiSharedService uiSharedService, PairManager pairManager, GroupFullInfoDto groupFullInfo, PerformanceCollectorService performanceCollectorService) UiSharedService uiSharedService, PairManager pairManager, GroupFullInfoDto groupFullInfo, PerformanceCollectorService performanceCollectorService, LightlessProfileManager lightlessProfileManager, FileDialogManager fileDialogManager)
: base(logger, mediator, "Syncshell Admin Panel (" + groupFullInfo.GroupAliasOrGID + ")", performanceCollectorService) : base(logger, mediator, "Syncshell Admin Panel (" + groupFullInfo.GroupAliasOrGID + ")", performanceCollectorService)
{ {
GroupFullInfo = groupFullInfo; GroupFullInfo = groupFullInfo;
_apiController = apiController; _apiController = apiController;
_uiSharedService = uiSharedService; _uiSharedService = uiSharedService;
_pairManager = pairManager; _pairManager = pairManager;
_lightlessProfileManager = lightlessProfileManager;
_fileDialogManager = fileDialogManager;
_isOwner = string.Equals(GroupFullInfo.OwnerUID, _apiController.UID, StringComparison.Ordinal); _isOwner = string.Equals(GroupFullInfo.OwnerUID, _apiController.UID, StringComparison.Ordinal);
_isModerator = GroupFullInfo.GroupUserInfo.IsModerator(); _isModerator = GroupFullInfo.GroupUserInfo.IsModerator();
_newPassword = string.Empty; _newPassword = string.Empty;
@@ -76,7 +95,9 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
DrawManagement(); DrawManagement();
DrawPermission(perm); DrawPermission(perm);
DrawProfile();
} }
} }
@@ -176,6 +197,157 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
ownerTab.Dispose(); ownerTab.Dispose();
} }
} }
private void DrawProfile()
{
var profile = _lightlessProfileManager.GetLightlessGroupProfile(new GroupData(GroupFullInfo.Group.GID));
var profileTab = ImRaii.TabItem("Profile");
if (profileTab)
{
_uiSharedService.MediumText("Current Profile (as saved on server)", UIColors.Get("LightlessPurple"));
ImGui.Dummy(new Vector2(5));
if (!_profileImage.SequenceEqual(profile.ImageData.Value))
{
_profileImage = profile.ImageData.Value;
_pfpTextureWrap?.Dispose();
_pfpTextureWrap = _uiSharedService.LoadImage(_profileImage);
}
if (!string.Equals(_profileDescription, profile.Description, StringComparison.OrdinalIgnoreCase))
{
_profileDescription = profile.Description;
_descriptionText = _profileDescription;
}
if (_pfpTextureWrap != null)
{
ImGui.Image(_pfpTextureWrap.Handle, ImGuiHelpers.ScaledVector2(_pfpTextureWrap.Width, _pfpTextureWrap.Height));
}
var spacing = ImGui.GetStyle().ItemSpacing.X;
ImGuiHelpers.ScaledRelativeSameLine(256, spacing);
using (_uiSharedService.GameFont.Push())
{
var descriptionTextSize = ImGui.CalcTextSize(profile.Description, wrapWidth: 256f);
var childFrame = ImGuiHelpers.ScaledVector2(256 + ImGui.GetStyle().WindowPadding.X + ImGui.GetStyle().WindowBorderSize, 256);
if (descriptionTextSize.Y > childFrame.Y)
{
_adjustedForScollBarsOnlineProfile = true;
}
else
{
_adjustedForScollBarsOnlineProfile = false;
}
childFrame = childFrame with
{
X = childFrame.X + (_adjustedForScollBarsOnlineProfile ? ImGui.GetStyle().ScrollbarSize : 0),
};
if (ImGui.BeginChildFrame(101, childFrame))
{
UiSharedService.TextWrapped(profile.Description);
}
ImGui.EndChildFrame();
}
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
ImGui.EndTabItem();
}
if (ImGui.BeginTabItem("Profile Settings"))
{
_uiSharedService.MediumText("Profile Settings", UIColors.Get("LightlessPurple"));
ImGui.Dummy(new Vector2(5));
if (_uiSharedService.IconTextButton(FontAwesomeIcon.FileUpload, "Upload new profile picture"))
{
_fileDialogManager.OpenFileDialog("Select new Profile picture", ".png", (success, file) =>
{
if (!success) return;
_ = Task.Run(async () =>
{
var fileContent = File.ReadAllBytes(file);
using MemoryStream ms = new(fileContent);
var format = await Image.DetectFormatAsync(ms).ConfigureAwait(false);
if (!format.FileExtensions.Contains("png", StringComparer.OrdinalIgnoreCase))
{
_showFileDialogError = true;
return;
}
using var image = Image.Load<Rgba32>(fileContent);
if (image.Width > 256 || image.Height > 256 || (fileContent.Length > 250 * 1024))
{
_showFileDialogError = true;
return;
}
_showFileDialogError = false;
await _apiController.GroupSetProfile(new GroupProfileDto(new GroupData(GroupFullInfo.Group.GID), Description: null, Tags: null, Convert.ToBase64String(fileContent)))
.ConfigureAwait(false);
});
});
}
UiSharedService.AttachToolTip("Select and upload a new profile picture");
ImGui.SameLine();
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Clear uploaded profile picture"))
{
_ = _apiController.GroupSetProfile(new GroupProfileDto(new GroupData(GroupFullInfo.Group.GID), Description: null, Tags: null, PictureBase64: null));
}
UiSharedService.AttachToolTip("Clear your currently uploaded profile picture");
if (_showFileDialogError)
{
UiSharedService.ColorTextWrapped("The profile picture must be a PNG file with a maximum height and width of 256px and 250KiB size", ImGuiColors.DalamudRed);
}
_uiSharedService.DrawHelpText("If your profile description or image can be considered NSFW, toggle this to ON");
var widthTextBox = 400;
var posX = ImGui.GetCursorPosX();
ImGui.TextUnformatted($"Description {_descriptionText.Length}/1500");
ImGui.SetCursorPosX(posX);
ImGuiHelpers.ScaledRelativeSameLine(widthTextBox, ImGui.GetStyle().ItemSpacing.X);
ImGui.TextUnformatted("Preview (approximate)");
using (_uiSharedService.GameFont.Push())
ImGui.InputTextMultiline("##description", ref _descriptionText, 1500, ImGuiHelpers.ScaledVector2(widthTextBox, 200));
ImGui.SameLine();
using (_uiSharedService.GameFont.Push())
{
var descriptionTextSizeLocal = ImGui.CalcTextSize(_descriptionText, wrapWidth: 256f);
var childFrameLocal = ImGuiHelpers.ScaledVector2(256 + ImGui.GetStyle().WindowPadding.X + ImGui.GetStyle().WindowBorderSize, 200);
if (descriptionTextSizeLocal.Y > childFrameLocal.Y)
{
_adjustedForScollBarsLocalProfile = true;
}
else
{
_adjustedForScollBarsLocalProfile = false;
}
childFrameLocal = childFrameLocal with
{
X = childFrameLocal.X + (_adjustedForScollBarsLocalProfile ? ImGui.GetStyle().ScrollbarSize : 0),
};
if (ImGui.BeginChildFrame(102, childFrameLocal))
{
UiSharedService.TextWrapped(_descriptionText);
}
ImGui.EndChildFrame();
}
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Save, "Save Description"))
{
_ = _apiController.GroupSetProfile(new GroupProfileDto(new GroupData(GroupFullInfo.Group.GID), Description: _descriptionText, Tags: null, PictureBase64: null));
}
UiSharedService.AttachToolTip("Sets your profile description text");
ImGui.SameLine();
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Clear Description"))
{
_ = _apiController.GroupSetProfile(new GroupProfileDto(new GroupData(GroupFullInfo.Group.GID), Description: null, Tags: null, PictureBase64: null));
}
UiSharedService.AttachToolTip("Clears your profile description text");
}
profileTab.Dispose();
}
private void DrawManagement() private void DrawManagement()
{ {
@@ -474,7 +646,6 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
ImGui.Separator(); ImGui.Separator();
} }
mgmtTab.Dispose(); mgmtTab.Dispose();
} }
private void DrawInvites(GroupPermissions perm) private void DrawInvites(GroupPermissions perm)