diff --git a/MareSynchronos/Plugin.cs b/MareSynchronos/Plugin.cs index 755e387..138dacd 100644 --- a/MareSynchronos/Plugin.cs +++ b/MareSynchronos/Plugin.cs @@ -3,6 +3,7 @@ using Dalamud.Interface.ImGuiFileDialog; using Dalamud.Interface.Windowing; using Dalamud.Plugin; using Dalamud.Plugin.Services; +using MareSynchronos.API.Dto.Group; using MareSynchronos.FileCache; using MareSynchronos.Interop; using MareSynchronos.MareConfiguration; @@ -103,6 +104,14 @@ public sealed class Plugin : IDalamudPlugin s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), pair))); + collection.AddSingleton(s => + new Func((dto) => + new SyncshellAdminUI(s.GetRequiredService>(), + s.GetRequiredService(), + dto, + s.GetRequiredService(), + s.GetRequiredService(), + s.GetRequiredService()))); // add scoped services collection.AddScoped(); @@ -122,17 +131,18 @@ public sealed class Plugin : IDalamudPlugin collection.AddScoped(); collection.AddScoped(); collection.AddScoped(); - collection.AddScoped(); collection.AddScoped(); collection.AddScoped(); collection.AddScoped(); collection.AddScoped(); collection.AddScoped((s) => new UiService(s.GetRequiredService>(), pluginInterface, s.GetRequiredService(), - s.GetRequiredService(), s.GetServices(), s.GetRequiredService>(), + s.GetRequiredService(), s.GetServices(), + s.GetRequiredService>(), + s.GetRequiredService>(), s.GetRequiredService(), s.GetRequiredService())); collection.AddScoped((s) => new CommandManagerService(commandManager, s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), - s.GetRequiredService())); + s.GetRequiredService(), s.GetRequiredService())); collection.AddScoped((s) => new NotificationService(s.GetRequiredService>(), s.GetRequiredService(), pluginInterface.UiBuilder, chatGui, s.GetRequiredService())); collection.AddScoped((s) => new UiSharedService(s.GetRequiredService>(), s.GetRequiredService(), s.GetRequiredService(), diff --git a/MareSynchronos/Services/Mediator/Messages.cs b/MareSynchronos/Services/Mediator/Messages.cs index c814c26..943433c 100644 --- a/MareSynchronos/Services/Mediator/Messages.cs +++ b/MareSynchronos/Services/Mediator/Messages.cs @@ -72,7 +72,7 @@ public record PairHandlerVisibleMessage(PairHandler Player) : MessageBase; public record RefreshUiMessage : MessageBase; public record OpenReportPopupMessage(Pair PairToReport) : MessageBase; public record OpenBanUserPopupMessage(Pair PairToBan, GroupFullInfoDto GroupFullInfoDto) : MessageBase; -public record OpenSyncshellAdminPanelPopupMessage(GroupFullInfoDto GroupInfo) : MessageBase; +public record OpenSyncshellAdminPanel(GroupFullInfoDto GroupInfo) : MessageBase; #pragma warning restore S2094 #pragma warning restore MA0048 // File name must match type name \ No newline at end of file diff --git a/MareSynchronos/Services/UiService.cs b/MareSynchronos/Services/UiService.cs index 7ae2efb..eb72605 100644 --- a/MareSynchronos/Services/UiService.cs +++ b/MareSynchronos/Services/UiService.cs @@ -1,10 +1,12 @@ using Dalamud.Interface.ImGuiFileDialog; using Dalamud.Interface.Windowing; using Dalamud.Plugin; +using MareSynchronos.API.Dto.Group; using MareSynchronos.MareConfiguration; using MareSynchronos.PlayerData.Pairs; using MareSynchronos.Services.Mediator; using MareSynchronos.UI; +using MareSynchronos.UI.Components.Popup; using Microsoft.Extensions.Logging; namespace MareSynchronos.Services; @@ -17,10 +19,13 @@ public sealed class UiService : DisposableMediatorSubscriberBase private readonly ILogger _logger; private readonly MareConfigService _mareConfigService; private readonly WindowSystem _windowSystem; + private readonly Func _syncshellAdminUiFactory; public UiService(ILogger logger, DalamudPluginInterface dalamudPluginInterface, MareConfigService mareConfigService, WindowSystem windowSystem, - IEnumerable windows, Func standaloneProfileUiFactory, + IEnumerable windows, + Func standaloneProfileUiFactory, + Func syncshellAdminUiFactory, FileDialogManager fileDialogManager, MareMediator mareMediator) : base(logger, mareMediator) { _logger = logger; @@ -28,6 +33,7 @@ public sealed class UiService : DisposableMediatorSubscriberBase _dalamudPluginInterface = dalamudPluginInterface; _mareConfigService = mareConfigService; _windowSystem = windowSystem; + _syncshellAdminUiFactory = syncshellAdminUiFactory; _fileDialogManager = fileDialogManager; _dalamudPluginInterface.UiBuilder.DisableGposeUiHide = true; @@ -51,6 +57,17 @@ public sealed class UiService : DisposableMediatorSubscriberBase } }); + Mediator.Subscribe(this, (msg) => + { + if (!_createdWindows.Exists(p => p is SyncshellAdminUI ui + && string.Equals(ui.GroupFullInfo.GID, msg.GroupInfo.GID, StringComparison.Ordinal))) + { + var window = _syncshellAdminUiFactory(msg.GroupInfo); + _createdWindows.Add(window); + _windowSystem.AddWindow(window); + } + }); + Mediator.Subscribe(this, (msg) => { _windowSystem.RemoveWindow(msg.Window); diff --git a/MareSynchronos/UI/Components/DrawFolderGroup.cs b/MareSynchronos/UI/Components/DrawFolderGroup.cs index 85e8c38..1151b3b 100644 --- a/MareSynchronos/UI/Components/DrawFolderGroup.cs +++ b/MareSynchronos/UI/Components/DrawFolderGroup.cs @@ -160,7 +160,7 @@ public class DrawFolderGroup : DrawFolderBase if (UiSharedService.IconTextButton(FontAwesomeIcon.Cog, "Open Admin Panel", menuWidth, true)) { ImGui.CloseCurrentPopup(); - _mareMediator.Publish(new OpenSyncshellAdminPanelPopupMessage(_groupFullInfoDto)); + _mareMediator.Publish(new OpenSyncshellAdminPanel(_groupFullInfoDto)); } } } diff --git a/MareSynchronos/UI/Components/Popup/PopupHandler.cs b/MareSynchronos/UI/Components/Popup/PopupHandler.cs index 8359e97..8bd9b2f 100644 --- a/MareSynchronos/UI/Components/Popup/PopupHandler.cs +++ b/MareSynchronos/UI/Components/Popup/PopupHandler.cs @@ -1,4 +1,5 @@ using Dalamud.Interface; +using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using ImGuiNET; using MareSynchronos.Services.Mediator; @@ -43,15 +44,6 @@ public class PopupHandler : WindowMediatorSubscriberBase ((BanUserPopupHandler)_currentHandler).Open(msg); IsOpen = true; }); - - Mediator.Subscribe(this, (msg) => - { - IsOpen = true; - _openPopup = true; - _currentHandler = _handlers.OfType().Single(); - ((SyncshellAdminPopupHandler)_currentHandler).Open(msg.GroupInfo); - IsOpen = true; - }); } public override void Draw() @@ -65,7 +57,7 @@ public class PopupHandler : WindowMediatorSubscriberBase } var viewportSize = ImGui.GetWindowViewport().Size; - ImGui.SetNextWindowSize(_currentHandler!.PopupSize); + ImGui.SetNextWindowSize(_currentHandler!.PopupSize * ImGuiHelpers.GlobalScale); ImGui.SetNextWindowPos(viewportSize / 2, ImGuiCond.Always, new Vector2(0.5f)); using var popup = ImRaii.Popup(WindowName, ImGuiWindowFlags.Modal); if (!popup) return; diff --git a/MareSynchronos/UI/Components/Popup/SyncshellAdminPopupHandler.cs b/MareSynchronos/UI/Components/Popup/SyncshellAdminPopupHandler.cs deleted file mode 100644 index 7fbdbb6..0000000 --- a/MareSynchronos/UI/Components/Popup/SyncshellAdminPopupHandler.cs +++ /dev/null @@ -1,234 +0,0 @@ -using Dalamud.Interface; -using Dalamud.Interface.Colors; -using Dalamud.Interface.Utility.Raii; -using ImGuiNET; -using MareSynchronos.API.Data.Extensions; -using MareSynchronos.API.Dto.Group; -using MareSynchronos.PlayerData.Pairs; -using MareSynchronos.WebAPI; -using System.Globalization; -using System.Numerics; - -namespace MareSynchronos.UI.Components.Popup; - -internal class SyncshellAdminPopupHandler : IPopupHandler -{ - private readonly ApiController _apiController; - private readonly List _oneTimeInvites = []; - private readonly PairManager _pairManager; - private readonly UiSharedService _uiSharedService; - private List _bannedUsers = []; - private GroupFullInfoDto _groupFullInfo = null!; - private bool _isModerator = false; - private bool _isOwner = false; - private int _multiInvites = 30; - private string _newPassword = string.Empty; - private bool _pwChangeSuccess = true; - - public SyncshellAdminPopupHandler(ApiController apiController, UiSharedService uiSharedService, PairManager pairManager) - { - _apiController = apiController; - _uiSharedService = uiSharedService; - _pairManager = pairManager; - } - - public Vector2 PopupSize => new(700, 500); - - public void DrawContent() - { - if (!_isModerator && !_isOwner) return; - - _groupFullInfo = _pairManager.Groups[_groupFullInfo.Group]; - - using (ImRaii.PushFont(_uiSharedService.UidFont)) - ImGui.TextUnformatted(_groupFullInfo.GroupAliasOrGID + " Administrative Panel"); - - ImGui.Separator(); - var perm = _groupFullInfo.GroupPermissions; - - var inviteNode = ImRaii.TreeNode("Invites"); - if (inviteNode) - { - bool isInvitesDisabled = perm.IsDisableInvites(); - - if (UiSharedService.IconTextButton(isInvitesDisabled ? FontAwesomeIcon.Unlock : FontAwesomeIcon.Lock, - isInvitesDisabled ? "Unlock Syncshell" : "Lock Syncshell")) - { - perm.SetDisableInvites(!isInvitesDisabled); - _ = _apiController.GroupChangeGroupPermissionState(new(_groupFullInfo.Group, perm)); - } - - ImGui.Dummy(new(2f)); - - UiSharedService.TextWrapped("One-time invites work as single-use passwords. Use those if you do not want to distribute your Syncshell password."); - if (UiSharedService.IconTextButton(FontAwesomeIcon.Envelope, "Single one-time invite")) - { - ImGui.SetClipboardText(_apiController.GroupCreateTempInvite(new(_groupFullInfo.Group), 1).Result.FirstOrDefault() ?? string.Empty); - } - UiSharedService.AttachToolTip("Creates a single-use password for joining the syncshell which is valid for 24h and copies it to the clipboard."); - ImGui.InputInt("##amountofinvites", ref _multiInvites); - ImGui.SameLine(); - using (ImRaii.Disabled(_multiInvites <= 1 || _multiInvites > 100)) - { - if (UiSharedService.IconTextButton(FontAwesomeIcon.Envelope, "Generate " + _multiInvites + " one-time invites")) - { - _oneTimeInvites.AddRange(_apiController.GroupCreateTempInvite(new(_groupFullInfo.Group), _multiInvites).Result); - } - } - - if (_oneTimeInvites.Any()) - { - var invites = string.Join(Environment.NewLine, _oneTimeInvites); - ImGui.InputTextMultiline("Generated Multi Invites", ref invites, 5000, new(0, 0), ImGuiInputTextFlags.ReadOnly); - if (UiSharedService.IconTextButton(FontAwesomeIcon.Copy, "Copy Invites to clipboard")) - { - ImGui.SetClipboardText(invites); - } - } - } - inviteNode.Dispose(); - - var mgmtNode = ImRaii.TreeNode("User Management"); - if (mgmtNode) - { - if (UiSharedService.IconTextButton(FontAwesomeIcon.Broom, "Clear Syncshell")) - { - _ = _apiController.GroupClear(new(_groupFullInfo.Group)); - } - UiSharedService.AttachToolTip("This will remove all non-pinned, non-moderator users from the Syncshell"); - - ImGui.Dummy(new(2f)); - - if (UiSharedService.IconTextButton(FontAwesomeIcon.Retweet, "Refresh Banlist from Server")) - { - _bannedUsers = _apiController.GroupGetBannedUsers(new GroupDto(_groupFullInfo.Group)).Result; - } - - if (ImGui.BeginTable("bannedusertable" + _groupFullInfo.GID, 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.ScrollY)) - { - ImGui.TableSetupColumn("UID", ImGuiTableColumnFlags.None, 1); - ImGui.TableSetupColumn("Alias", ImGuiTableColumnFlags.None, 1); - ImGui.TableSetupColumn("By", ImGuiTableColumnFlags.None, 1); - ImGui.TableSetupColumn("Date", ImGuiTableColumnFlags.None, 2); - ImGui.TableSetupColumn("Reason", ImGuiTableColumnFlags.None, 3); - ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.None, 1); - - ImGui.TableHeadersRow(); - - foreach (var bannedUser in _bannedUsers.ToList()) - { - ImGui.TableNextColumn(); - ImGui.TextUnformatted(bannedUser.UID); - ImGui.TableNextColumn(); - ImGui.TextUnformatted(bannedUser.UserAlias ?? string.Empty); - ImGui.TableNextColumn(); - ImGui.TextUnformatted(bannedUser.BannedBy); - ImGui.TableNextColumn(); - ImGui.TextUnformatted(bannedUser.BannedOn.ToLocalTime().ToString(CultureInfo.CurrentCulture)); - ImGui.TableNextColumn(); - UiSharedService.TextWrapped(bannedUser.Reason); - ImGui.TableNextColumn(); - if (UiSharedService.IconTextButton(FontAwesomeIcon.Check, "Unban#" + bannedUser.UID)) - { - _ = _apiController.GroupUnbanUser(bannedUser); - _bannedUsers.RemoveAll(b => string.Equals(b.UID, bannedUser.UID, StringComparison.Ordinal)); - } - } - - ImGui.EndTable(); - } - } - mgmtNode.Dispose(); - - var permNode = ImRaii.TreeNode("Permissions"); - if (permNode) - { - bool isDisableAnimations = perm.IsPreferDisableAnimations(); - bool isDisableSounds = perm.IsPreferDisableSounds(); - bool isDisableVfx = perm.IsPreferDisableVFX(); - - ImGui.AlignTextToFramePadding(); - ImGui.Text("Suggest Sound Sync"); - UiSharedService.BooleanToColoredIcon(!isDisableSounds); - ImGui.SameLine(230); - if (UiSharedService.IconTextButton(isDisableSounds ? FontAwesomeIcon.VolumeUp : FontAwesomeIcon.VolumeMute, - isDisableSounds ? "Suggest to enable sound sync" : "Suggest to disable sound sync")) - { - perm.SetPreferDisableSounds(!perm.IsPreferDisableSounds()); - _ = _apiController.GroupChangeGroupPermissionState(new(_groupFullInfo.Group, perm)); - } - - ImGui.AlignTextToFramePadding(); - ImGui.Text("Suggest Animation Sync"); - UiSharedService.BooleanToColoredIcon(!isDisableAnimations); - ImGui.SameLine(230); - if (UiSharedService.IconTextButton(isDisableAnimations ? FontAwesomeIcon.Running : FontAwesomeIcon.Stop, - isDisableAnimations ? "Suggest to enable animation sync" : "Suggest to disable animation sync")) - { - perm.SetPreferDisableAnimations(!perm.IsPreferDisableAnimations()); - _ = _apiController.GroupChangeGroupPermissionState(new(_groupFullInfo.Group, perm)); - } - - ImGui.AlignTextToFramePadding(); - ImGui.Text("Suggest VFX Sync"); - UiSharedService.BooleanToColoredIcon(!isDisableVfx); - ImGui.SameLine(230); - if (UiSharedService.IconTextButton(isDisableVfx ? FontAwesomeIcon.Sun : FontAwesomeIcon.Circle, - isDisableVfx ? "Suggest to enable vfx sync" : "Suggest to disable vfx sync")) - { - perm.SetPreferDisableVFX(!perm.IsPreferDisableVFX()); - _ = _apiController.GroupChangeGroupPermissionState(new(_groupFullInfo.Group, perm)); - } - - UiSharedService.TextWrapped("Note: those suggested permissions will be shown to users on joining the Syncshell."); - } - permNode.Dispose(); - - if (_isOwner) - { - var ownerNode = ImRaii.TreeNode("Owner Settings"); - if (ownerNode) - { - ImGui.AlignTextToFramePadding(); - ImGui.TextUnformatted("New Password"); - ImGui.SameLine(); - ImGui.InputTextWithHint("##changepw", "Min 10 characters", ref _newPassword, 50); - ImGui.SameLine(); - using (ImRaii.Disabled(_newPassword.Length < 10)) - { - if (UiSharedService.IconTextButton(FontAwesomeIcon.Passport, "Change Password")) - { - _pwChangeSuccess = _apiController.GroupChangePassword(new GroupPasswordDto(_groupFullInfo.Group, _newPassword)).Result; - _newPassword = string.Empty; - } - } - UiSharedService.AttachToolTip("Password requires to be at least 10 characters long. This action is irreversible."); - - if (!_pwChangeSuccess) - { - UiSharedService.ColorTextWrapped("Failed to change the password. Password requires to be at least 10 characters long.", ImGuiColors.DalamudYellow); - } - - if (UiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Delete Syncshell") && UiSharedService.CtrlPressed() && UiSharedService.ShiftPressed()) - { - ImGui.CloseCurrentPopup(); - _ = _apiController.GroupDelete(new(_groupFullInfo.Group)); - } - UiSharedService.AttachToolTip("Hold CTRL and Shift and click to delete this Syncshell." + Environment.NewLine + "WARNING: this action is irreversible."); - } - ownerNode.Dispose(); - } - } - - public void Open(GroupFullInfoDto groupFullInfo) - { - _groupFullInfo = groupFullInfo; - _isOwner = string.Equals(_groupFullInfo.OwnerUID, _apiController.UID, StringComparison.Ordinal); - _isModerator = _groupFullInfo.GroupUserInfo.IsModerator(); - _newPassword = string.Empty; - _bannedUsers.Clear(); - _oneTimeInvites.Clear(); - _multiInvites = 30; - _pwChangeSuccess = true; - } -} \ No newline at end of file diff --git a/MareSynchronos/UI/SyncshellAdminUI.cs b/MareSynchronos/UI/SyncshellAdminUI.cs new file mode 100644 index 0000000..57f3a7a --- /dev/null +++ b/MareSynchronos/UI/SyncshellAdminUI.cs @@ -0,0 +1,252 @@ +using Dalamud.Interface; +using Dalamud.Interface.Colors; +using Dalamud.Interface.Utility.Raii; +using ImGuiNET; +using MareSynchronos.API.Data.Extensions; +using MareSynchronos.API.Dto.Group; +using MareSynchronos.PlayerData.Pairs; +using MareSynchronos.Services.Mediator; +using MareSynchronos.WebAPI; +using Microsoft.Extensions.Logging; +using System.Globalization; + +namespace MareSynchronos.UI.Components.Popup; + +public class SyncshellAdminUI : WindowMediatorSubscriberBase +{ + private readonly ApiController _apiController; + private readonly bool _isModerator = false; + private readonly bool _isOwner = false; + private readonly List _oneTimeInvites = []; + private readonly PairManager _pairManager; + private readonly UiSharedService _uiSharedService; + private List _bannedUsers = []; + private int _multiInvites; + private string _newPassword; + private bool _pwChangeSuccess; + public SyncshellAdminUI(ILogger logger, MareMediator mediator, GroupFullInfoDto groupFullInfo, ApiController apiController, UiSharedService uiSharedService, PairManager pairManager) + : base(logger, mediator, "Syncshell Admin Panel (" + groupFullInfo.GID + ")") + { + GroupFullInfo = groupFullInfo; + _apiController = apiController; + _uiSharedService = uiSharedService; + _pairManager = pairManager; + _isOwner = string.Equals(GroupFullInfo.OwnerUID, _apiController.UID, StringComparison.Ordinal); + _isModerator = GroupFullInfo.GroupUserInfo.IsModerator(); + _newPassword = string.Empty; + _multiInvites = 30; + _pwChangeSuccess = true; + IsOpen = true; + SizeConstraints = new WindowSizeConstraints() + { + MinimumSize = new(700, 500), + MaximumSize = new(700, 2000), + }; + } + + public GroupFullInfoDto GroupFullInfo { get; private set; } + + public override void Draw() + { + if (!_isModerator && !_isOwner) return; + + GroupFullInfo = _pairManager.Groups[GroupFullInfo.Group]; + + using var id = ImRaii.PushId("syncshell_admin_" + GroupFullInfo.GID); + + using (ImRaii.PushFont(_uiSharedService.UidFont)) + ImGui.TextUnformatted(GroupFullInfo.GroupAliasOrGID + " Administrative Panel"); + + ImGui.Separator(); + var perm = GroupFullInfo.GroupPermissions; + + using var tabbar = ImRaii.TabBar("syncshell_tab_" + GroupFullInfo.GID); + + if (tabbar) + { + var inviteTab = ImRaii.TabItem("Invites"); + if (inviteTab) + { + bool isInvitesDisabled = perm.IsDisableInvites(); + + if (UiSharedService.IconTextButton(isInvitesDisabled ? FontAwesomeIcon.Unlock : FontAwesomeIcon.Lock, + isInvitesDisabled ? "Unlock Syncshell" : "Lock Syncshell")) + { + perm.SetDisableInvites(!isInvitesDisabled); + _ = _apiController.GroupChangeGroupPermissionState(new(GroupFullInfo.Group, perm)); + } + + ImGui.Dummy(new(2f)); + + UiSharedService.TextWrapped("One-time invites work as single-use passwords. Use those if you do not want to distribute your Syncshell password."); + if (UiSharedService.IconTextButton(FontAwesomeIcon.Envelope, "Single one-time invite")) + { + ImGui.SetClipboardText(_apiController.GroupCreateTempInvite(new(GroupFullInfo.Group), 1).Result.FirstOrDefault() ?? string.Empty); + } + UiSharedService.AttachToolTip("Creates a single-use password for joining the syncshell which is valid for 24h and copies it to the clipboard."); + ImGui.InputInt("##amountofinvites", ref _multiInvites); + ImGui.SameLine(); + using (ImRaii.Disabled(_multiInvites <= 1 || _multiInvites > 100)) + { + if (UiSharedService.IconTextButton(FontAwesomeIcon.Envelope, "Generate " + _multiInvites + " one-time invites")) + { + _oneTimeInvites.AddRange(_apiController.GroupCreateTempInvite(new(GroupFullInfo.Group), _multiInvites).Result); + } + } + + if (_oneTimeInvites.Any()) + { + var invites = string.Join(Environment.NewLine, _oneTimeInvites); + ImGui.InputTextMultiline("Generated Multi Invites", ref invites, 5000, new(0, 0), ImGuiInputTextFlags.ReadOnly); + if (UiSharedService.IconTextButton(FontAwesomeIcon.Copy, "Copy Invites to clipboard")) + { + ImGui.SetClipboardText(invites); + } + } + } + inviteTab.Dispose(); + + var mgmtTab = ImRaii.TabItem("User Management"); + if (mgmtTab) + { + if (UiSharedService.IconTextButton(FontAwesomeIcon.Broom, "Clear Syncshell")) + { + _ = _apiController.GroupClear(new(GroupFullInfo.Group)); + } + UiSharedService.AttachToolTip("This will remove all non-pinned, non-moderator users from the Syncshell"); + + ImGui.Dummy(new(2f)); + + if (UiSharedService.IconTextButton(FontAwesomeIcon.Retweet, "Refresh Banlist from Server")) + { + _bannedUsers = _apiController.GroupGetBannedUsers(new GroupDto(GroupFullInfo.Group)).Result; + } + + if (ImGui.BeginTable("bannedusertable" + GroupFullInfo.GID, 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.ScrollY)) + { + ImGui.TableSetupColumn("UID", ImGuiTableColumnFlags.None, 1); + ImGui.TableSetupColumn("Alias", ImGuiTableColumnFlags.None, 1); + ImGui.TableSetupColumn("By", ImGuiTableColumnFlags.None, 1); + ImGui.TableSetupColumn("Date", ImGuiTableColumnFlags.None, 2); + ImGui.TableSetupColumn("Reason", ImGuiTableColumnFlags.None, 3); + ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.None, 1); + + ImGui.TableHeadersRow(); + + foreach (var bannedUser in _bannedUsers.ToList()) + { + ImGui.TableNextColumn(); + ImGui.TextUnformatted(bannedUser.UID); + ImGui.TableNextColumn(); + ImGui.TextUnformatted(bannedUser.UserAlias ?? string.Empty); + ImGui.TableNextColumn(); + ImGui.TextUnformatted(bannedUser.BannedBy); + ImGui.TableNextColumn(); + ImGui.TextUnformatted(bannedUser.BannedOn.ToLocalTime().ToString(CultureInfo.CurrentCulture)); + ImGui.TableNextColumn(); + UiSharedService.TextWrapped(bannedUser.Reason); + ImGui.TableNextColumn(); + if (UiSharedService.IconTextButton(FontAwesomeIcon.Check, "Unban#" + bannedUser.UID)) + { + _ = _apiController.GroupUnbanUser(bannedUser); + _bannedUsers.RemoveAll(b => string.Equals(b.UID, bannedUser.UID, StringComparison.Ordinal)); + } + } + + ImGui.EndTable(); + } + } + mgmtTab.Dispose(); + + var permissionTab = ImRaii.TabItem("Permissions"); + if (permissionTab) + { + bool isDisableAnimations = perm.IsPreferDisableAnimations(); + bool isDisableSounds = perm.IsPreferDisableSounds(); + bool isDisableVfx = perm.IsPreferDisableVFX(); + + ImGui.AlignTextToFramePadding(); + ImGui.Text("Suggest Sound Sync"); + UiSharedService.BooleanToColoredIcon(!isDisableSounds); + ImGui.SameLine(230); + if (UiSharedService.IconTextButton(isDisableSounds ? FontAwesomeIcon.VolumeUp : FontAwesomeIcon.VolumeMute, + isDisableSounds ? "Suggest to enable sound sync" : "Suggest to disable sound sync")) + { + perm.SetPreferDisableSounds(!perm.IsPreferDisableSounds()); + _ = _apiController.GroupChangeGroupPermissionState(new(GroupFullInfo.Group, perm)); + } + + ImGui.AlignTextToFramePadding(); + ImGui.Text("Suggest Animation Sync"); + UiSharedService.BooleanToColoredIcon(!isDisableAnimations); + ImGui.SameLine(230); + if (UiSharedService.IconTextButton(isDisableAnimations ? FontAwesomeIcon.Running : FontAwesomeIcon.Stop, + isDisableAnimations ? "Suggest to enable animation sync" : "Suggest to disable animation sync")) + { + perm.SetPreferDisableAnimations(!perm.IsPreferDisableAnimations()); + _ = _apiController.GroupChangeGroupPermissionState(new(GroupFullInfo.Group, perm)); + } + + ImGui.AlignTextToFramePadding(); + ImGui.Text("Suggest VFX Sync"); + UiSharedService.BooleanToColoredIcon(!isDisableVfx); + ImGui.SameLine(230); + if (UiSharedService.IconTextButton(isDisableVfx ? FontAwesomeIcon.Sun : FontAwesomeIcon.Circle, + isDisableVfx ? "Suggest to enable vfx sync" : "Suggest to disable vfx sync")) + { + perm.SetPreferDisableVFX(!perm.IsPreferDisableVFX()); + _ = _apiController.GroupChangeGroupPermissionState(new(GroupFullInfo.Group, perm)); + } + + UiSharedService.TextWrapped("Note: those suggested permissions will be shown to users on joining the Syncshell."); + } + permissionTab.Dispose(); + + if (_isOwner) + { + var ownerTab = ImRaii.TabItem("Owner Settings"); + if (ownerTab) + { + ImGui.AlignTextToFramePadding(); + ImGui.TextUnformatted("New Password"); + var availableWidth = ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X; + var buttonSize = UiSharedService.GetIconTextButtonSize(FontAwesomeIcon.Passport, "Change Password").X; + var textSize = ImGui.CalcTextSize("New Password").X; + var spacing = ImGui.GetStyle().ItemSpacing.X; + + ImGui.SameLine(); + ImGui.SetNextItemWidth(availableWidth - buttonSize - textSize - spacing * 2); + ImGui.InputTextWithHint("##changepw", "Min 10 characters", ref _newPassword, 50); + ImGui.SameLine(); + using (ImRaii.Disabled(_newPassword.Length < 10)) + { + if (UiSharedService.IconTextButton(FontAwesomeIcon.Passport, "Change Password")) + { + _pwChangeSuccess = _apiController.GroupChangePassword(new GroupPasswordDto(GroupFullInfo.Group, _newPassword)).Result; + _newPassword = string.Empty; + } + } + UiSharedService.AttachToolTip("Password requires to be at least 10 characters long. This action is irreversible."); + + if (!_pwChangeSuccess) + { + UiSharedService.ColorTextWrapped("Failed to change the password. Password requires to be at least 10 characters long.", ImGuiColors.DalamudYellow); + } + + if (UiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Delete Syncshell") && UiSharedService.CtrlPressed() && UiSharedService.ShiftPressed()) + { + IsOpen = false; + _ = _apiController.GroupDelete(new(GroupFullInfo.Group)); + } + UiSharedService.AttachToolTip("Hold CTRL and Shift and click to delete this Syncshell." + Environment.NewLine + "WARNING: this action is irreversible."); + } + ownerTab.Dispose(); + } + } + } + + public override void OnClose() + { + Mediator.Publish(new RemoveWindowMessage(this)); + } +} \ No newline at end of file