@@ -1,17 +1,24 @@
using Dalamud.Bindings.ImGui ;
using Dalamud.Interface ;
using Dalamud.Interface.Colors ;
using Dalamud.Interface.ImGuiFileDialog ;
using Dalamud.Interface.Textures.TextureWraps ;
using Dalamud.Interface.Utility ;
using Dalamud.Interface.Utility.Raii ;
using LightlessSync.API.Data ;
using LightlessSync.API.Data.Enum ;
using LightlessSync.API.Data.Extensions ;
using LightlessSync.API.Dto.Group ;
using LightlessSync.API.Dto.User ;
using LightlessSync.PlayerData.Pairs ;
using LightlessSync.Services ;
using LightlessSync.Services.Mediator ;
using LightlessSync.WebAPI ;
using Microsoft.Extensions.Logging ;
using SixLabors.ImageSharp ;
using SixLabors.ImageSharp.PixelFormats ;
using System.Globalization ;
using System.Numerics ;
namespace LightlessSync.UI ;
@@ -22,8 +29,17 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
private readonly bool _isOwner = false ;
private readonly List < string > _oneTimeInvites = [ ] ;
private readonly PairManager _pairManager ;
private readonly LightlessProfileManager _lightlessProfileManager ;
private readonly FileDialogManager _fileDialogManager ;
private readonly UiSharedService _uiSharedService ;
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 string _newPassword ;
private bool _pwChangeSuccess ;
@@ -32,13 +48,16 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
private int _pruneDays = 14 ;
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 )
{
GroupFullInfo = groupFullInfo ;
_apiController = apiController ;
_uiSharedService = uiSharedService ;
_pairManager = pairManager ;
_lightlessProfileManager = lightlessProfileManager ;
_fileDialogManager = fileDialogManager ;
_isOwner = string . Equals ( GroupFullInfo . OwnerUID , _apiController . UID , StringComparison . Ordinal ) ;
_isModerator = GroupFullInfo . GroupUserInfo . IsModerator ( ) ;
_newPassword = string . Empty ;
@@ -76,7 +95,9 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
DrawManagement ( ) ;
DrawPermission ( perm ) ;
DrawPermission ( perm ) ;
DrawProfile ( ) ;
}
}
@@ -176,6 +197,157 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
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 ( )
{
@@ -474,7 +646,6 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
ImGui . Separator ( ) ;
}
mgmtTab . Dispose ( ) ;
}
private void DrawInvites ( GroupPermissions perm )