diff --git a/.gitea/lightless-tag-and-release.yml b/.gitea/lightless-tag-and-release.yml new file mode 100644 index 0000000..63b4fb0 --- /dev/null +++ b/.gitea/lightless-tag-and-release.yml @@ -0,0 +1,182 @@ +name: Tag and Release Lightless + +on: + push: + branches: [ master ] + +env: + PLUGIN_NAME: LightlessSync + DOTNET_VERSION: 9.x + +jobs: + tag-and-release: + runs-on: ubuntu-22.04 + permissions: + contents: write + + steps: + - name: Checkout Lightless + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: true + + - name: Setup .NET 9 SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 9.x + + - name: Download Dalamud + run: | + cd / + mkdir -p root/.xlcore/dalamud/Hooks/dev + curl -O https://goatcorp.github.io/dalamud-distrib/stg/latest.zip + unzip latest.zip -d /root/.xlcore/dalamud/Hooks/dev + + - name: Lets Build Lightless! + run: | + dotnet restore + dotnet build --configuration Release --no-restore + dotnet publish --configuration Release --no-build + + - name: Get version + id: package_version + uses: KageKirin/get-csproj-version@v0 + with: + file: LightlessSync/LightlessSync.csproj + + - name: Display version + run: | + echo "Version: ${{ steps.package_version.outputs.version }}" + + - name: Prepare Lightless Client + run: | + PUBLISH_PATH="/workspace/Lightless-Sync/LightlessClient/LightlessSync/bin/x64/Release/publish/" + if [ -d "$PUBLISH_PATH" ]; then + rm -rf "$PUBLISH_PATH" + echo "Removed $PUBLISH_PATH" + else + echo "$PUBLISH_PATH does not exist, nothing to remove." + fi + + mkdir -p output + (cd /workspace/Lightless-Sync/LightlessClient/LightlessSync/bin/x64/Release/ && zip -r $OLDPWD/output/LightlessClient.zip *) + + - name: Create Git tag if not exists + run: | + tag="${{ steps.package_version.outputs.version }}" + git fetch --tags + if ! git tag -l "$tag" | grep -q "$tag"; then + echo "Tag $tag does not exist. Creating and pushing..." + git config user.name "GitHub Action" + git config user.email "action@github.com" + git tag "$tag" + git push origin "$tag" + else + echo "Tag $tag already exists. Skipping tag creation." + fi + + - name: Create Release + id: create_release + run: | + echo "=== Searching for existing release ${{ steps.package_version.outputs.version }}===" + + release_id=$(curl -s -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \ + "https://git.lightless-sync.org/api/v1/repos/${GITHUB_REPOSITORY}/releases/tags/${{ steps.package_version.outputs.version }}" | jq -r .id) + + if [ "$release_id" != "null" ]; then + echo "=== Deleting existing release ${{ steps.package_version.outputs.version }}===" + curl -X DELETE -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \ + "https://git.lightless-sync.org/api/v1/repos/${GITHUB_REPOSITORY}/releases/$release_id" + fi + + echo "=== Creating new release ${{ steps.package_version.outputs.version }}===" + response=$( + curl --fail-with-body -X POST \ + -H "Content-Type: application/json" \ + -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \ + -d '{ + "tag_name": "${{ steps.package_version.outputs.version }}", + "name": "${{ steps.package_version.outputs.version }}", + "draft": false, + "prerelease": false + }' \ + "https://git.lightless-sync.org/api/v1/repos/${GITHUB_REPOSITORY}/releases" + ) + + release_id=$(echo "$response" | jq -r .id) + echo "release_id=$release_id" >> "$GITHUB_OUTPUT" + + - name: Upload Assets to release + run: | + curl --fail-with-body -s -X POST \ + -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \ + -F "attachment=@output/LightlessClient.zip" \ + "https://git.lightless-sync.org/api/v1/repos/${GITHUB_REPOSITORY}/releases/${{ steps.create_release.outputs.release_id }}/assets" + + - name: Clone plugin hosting repo + run: | + mkdir LightlessSyncRepo + cd LightlessSyncRepo + git clone https://git.lightless-sync.org/${{ gitea.repository_owner }}/LightlessSync.git + env: + GIT_TERMINAL_PROMPT: 0 + + - name: Update plogonmaster.json with version + env: + VERSION: ${{ steps.package_version.outputs.version }} + run: | + set -e + + pluginJsonPath="${PLUGIN_NAME}/bin/x64/Release/${PLUGIN_NAME}.json" + repoJsonPath="LightlessSyncRepo/LightlessSync/plogonmaster.json" + version="${VERSION}" + downloadUrl="https://git.lightless-sync.org/${{ gitea.repository_owner }}/LightlessClient/releases/download/$version/LightlessClient.zip" + + # Read plugin JSON + pluginJson=$(cat "$pluginJsonPath") + internalName=$(jq -r '.InternalName' <<< "$pluginJson") + dalamudApiLevel=$(jq -r '.DalamudApiLevel' <<< "$pluginJson") + + # Read repo JSON (force array if not already) + repoJsonRaw=$(cat "$repoJsonPath") + if echo "$repoJsonRaw" | jq 'type' | grep -q '"array"'; then + repoJson="$repoJsonRaw" + else + repoJson="[$repoJsonRaw]" + fi + + # Update matching plugin entry + updatedRepoJson=$(jq \ + --arg internalName "$internalName" \ + --arg dalamudApiLevel "$dalamudApiLevel" \ + --arg version "$version" \ + --arg downloadUrl "$downloadUrl" \ + ' + map( + if .InternalName == $internalName + then + .DalamudApiLevel = $dalamudApiLevel + | .AssemblyVersion = $version + | .DownloadLinkInstall = $downloadUrl + | .DownloadLinkTesting = $downloadUrl + | .DownloadLinkUpdate = $downloadUrl + else + . + end + ) + ' <<< "$repoJson") + + # Write back to file + echo "$updatedRepoJson" > "$repoJsonPath" + # Output the content of the file + cat "$repoJsonPath" + + - name: Commit and push to LightlessSync + run: | + cd LightlessSyncRepo/LightlessSync + git config user.name "github-actions" + git config user.email "github-actions@github.com" + git add . + git diff-index --quiet HEAD || git commit -m "Update ${{ env.PLUGIN_NAME }} to ${{ steps.package_version.outputs.version }}" + git push https://x-access-token:${{ secrets.AUTOMATION_TOKEN }}@git.lightless-sync.org/${{ gitea.repository_owner }}/LightlessSync.git HEAD:main diff --git a/LightlessSync/LightlessSync.csproj b/LightlessSync/LightlessSync.csproj index 7928f4c..548517f 100644 --- a/LightlessSync/LightlessSync.csproj +++ b/LightlessSync/LightlessSync.csproj @@ -3,7 +3,7 @@ - 1.11.4 + 1.11.5 https://github.com/Light-Public-Syncshells/LightlessClient diff --git a/LightlessSync/PlayerData/Pairs/Pair.cs b/LightlessSync/PlayerData/Pairs/Pair.cs index fe6cd7b..d4e2950 100644 --- a/LightlessSync/PlayerData/Pairs/Pair.cs +++ b/LightlessSync/PlayerData/Pairs/Pair.cs @@ -72,8 +72,8 @@ public class Pair Name = openProfileSeString, OnClicked = (a) => _mediator.Publish(new ProfileOpenStandaloneMessage(this)), UseDefaultPrefix = false, - PrefixChar = 'M', - PrefixColor = 526 + PrefixChar = 'L', + PrefixColor = 708 }); args.AddMenuItem(new MenuItem() @@ -81,8 +81,8 @@ public class Pair Name = reapplyDataSeString, OnClicked = (a) => ApplyLastReceivedData(forced: true), UseDefaultPrefix = false, - PrefixChar = 'M', - PrefixColor = 526 + PrefixChar = 'L', + PrefixColor = 708 }); args.AddMenuItem(new MenuItem() @@ -90,8 +90,8 @@ public class Pair Name = changePermissions, OnClicked = (a) => _mediator.Publish(new OpenPermissionWindow(this)), UseDefaultPrefix = false, - PrefixChar = 'M', - PrefixColor = 526 + PrefixChar = 'L', + PrefixColor = 708 }); args.AddMenuItem(new MenuItem() @@ -99,8 +99,8 @@ public class Pair Name = cyclePauseState, OnClicked = (a) => _mediator.Publish(new CyclePauseMessage(UserData)), UseDefaultPrefix = false, - PrefixChar = 'M', - PrefixColor = 526 + PrefixChar = 'L', + PrefixColor = 708 }); } diff --git a/LightlessSync/Plugin.cs b/LightlessSync/Plugin.cs index cb76876..7e00038 100644 --- a/LightlessSync/Plugin.cs +++ b/LightlessSync/Plugin.cs @@ -130,6 +130,7 @@ public sealed class Plugin : IDalamudPlugin s.GetRequiredService(), s.GetRequiredService())); collection.AddSingleton(); + collection.AddSingleton(); collection.AddSingleton((s) => new EventAggregator(pluginInterface.ConfigDirectory.FullName, s.GetRequiredService>(), s.GetRequiredService())); collection.AddSingleton((s) => new DalamudUtilService(s.GetRequiredService>(), diff --git a/LightlessSync/UI/CompactUI.cs b/LightlessSync/UI/CompactUI.cs index 1b5a625..5c1ae53 100644 --- a/LightlessSync/UI/CompactUI.cs +++ b/LightlessSync/UI/CompactUI.cs @@ -38,6 +38,7 @@ public class CompactUi : WindowMediatorSubscriberBase private readonly PairManager _pairManager; private readonly SelectTagForPairUi _selectGroupForPairUi; private readonly SelectPairForTagUi _selectPairsForGroupUi; + private readonly RenameTagUi _renameTagUi; private readonly IpcManager _ipcManager; private readonly ServerConfigurationManager _serverManager; private readonly TopTabMenu _tabMenu; @@ -56,7 +57,7 @@ public class CompactUi : WindowMediatorSubscriberBase public CompactUi(ILogger logger, UiSharedService uiShared, LightlessConfigService configService, ApiController apiController, PairManager pairManager, ServerConfigurationManager serverManager, LightlessMediator mediator, FileUploadManager fileTransferManager, - TagHandler tagHandler, DrawEntityFactory drawEntityFactory, SelectTagForPairUi selectTagForPairUi, SelectPairForTagUi selectPairForTagUi, + TagHandler tagHandler, DrawEntityFactory drawEntityFactory, SelectTagForPairUi selectTagForPairUi, SelectPairForTagUi selectPairForTagUi, RenameTagUi renameTagUi, PerformanceCollectorService performanceCollectorService, IpcManager ipcManager) : base(logger, mediator, "###LightlessSyncMainUI", performanceCollectorService) { @@ -70,6 +71,7 @@ public class CompactUi : WindowMediatorSubscriberBase _drawEntityFactory = drawEntityFactory; _selectGroupForPairUi = selectTagForPairUi; _selectPairsForGroupUi = selectPairForTagUi; + _renameTagUi = renameTagUi; _ipcManager = ipcManager; _tabMenu = new TopTabMenu(Mediator, _apiController, _pairManager, _uiSharedService); @@ -149,10 +151,10 @@ public class CompactUi : WindowMediatorSubscriberBase var uidTextSize = ImGui.CalcTextSize(unsupported); ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMax().X + ImGui.GetWindowContentRegionMin().X) / 2 - uidTextSize.X / 2); ImGui.AlignTextToFramePadding(); - ImGui.TextColored(ImGuiColors.DalamudRed, unsupported); + ImGui.TextColored(UIColors.Get("DimRed"), unsupported); } UiSharedService.ColorTextWrapped($"Your Lightless Sync installation is out of date, the current version is {ver.Major}.{ver.Minor}.{ver.Build}. " + - $"It is highly recommended to keep Lightless Sync up to date. Open /xlplugins and update the plugin.", ImGuiColors.DalamudRed); + $"It is highly recommended to keep Lightless Sync up to date. Open /xlplugins and update the plugin.", UIColors.Get("DimRed")); } if (!_ipcManager.Initialized) @@ -164,12 +166,12 @@ public class CompactUi : WindowMediatorSubscriberBase var uidTextSize = ImGui.CalcTextSize(unsupported); ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMax().X + ImGui.GetWindowContentRegionMin().X) / 2 - uidTextSize.X / 2); ImGui.AlignTextToFramePadding(); - ImGui.TextColored(ImGuiColors.DalamudRed, unsupported); + ImGui.TextColored(UIColors.Get("DimRed"), unsupported); } var penumAvailable = _ipcManager.Penumbra.APIAvailable; var glamAvailable = _ipcManager.Glamourer.APIAvailable; - UiSharedService.ColorTextWrapped($"One or more Plugins essential for Lightless operation are unavailable. Enable or update following plugins:", ImGuiColors.DalamudRed); + UiSharedService.ColorTextWrapped($"One or more Plugins essential for Lightless operation are unavailable. Enable or update following plugins:", UIColors.Get("DimRed")); using var indent = ImRaii.PushIndent(10f); if (!penumAvailable) { @@ -185,7 +187,7 @@ public class CompactUi : WindowMediatorSubscriberBase } using (ImRaii.PushId("header")) DrawUIDHeader(); - ImGui.Separator(); + _uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f); using (ImRaii.PushId("serverstatus")) DrawServerStatus(); ImGui.Separator(); @@ -198,6 +200,7 @@ public class CompactUi : WindowMediatorSubscriberBase using (ImRaii.PushId("transfers")) DrawTransfers(); _transferPartHeight = ImGui.GetCursorPosY() - pairlistEnd - ImGui.GetTextLineHeight(); using (ImRaii.PushId("group-user-popup")) _selectPairsForGroupUi.Draw(_pairManager.DirectPairs); + using (ImRaii.PushId("group-user-edit")) _renameTagUi.Draw(_pairManager.DirectPairs); using (ImRaii.PushId("grouping-popup")) _selectGroupForPairUi.Draw(); } @@ -284,7 +287,7 @@ public class CompactUi : WindowMediatorSubscriberBase else { ImGui.AlignTextToFramePadding(); - ImGui.TextColored(ImGuiColors.DalamudRed, "Not connected to any server"); + ImGui.TextColored(UIColors.Get("DimRed"), "Not connected to any server"); } if (printShard) @@ -587,21 +590,21 @@ public class CompactUi : WindowMediatorSubscriberBase { return _apiController.ServerState switch { - ServerState.Connecting => ImGuiColors.DalamudYellow, - ServerState.Reconnecting => ImGuiColors.DalamudRed, + ServerState.Connecting => UIColors.Get("LightlessYellow"), + ServerState.Reconnecting => UIColors.Get("DimRed"), ServerState.Connected => UIColors.Get("LightlessPurple"), - ServerState.Disconnected => ImGuiColors.DalamudYellow, - ServerState.Disconnecting => ImGuiColors.DalamudYellow, - ServerState.Unauthorized => ImGuiColors.DalamudRed, - ServerState.VersionMisMatch => ImGuiColors.DalamudRed, - ServerState.Offline => ImGuiColors.DalamudRed, - ServerState.RateLimited => ImGuiColors.DalamudYellow, - ServerState.NoSecretKey => ImGuiColors.DalamudYellow, - ServerState.MultiChara => ImGuiColors.DalamudYellow, - ServerState.OAuthMisconfigured => ImGuiColors.DalamudRed, - ServerState.OAuthLoginTokenStale => ImGuiColors.DalamudRed, - ServerState.NoAutoLogon => ImGuiColors.DalamudYellow, - _ => ImGuiColors.DalamudRed + ServerState.Disconnected => UIColors.Get("LightlessYellow"), + ServerState.Disconnecting => UIColors.Get("LightlessYellow"), + ServerState.Unauthorized => UIColors.Get("DimRed"), + ServerState.VersionMisMatch => UIColors.Get("DimRed"), + ServerState.Offline => UIColors.Get("DimRed"), + ServerState.RateLimited => UIColors.Get("LightlessYellow"), + ServerState.NoSecretKey => UIColors.Get("LightlessYellow"), + ServerState.MultiChara => UIColors.Get("LightlessYellow"), + ServerState.OAuthMisconfigured => UIColors.Get("DimRed"), + ServerState.OAuthLoginTokenStale => UIColors.Get("DimRed"), + ServerState.NoAutoLogon => UIColors.Get("LightlessYellow"), + _ => UIColors.Get("DimRed") }; } diff --git a/LightlessSync/UI/Components/DrawFolderTag.cs b/LightlessSync/UI/Components/DrawFolderTag.cs index 3c6fe85..79ec3c0 100644 --- a/LightlessSync/UI/Components/DrawFolderTag.cs +++ b/LightlessSync/UI/Components/DrawFolderTag.cs @@ -13,13 +13,15 @@ public class DrawFolderTag : DrawFolderBase { private readonly ApiController _apiController; private readonly SelectPairForTagUi _selectPairForTagUi; + private readonly RenameTagUi _renameTagUi; public DrawFolderTag(string id, IImmutableList drawPairs, IImmutableList allPairs, - TagHandler tagHandler, ApiController apiController, SelectPairForTagUi selectPairForTagUi, UiSharedService uiSharedService) + TagHandler tagHandler, ApiController apiController, SelectPairForTagUi selectPairForTagUi, RenameTagUi renameTagUi, UiSharedService uiSharedService) : base(id, drawPairs, allPairs, tagHandler, uiSharedService) { _apiController = apiController; _selectPairForTagUi = selectPairForTagUi; + _renameTagUi = renameTagUi; } protected override bool RenderIfEmpty => _id switch @@ -100,12 +102,15 @@ public class DrawFolderTag : DrawFolderBase protected override void DrawMenu(float menuWidth) { ImGui.TextUnformatted("Group Menu"); - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Users, "Select Pairs", menuWidth, true)) + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Users, "Select Pairs", menuWidth, isInPopup: true)) { _selectPairForTagUi.Open(_id); } - UiSharedService.AttachToolTip("Select Individual Pairs for this Pair Group"); - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Delete Pair Group", menuWidth, true) && UiSharedService.CtrlPressed()) + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Edit, "Rename Pair Group", menuWidth, isInPopup: true)) + { + _renameTagUi.Open(_id); + } + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Delete Pair Group", menuWidth, isInPopup: true) && UiSharedService.CtrlPressed()) { _tagHandler.RemoveTag(_id); } diff --git a/LightlessSync/UI/Components/RenameTagUi.cs b/LightlessSync/UI/Components/RenameTagUi.cs new file mode 100644 index 0000000..1d71f64 --- /dev/null +++ b/LightlessSync/UI/Components/RenameTagUi.cs @@ -0,0 +1,93 @@ +using Dalamud.Bindings.ImGui; +using Dalamud.Interface.Utility; +using Dalamud.Interface.Utility.Raii; +using LightlessSync.PlayerData.Pairs; +using LightlessSync.UI.Handlers; + +using System.Numerics; + +namespace LightlessSync.UI.Components; + +public class RenameTagUi +{ + private readonly TagHandler _tagHandler; + private readonly UiSharedService _uiSharedService; + private string _desiredName = string.Empty; + private bool _opened = false; + private HashSet _peopleInGroup = new(StringComparer.Ordinal); + private bool _show = false; + private string _tag = string.Empty; + + public RenameTagUi(TagHandler tagHandler, UiSharedService uiSharedService) + { + _tagHandler = tagHandler; + _uiSharedService = uiSharedService; + } + + public void Draw(List pairs) + { + var workHeight = ImGui.GetMainViewport().WorkSize.Y / ImGuiHelpers.GlobalScale; + var minSize = new Vector2(300, workHeight < 110 ? workHeight : 110) * ImGuiHelpers.GlobalScale; + var maxSize = new Vector2(300, 110) * ImGuiHelpers.GlobalScale; + + var popupName = $"Renaming Group {_tag}"; + + if (!_show) + { + _opened = false; + } + + if (_show && !_opened) + { + ImGui.SetNextWindowSize(minSize); + UiSharedService.CenterNextWindow(minSize.X, minSize.Y, ImGuiCond.Always); + ImGui.OpenPopup(popupName); + _opened = true; + } + + ImGui.SetNextWindowSizeConstraints(minSize, maxSize); + if (ImGui.BeginPopupModal(popupName, ref _show, ImGuiWindowFlags.Popup | ImGuiWindowFlags.Modal)) + { + ImGui.TextUnformatted($"Renaming {_tag}"); + + ImGui.InputTextWithHint("##desiredname", "Enter new group name", ref _desiredName, 255, ImGuiInputTextFlags.None); + using (ImRaii.Disabled(string.IsNullOrEmpty(_desiredName))) + { + if (_uiSharedService.IconTextButton(Dalamud.Interface.FontAwesomeIcon.Plus, "Rename Group")) + { + RenameTag(pairs, _tag, _desiredName); + _show = false; + } + } + ImGui.EndPopup(); + } + else + { + _show = false; + } + } + + public void Open(string tag) + { + _peopleInGroup = _tagHandler.GetOtherUidsForTag(tag); + _tag = tag; + _desiredName = ""; + _show = true; + } + public void RenameTag(List pairs, string oldTag, string newTag) + { + //Removal of old tag + _tagHandler.RemoveTag(oldTag); + + //Creation of new tag and adding of old group pairs in new one. + _tagHandler.AddTag(newTag); + foreach (Pair pair in pairs) + { + var isInTag = _peopleInGroup.Contains(pair.UserData.UID); + if (isInTag) + { + _tagHandler.AddTagToPairedUid(pair.UserData.UID, newTag); + } + } + } +} \ No newline at end of file diff --git a/LightlessSync/UI/DrawEntityFactory.cs b/LightlessSync/UI/DrawEntityFactory.cs index 939ab83..01b6738 100644 --- a/LightlessSync/UI/DrawEntityFactory.cs +++ b/LightlessSync/UI/DrawEntityFactory.cs @@ -23,11 +23,12 @@ public class DrawEntityFactory private readonly PlayerPerformanceConfigService _playerPerformanceConfigService; private readonly CharaDataManager _charaDataManager; private readonly SelectTagForPairUi _selectTagForPairUi; + private readonly RenameTagUi _renameTagUi; private readonly TagHandler _tagHandler; private readonly IdDisplayHandler _uidDisplayHandler; public DrawEntityFactory(ILogger logger, ApiController apiController, IdDisplayHandler uidDisplayHandler, - SelectTagForPairUi selectTagForPairUi, LightlessMediator mediator, + SelectTagForPairUi selectTagForPairUi, RenameTagUi renameTagUi, LightlessMediator mediator, TagHandler tagHandler, SelectPairForTagUi selectPairForTagUi, ServerConfigurationManager serverConfigurationManager, UiSharedService uiSharedService, PlayerPerformanceConfigService playerPerformanceConfigService, CharaDataManager charaDataManager) @@ -36,6 +37,7 @@ public class DrawEntityFactory _apiController = apiController; _uidDisplayHandler = uidDisplayHandler; _selectTagForPairUi = selectTagForPairUi; + _renameTagUi = renameTagUi; _mediator = mediator; _tagHandler = tagHandler; _selectPairForTagUi = selectPairForTagUi; @@ -58,8 +60,8 @@ public class DrawEntityFactory Dictionary> filteredPairs, IImmutableList allPairs) { - return new(tag, filteredPairs.Select(u => CreateDrawPair(tag, u.Key, u.Value, null)).ToImmutableList(), - allPairs, _tagHandler, _apiController, _selectPairForTagUi, _uiSharedService); + return new(tag, filteredPairs.Select(u => CreateDrawPair(tag, u.Key, u.Value, currentGroup: null)).ToImmutableList(), + allPairs, _tagHandler, _apiController, _selectPairForTagUi, _renameTagUi, _uiSharedService); } public DrawUserPair CreateDrawPair(string id, Pair user, List groups, GroupFullInfoDto? currentGroup) diff --git a/LightlessSync/UI/PermissionWindowUI.cs b/LightlessSync/UI/PermissionWindowUI.cs index bafcaa0..45be154 100644 --- a/LightlessSync/UI/PermissionWindowUI.cs +++ b/LightlessSync/UI/PermissionWindowUI.cs @@ -102,7 +102,7 @@ public class PermissionWindowUI : WindowMediatorSubscriberBase { _ownPermissions.SetDisableAnimations(disableAnimations); } - _uiSharedService.DrawHelpText("Disabling sounds will remove all animations synced with this user on both sides." + UiSharedService.TooltipSeparator + _uiSharedService.DrawHelpText("Disabling animations will remove all animations synced with this user on both sides." + UiSharedService.TooltipSeparator + "Note: this is bidirectional, either user disabling animation sync will stop animation sync on both sides."); using (ImRaii.PushIndent(indentSize, false)) { @@ -116,7 +116,7 @@ public class PermissionWindowUI : WindowMediatorSubscriberBase { _ownPermissions.SetDisableVFX(disableVfx); } - _uiSharedService.DrawHelpText("Disabling sounds will remove all VFX synced with this user on both sides." + UiSharedService.TooltipSeparator + _uiSharedService.DrawHelpText("Disabling VFX will remove all VFX synced with this user on both sides." + UiSharedService.TooltipSeparator + "Note: this is bidirectional, either user disabling VFX sync will stop VFX sync on both sides."); using (ImRaii.PushIndent(indentSize, false)) { diff --git a/LightlessSync/UI/SettingsUi.cs b/LightlessSync/UI/SettingsUi.cs index db825c0..2932892 100644 --- a/LightlessSync/UI/SettingsUi.cs +++ b/LightlessSync/UI/SettingsUi.cs @@ -214,7 +214,8 @@ public class SettingsUi : WindowMediatorSubscriberBase private void DrawCurrentTransfers() { _lastTab = "Transfers"; - _uiShared.BigText("Transfer Settings"); + _uiShared.UnderlinedBigText("Transfer Settings", UIColors.Get("LightlessBlue")); + ImGuiHelpers.ScaledDummy(5); int maxParallelDownloads = _configService.Current.ParallelDownloads; bool useAlternativeUpload = _configService.Current.UseAlternativeFileUpload; @@ -263,7 +264,8 @@ public class SettingsUi : WindowMediatorSubscriberBase _uiShared.DrawHelpText("This will attempt to upload files in one go instead of a stream. Typically not necessary to enable. Use if you have upload issues."); ImGui.Separator(); - _uiShared.BigText("Transfer UI"); + _uiShared.UnderlinedBigText("Transfer UI", UIColors.Get("LightlessBlue")); + ImGuiHelpers.ScaledDummy(5); bool showTransferWindow = _configService.Current.ShowTransferWindow; if (ImGui.Checkbox("Show separate transfer window", ref showTransferWindow)) @@ -400,7 +402,8 @@ public class SettingsUi : WindowMediatorSubscriberBase } ImGui.Separator(); - _uiShared.BigText("Current Transfers"); + _uiShared.UnderlinedBigText("Current Transfers", UIColors.Get("LightlessBlue")); + ImGuiHelpers.ScaledDummy(5); if (ImGui.BeginTabBar("TransfersTabBar")) { @@ -561,7 +564,8 @@ public class SettingsUi : WindowMediatorSubscriberBase { _lastTab = "Debug"; - _uiShared.BigText("Debug"); + _uiShared.UnderlinedBigText("Debug", UIColors.Get("LightlessYellow")); + ImGuiHelpers.ScaledDummy(10); #if DEBUG if (LastCreatedCharacterData != null && ImGui.TreeNode("Last created character data")) { @@ -621,13 +625,15 @@ public class SettingsUi : WindowMediatorSubscriberBase } _uiShared.DrawHelpText("Having modified game files will still mark your logs with UNSUPPORTED and you will not receive support, message shown or not." + UiSharedService.TooltipSeparator + "Keeping LOD enabled can lead to more crashes. Use at your own risk."); + + _uiShared.ColoredSeparator(UIColors.Get("LightlessYellow"), 2f); } private void DrawFileStorageSettings() { _lastTab = "FileCache"; - _uiShared.BigText("Export MCDF"); + _uiShared.UnderlinedBigText("Export MCDF", UIColors.Get("LightlessBlue")); ImGuiHelpers.ScaledDummy(10); @@ -646,7 +652,8 @@ public class SettingsUi : WindowMediatorSubscriberBase ImGuiHelpers.ScaledDummy(5); ImGui.Separator(); - _uiShared.BigText("Storage"); + _uiShared.UnderlinedBigText("Storage", UIColors.Get("LightlessBlue")); + ImGuiHelpers.ScaledDummy(5); UiSharedService.TextWrapped("Lightless stores downloaded files from paired people permanently. This is to improve loading performance and requiring less downloads. " + "The storage governs itself by clearing data beyond the set storage size. Please set the storage size accordingly. It is not necessary to manually clear the storage."); @@ -759,74 +766,87 @@ public class SettingsUi : WindowMediatorSubscriberBase ImGuiHelpers.ScaledDummy(new Vector2(10, 10)); ImGui.Separator(); - UiSharedService.TextWrapped("File Storage validation can make sure that all files in your local Lightless Storage are valid. " + + + if (_uiShared.MediumTreeNode("Storage Validation", UIColors.Get("LightlessYellow"))) + { + UiSharedService.TextWrapped("File Storage validation can make sure that all files in your local Lightless Storage are valid. " + "Run the validation before you clear the Storage for no reason. " + Environment.NewLine + "This operation, depending on how many files you have in your storage, can take a while and will be CPU and drive intensive."); - using (ImRaii.Disabled(_validationTask != null && !_validationTask.IsCompleted)) - { - if (_uiShared.IconTextButton(FontAwesomeIcon.Check, "Start File Storage Validation")) + using (ImRaii.Disabled(_validationTask != null && !_validationTask.IsCompleted)) { - _validationCts?.Cancel(); - _validationCts?.Dispose(); - _validationCts = new(); - var token = _validationCts.Token; - _validationTask = Task.Run(() => _fileCacheManager.ValidateLocalIntegrity(_validationProgress, token)); - } - } - if (_validationTask != null && !_validationTask.IsCompleted) - { - ImGui.SameLine(); - if (_uiShared.IconTextButton(FontAwesomeIcon.Times, "Cancel")) - { - _validationCts?.Cancel(); - } - } - - if (_validationTask != null) - { - using (ImRaii.PushIndent(20f)) - { - if (_validationTask.IsCompleted) + if (_uiShared.IconTextButton(FontAwesomeIcon.Check, "Start File Storage Validation")) { - UiSharedService.TextWrapped($"The storage validation has completed and removed {_validationTask.Result.Count} invalid files from storage."); - } - else - { - - UiSharedService.TextWrapped($"Storage validation is running: {_currentProgress.Item1}/{_currentProgress.Item2}"); - UiSharedService.TextWrapped($"Current item: {_currentProgress.Item3.ResolvedFilepath}"); + _validationCts?.Cancel(); + _validationCts?.Dispose(); + _validationCts = new(); + var token = _validationCts.Token; + _validationTask = Task.Run(() => _fileCacheManager.ValidateLocalIntegrity(_validationProgress, token)); } } + if (_validationTask != null && !_validationTask.IsCompleted) + { + ImGui.SameLine(); + if (_uiShared.IconTextButton(FontAwesomeIcon.Times, "Cancel")) + { + _validationCts?.Cancel(); + } + } + + if (_validationTask != null) + { + using (ImRaii.PushIndent(20f)) + { + if (_validationTask.IsCompleted) + { + UiSharedService.TextWrapped($"The storage validation has completed and removed {_validationTask.Result.Count} invalid files from storage."); + } + else + { + + UiSharedService.TextWrapped($"Storage validation is running: {_currentProgress.Item1}/{_currentProgress.Item2}"); + UiSharedService.TextWrapped($"Current item: {_currentProgress.Item3.ResolvedFilepath}"); + } + } + } + + _uiShared.ColoredSeparator(UIColors.Get("LightlessYellow"), 1.5f); + ImGui.TreePop(); } + ImGui.Separator(); - ImGuiHelpers.ScaledDummy(new Vector2(10, 10)); - ImGui.TextUnformatted("To clear the local storage accept the following disclaimer"); - ImGui.Indent(); - ImGui.Checkbox("##readClearCache", ref _readClearCache); - ImGui.SameLine(); - UiSharedService.TextWrapped("I understand that: " + Environment.NewLine + "- By clearing the local storage I put the file servers of my connected service under extra strain by having to redownload all data." - + Environment.NewLine + "- This is not a step to try to fix sync issues." - + Environment.NewLine + "- This can make the situation of not getting other players data worse in situations of heavy file server load."); - if (!_readClearCache) - ImGui.BeginDisabled(); - if (_uiShared.IconTextButton(FontAwesomeIcon.Trash, "Clear local storage") && UiSharedService.CtrlPressed() && _readClearCache) + if (_uiShared.MediumTreeNode("Storage Clearing", UIColors.Get("DimRed"))) { - _ = Task.Run(() => + ImGui.TextUnformatted("To clear the local storage accept the following disclaimer"); + ImGui.Indent(); + ImGui.Checkbox("##readClearCache", ref _readClearCache); + ImGui.SameLine(); + UiSharedService.TextWrapped("I understand that: " + Environment.NewLine + "- By clearing the local storage I put the file servers of my connected service under extra strain by having to redownload all data." + + Environment.NewLine + "- This is not a step to try to fix sync issues." + + Environment.NewLine + "- This can make the situation of not getting other players data worse in situations of heavy file server load."); + if (!_readClearCache) + ImGui.BeginDisabled(); + if (_uiShared.IconTextButton(FontAwesomeIcon.Trash, "Clear local storage") && UiSharedService.CtrlPressed() && _readClearCache) { - foreach (var file in Directory.GetFiles(_configService.Current.CacheFolder)) + _ = Task.Run(() => { - File.Delete(file); - } - }); + foreach (var file in Directory.GetFiles(_configService.Current.CacheFolder)) + { + File.Delete(file); + } + }); + } + UiSharedService.AttachToolTip("You normally do not need to do this. THIS IS NOT SOMETHING YOU SHOULD BE DOING TO TRY TO FIX SYNC ISSUES." + Environment.NewLine + + "This will solely remove all downloaded data from all players and will require you to re-download everything again." + Environment.NewLine + + "Lightless storage is self-clearing and will not surpass the limit you have set it to." + Environment.NewLine + + "If you still think you need to do this hold CTRL while pressing the button."); + if (!_readClearCache) + ImGui.EndDisabled(); + ImGui.Unindent(); + + _uiShared.ColoredSeparator(UIColors.Get("DimRed"), 1.5f); + ImGui.TreePop(); } - UiSharedService.AttachToolTip("You normally do not need to do this. THIS IS NOT SOMETHING YOU SHOULD BE DOING TO TRY TO FIX SYNC ISSUES." + Environment.NewLine - + "This will solely remove all downloaded data from all players and will require you to re-download everything again." + Environment.NewLine - + "Lightless storage is self-clearing and will not surpass the limit you have set it to." + Environment.NewLine - + "If you still think you need to do this hold CTRL while pressing the button."); - if (!_readClearCache) - ImGui.EndDisabled(); - ImGui.Unindent(); } private void DrawGeneral() @@ -840,49 +860,67 @@ public class SettingsUi : WindowMediatorSubscriberBase //UiSharedService.FontText("Experimental", _uiShared.UidFont); //ImGui.Separator(); + _uiShared.UnderlinedBigText("General Settings", UIColors.Get("LightlessBlue")); + ImGui.Dummy(new Vector2(10)); _uiShared.BigText("Notes"); - if (_uiShared.IconTextButton(FontAwesomeIcon.StickyNote, "Export all your user notes to clipboard")) - { - ImGui.SetClipboardText(UiSharedService.GetNotes(_pairManager.DirectPairs.UnionBy(_pairManager.GroupPairs.SelectMany(p => p.Value), p => p.UserData, UserDataComparer.Instance).ToList())); - } - if (_uiShared.IconTextButton(FontAwesomeIcon.FileImport, "Import notes from clipboard")) - { - _notesSuccessfullyApplied = null; - var notes = ImGui.GetClipboardText(); - _notesSuccessfullyApplied = _uiShared.ApplyNotesFromClipboard(notes, _overwriteExistingLabels); - } - ImGui.SameLine(); - ImGui.Checkbox("Overwrite existing notes", ref _overwriteExistingLabels); - _uiShared.DrawHelpText("If this option is selected all already existing notes for UIDs will be overwritten by the imported notes."); - if (_notesSuccessfullyApplied.HasValue && _notesSuccessfullyApplied.Value) + if (_uiShared.MediumTreeNode("Import & Export", UIColors.Get("LightlessPurple"))) { - UiSharedService.ColorTextWrapped("User Notes successfully imported", UIColors.Get("LightlessBlue")); - } - else if (_notesSuccessfullyApplied.HasValue && !_notesSuccessfullyApplied.Value) - { - UiSharedService.ColorTextWrapped("Attempt to import notes from clipboard failed. Check formatting and try again", ImGuiColors.DalamudRed); - } + if (_uiShared.IconTextButton(FontAwesomeIcon.StickyNote, "Export all your user notes to clipboard")) + { + ImGui.SetClipboardText(UiSharedService.GetNotes(_pairManager.DirectPairs.UnionBy(_pairManager.GroupPairs.SelectMany(p => p.Value), p => p.UserData, UserDataComparer.Instance).ToList())); + } + if (_uiShared.IconTextButton(FontAwesomeIcon.FileImport, "Import notes from clipboard")) + { + _notesSuccessfullyApplied = null; + var notes = ImGui.GetClipboardText(); + _notesSuccessfullyApplied = _uiShared.ApplyNotesFromClipboard(notes, _overwriteExistingLabels); + } - var openPopupOnAddition = _configService.Current.OpenPopupOnAdd; + ImGui.SameLine(); + ImGui.Checkbox("Overwrite existing notes", ref _overwriteExistingLabels); + _uiShared.DrawHelpText("If this option is selected all already existing notes for UIDs will be overwritten by the imported notes."); + if (_notesSuccessfullyApplied.HasValue && _notesSuccessfullyApplied.Value) + { + UiSharedService.ColorTextWrapped("User Notes successfully imported", UIColors.Get("LightlessBlue")); + } + else if (_notesSuccessfullyApplied.HasValue && !_notesSuccessfullyApplied.Value) + { + UiSharedService.ColorTextWrapped("Attempt to import notes from clipboard failed. Check formatting and try again", ImGuiColors.DalamudRed); + } - if (ImGui.Checkbox("Open Notes Popup on user addition", ref openPopupOnAddition)) - { - _configService.Current.OpenPopupOnAdd = openPopupOnAddition; - _configService.Save(); + _uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f); + ImGui.TreePop(); } - _uiShared.DrawHelpText("This will open a popup that allows you to set the notes for a user after successfully adding them to your individual pairs."); - - var autoPopulateNotes = _configService.Current.AutoPopulateEmptyNotesFromCharaName; - if (ImGui.Checkbox("Automatically populate notes using player names", ref autoPopulateNotes)) - { - _configService.Current.AutoPopulateEmptyNotesFromCharaName = autoPopulateNotes; - _configService.Save(); - } - _uiShared.DrawHelpText("This will automatically populate user notes using the first encountered player name if the note was not set prior"); ImGui.Separator(); + var openPopupOnAddition = _configService.Current.OpenPopupOnAdd; + + if (_uiShared.MediumTreeNode("Popup & Auto Fill", UIColors.Get("LightlessPurple"))) + { + if (ImGui.Checkbox("Open Notes Popup on user addition", ref openPopupOnAddition)) + { + _configService.Current.OpenPopupOnAdd = openPopupOnAddition; + _configService.Save(); + } + _uiShared.DrawHelpText("This will open a popup that allows you to set the notes for a user after successfully adding them to your individual pairs."); + + var autoPopulateNotes = _configService.Current.AutoPopulateEmptyNotesFromCharaName; + if (ImGui.Checkbox("Automatically populate notes using player names", ref autoPopulateNotes)) + { + _configService.Current.AutoPopulateEmptyNotesFromCharaName = autoPopulateNotes; + _configService.Save(); + } + _uiShared.DrawHelpText("This will automatically populate user notes using the first encountered player name if the note was not set prior"); + + _uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f); + ImGui.TreePop(); + } + + ImGui.Separator(); + ImGui.Dummy(new Vector2(10)); _uiShared.BigText("UI"); + var showNameInsteadOfNotes = _configService.Current.ShowCharacterNameInsteadOfNotesForVisible; var showVisibleSeparate = _configService.Current.ShowVisibleUsersSeparately; var showOfflineSeparate = _configService.Current.ShowOfflineUsersSeparately; @@ -904,380 +942,437 @@ public class SettingsUi : WindowMediatorSubscriberBase var groupInVisible = _configService.Current.ShowSyncshellUsersInVisible; var syncshellOfflineSeparate = _configService.Current.ShowSyncshellOfflineUsersSeparately; - if (ImGui.Checkbox("Enable Game Right Click Menu Entries", ref enableRightClickMenu)) - { - _configService.Current.EnableRightClickMenus = enableRightClickMenu; - _configService.Save(); - } - _uiShared.DrawHelpText("This will add Lightless related right click menu entries in the game UI on paired players."); - if (ImGui.Checkbox("Display status and visible pair count in Server Info Bar", ref enableDtrEntry)) + if (_uiShared.MediumTreeNode("Behavior", UIColors.Get("LightlessPurple"))) { - _configService.Current.EnableDtrEntry = enableDtrEntry; - _configService.Save(); - } - _uiShared.DrawHelpText("This will add Lightless connection status and visible pair count in the Server Info Bar.\nYou can further configure this through your Dalamud Settings."); - - using (ImRaii.Disabled(!enableDtrEntry)) - { - using var indent = ImRaii.PushIndent(); - if (ImGui.Checkbox("Show visible character's UID in tooltip", ref showUidInDtrTooltip)) + if (ImGui.Checkbox("Enable Game Right Click Menu Entries", ref enableRightClickMenu)) { - _configService.Current.ShowUidInDtrTooltip = showUidInDtrTooltip; + _configService.Current.EnableRightClickMenus = enableRightClickMenu; _configService.Save(); } + _uiShared.DrawHelpText("This will add Lightless related right click menu entries in the game UI on paired players."); - if (ImGui.Checkbox("Prefer notes over player names in tooltip", ref preferNoteInDtrTooltip)) + if (ImGui.Checkbox("Display status and visible pair count in Server Info Bar", ref enableDtrEntry)) { - _configService.Current.PreferNoteInDtrTooltip = preferNoteInDtrTooltip; + _configService.Current.EnableDtrEntry = enableDtrEntry; _configService.Save(); } + _uiShared.DrawHelpText("This will add Lightless connection status and visible pair count in the Server Info Bar.\nYou can further configure this through your Dalamud Settings."); - if (ImGui.Checkbox("Color-code the Server Info Bar entry according to status", ref useColorsInDtr)) + using (ImRaii.Disabled(!enableDtrEntry)) { - _configService.Current.UseColorsInDtr = useColorsInDtr; - _configService.Save(); - } - - using (ImRaii.Disabled(!useColorsInDtr)) - { - using var indent2 = ImRaii.PushIndent(); - if (InputDtrColors("Default", ref dtrColorsDefault)) + using var indent = ImRaii.PushIndent(); + if (ImGui.Checkbox("Show visible character's UID in tooltip", ref showUidInDtrTooltip)) { - _configService.Current.DtrColorsDefault = dtrColorsDefault; + _configService.Current.ShowUidInDtrTooltip = showUidInDtrTooltip; _configService.Save(); } - ImGui.SameLine(); - if (InputDtrColors("Not Connected", ref dtrColorsNotConnected)) + if (ImGui.Checkbox("Prefer notes over player names in tooltip", ref preferNoteInDtrTooltip)) { - _configService.Current.DtrColorsNotConnected = dtrColorsNotConnected; + _configService.Current.PreferNoteInDtrTooltip = preferNoteInDtrTooltip; _configService.Save(); } - ImGui.SameLine(); - if (InputDtrColors("Pairs in Range", ref dtrColorsPairsInRange)) + if (ImGui.Checkbox("Color-code the Server Info Bar entry according to status", ref useColorsInDtr)) { - _configService.Current.DtrColorsPairsInRange = dtrColorsPairsInRange; + _configService.Current.UseColorsInDtr = useColorsInDtr; _configService.Save(); } + + using (ImRaii.Disabled(!useColorsInDtr)) + { + using var indent2 = ImRaii.PushIndent(); + if (InputDtrColors("Default", ref dtrColorsDefault)) + { + _configService.Current.DtrColorsDefault = dtrColorsDefault; + _configService.Save(); + } + + ImGui.SameLine(); + if (InputDtrColors("Not Connected", ref dtrColorsNotConnected)) + { + _configService.Current.DtrColorsNotConnected = dtrColorsNotConnected; + _configService.Save(); + } + + ImGui.SameLine(); + if (InputDtrColors("Pairs in Range", ref dtrColorsPairsInRange)) + { + _configService.Current.DtrColorsPairsInRange = dtrColorsPairsInRange; + _configService.Save(); + } + } } - } - var nameColorsEnabled = _configService.Current.IsNameplateColorsEnabled; - var nameColors = _configService.Current.NameplateColors; - var isFriendOverride = _configService.Current.overrideFriendColor; - var isPartyOverride = _configService.Current.overridePartyColor; + var nameColorsEnabled = _configService.Current.IsNameplateColorsEnabled; + var nameColors = _configService.Current.NameplateColors; + var isFriendOverride = _configService.Current.overrideFriendColor; + var isPartyOverride = _configService.Current.overridePartyColor; - if (ImGui.Checkbox("Override name color of visible paired players", ref nameColorsEnabled)) - { - _configService.Current.IsNameplateColorsEnabled = nameColorsEnabled; - _configService.Save(); - _nameplateService.RequestRedraw(); - } - - using (ImRaii.Disabled(!nameColorsEnabled)) - { - using var indent = ImRaii.PushIndent(); - if (InputDtrColors("Name color", ref nameColors)) + if (ImGui.Checkbox("Override name color of visible paired players", ref nameColorsEnabled)) { - _configService.Current.NameplateColors = nameColors; + _configService.Current.IsNameplateColorsEnabled = nameColorsEnabled; _configService.Save(); _nameplateService.RequestRedraw(); } - if (ImGui.Checkbox("Override friend color", ref isFriendOverride)) + + using (ImRaii.Disabled(!nameColorsEnabled)) { - _configService.Current.overrideFriendColor = isFriendOverride; - _configService.Save(); - _nameplateService.RequestRedraw(); + using var indent = ImRaii.PushIndent(); + if (InputDtrColors("Name color", ref nameColors)) + { + _configService.Current.NameplateColors = nameColors; + _configService.Save(); + _nameplateService.RequestRedraw(); + } + if (ImGui.Checkbox("Override friend color", ref isFriendOverride)) + { + _configService.Current.overrideFriendColor = isFriendOverride; + _configService.Save(); + _nameplateService.RequestRedraw(); + } + if (ImGui.Checkbox("Override party color", ref isPartyOverride)) + { + _configService.Current.overridePartyColor = isPartyOverride; + _configService.Save(); + _nameplateService.RequestRedraw(); + } } - if (ImGui.Checkbox("Override party color", ref isPartyOverride)) - { - _configService.Current.overridePartyColor = isPartyOverride; - _configService.Save(); - _nameplateService.RequestRedraw(); - } - } - if (ImGui.Checkbox("Show separate Visible group", ref showVisibleSeparate)) - { - _configService.Current.ShowVisibleUsersSeparately = showVisibleSeparate; - _configService.Save(); - Mediator.Publish(new RefreshUiMessage()); + _uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f); + ImGui.TreePop(); } - _uiShared.DrawHelpText("This will show all currently visible users in a special 'Visible' group in the main UI."); - - using (ImRaii.Disabled(!showVisibleSeparate)) - { - using var indent = ImRaii.PushIndent(); - if (ImGui.Checkbox("Show Syncshell Users in Visible Group", ref groupInVisible)) - { - _configService.Current.ShowSyncshellUsersInVisible = groupInVisible; - _configService.Save(); - Mediator.Publish(new RefreshUiMessage()); - } - } - - if (ImGui.Checkbox("Show separate Offline group", ref showOfflineSeparate)) - { - _configService.Current.ShowOfflineUsersSeparately = showOfflineSeparate; - _configService.Save(); - Mediator.Publish(new RefreshUiMessage()); - } - _uiShared.DrawHelpText("This will show all currently offline users in a special 'Offline' group in the main UI."); - - using (ImRaii.Disabled(!showOfflineSeparate)) - { - using var indent = ImRaii.PushIndent(); - if (ImGui.Checkbox("Show separate Offline group for Syncshell users", ref syncshellOfflineSeparate)) - { - _configService.Current.ShowSyncshellOfflineUsersSeparately = syncshellOfflineSeparate; - _configService.Save(); - Mediator.Publish(new RefreshUiMessage()); - } - } - - if (ImGui.Checkbox("Group up all syncshells in one folder", ref groupUpSyncshells)) - { - _configService.Current.GroupUpSyncshells = groupUpSyncshells; - _configService.Save(); - Mediator.Publish(new RefreshUiMessage()); - } - _uiShared.DrawHelpText("This will group up all Syncshells in a special 'All Syncshells' folder in the main UI."); - - if (ImGui.Checkbox("Show player name for visible players", ref showNameInsteadOfNotes)) - { - _configService.Current.ShowCharacterNameInsteadOfNotesForVisible = showNameInsteadOfNotes; - _configService.Save(); - Mediator.Publish(new RefreshUiMessage()); - } - _uiShared.DrawHelpText("This will show the character name instead of custom set note when a character is visible"); - - ImGui.Indent(); - if (!_configService.Current.ShowCharacterNameInsteadOfNotesForVisible) ImGui.BeginDisabled(); - if (ImGui.Checkbox("Prefer notes over player names for visible players", ref preferNotesInsteadOfName)) - { - _configService.Current.PreferNotesOverNamesForVisible = preferNotesInsteadOfName; - _configService.Save(); - Mediator.Publish(new RefreshUiMessage()); - } - _uiShared.DrawHelpText("If you set a note for a player it will be shown instead of the player name"); - if (!_configService.Current.ShowCharacterNameInsteadOfNotesForVisible) ImGui.EndDisabled(); - ImGui.Unindent(); - - if (ImGui.Checkbox("Set visible pairs as focus targets when clicking the eye", ref useFocusTarget)) - { - _configService.Current.UseFocusTarget = useFocusTarget; - _configService.Save(); - } - - if (ImGui.Checkbox("Show Lightless Profiles on Hover", ref showProfiles)) - { - Mediator.Publish(new ClearProfileDataMessage()); - _configService.Current.ProfilesShow = showProfiles; - _configService.Save(); - } - _uiShared.DrawHelpText("This will show the configured user profile after a set delay"); - ImGui.Indent(); - if (!showProfiles) ImGui.BeginDisabled(); - if (ImGui.Checkbox("Popout profiles on the right", ref profileOnRight)) - { - _configService.Current.ProfilePopoutRight = profileOnRight; - _configService.Save(); - Mediator.Publish(new CompactUiChange(Vector2.Zero, Vector2.Zero)); - } - _uiShared.DrawHelpText("Will show profiles on the right side of the main UI"); - if (ImGui.SliderFloat("Hover Delay", ref profileDelay, 1, 10)) - { - _configService.Current.ProfileDelay = profileDelay; - _configService.Save(); - } - _uiShared.DrawHelpText("Delay until the profile should be displayed"); - if (!showProfiles) ImGui.EndDisabled(); - ImGui.Unindent(); - if (ImGui.Checkbox("Show profiles marked as NSFW", ref showNsfwProfiles)) - { - Mediator.Publish(new ClearProfileDataMessage()); - _configService.Current.ProfilesAllowNsfw = showNsfwProfiles; - _configService.Save(); - } - _uiShared.DrawHelpText("Will show profiles that have the NSFW tag enabled"); ImGui.Separator(); + if (_uiShared.MediumTreeNode("Pair List", UIColors.Get("LightlessPurple"))) + { + if (ImGui.Checkbox("Show separate Visible group", ref showVisibleSeparate)) + { + _configService.Current.ShowVisibleUsersSeparately = showVisibleSeparate; + _configService.Save(); + Mediator.Publish(new RefreshUiMessage()); + } + _uiShared.DrawHelpText("This will show all currently visible users in a special 'Visible' group in the main UI."); + + using (ImRaii.Disabled(!showVisibleSeparate)) + { + using var indent = ImRaii.PushIndent(); + if (ImGui.Checkbox("Show Syncshell Users in Visible Group", ref groupInVisible)) + { + _configService.Current.ShowSyncshellUsersInVisible = groupInVisible; + _configService.Save(); + Mediator.Publish(new RefreshUiMessage()); + } + } + + if (ImGui.Checkbox("Show separate Offline group", ref showOfflineSeparate)) + { + _configService.Current.ShowOfflineUsersSeparately = showOfflineSeparate; + _configService.Save(); + Mediator.Publish(new RefreshUiMessage()); + } + _uiShared.DrawHelpText("This will show all currently offline users in a special 'Offline' group in the main UI."); + + using (ImRaii.Disabled(!showOfflineSeparate)) + { + using var indent = ImRaii.PushIndent(); + if (ImGui.Checkbox("Show separate Offline group for Syncshell users", ref syncshellOfflineSeparate)) + { + _configService.Current.ShowSyncshellOfflineUsersSeparately = syncshellOfflineSeparate; + _configService.Save(); + Mediator.Publish(new RefreshUiMessage()); + } + } + + if (ImGui.Checkbox("Group up all syncshells in one folder", ref groupUpSyncshells)) + { + _configService.Current.GroupUpSyncshells = groupUpSyncshells; + _configService.Save(); + Mediator.Publish(new RefreshUiMessage()); + } + _uiShared.DrawHelpText("This will group up all Syncshells in a special 'All Syncshells' folder in the main UI."); + + if (ImGui.Checkbox("Show player name for visible players", ref showNameInsteadOfNotes)) + { + _configService.Current.ShowCharacterNameInsteadOfNotesForVisible = showNameInsteadOfNotes; + _configService.Save(); + Mediator.Publish(new RefreshUiMessage()); + } + _uiShared.DrawHelpText("This will show the character name instead of custom set note when a character is visible"); + + ImGui.Indent(); + if (!_configService.Current.ShowCharacterNameInsteadOfNotesForVisible) ImGui.BeginDisabled(); + if (ImGui.Checkbox("Prefer notes over player names for visible players", ref preferNotesInsteadOfName)) + { + _configService.Current.PreferNotesOverNamesForVisible = preferNotesInsteadOfName; + _configService.Save(); + Mediator.Publish(new RefreshUiMessage()); + } + _uiShared.DrawHelpText("If you set a note for a player it will be shown instead of the player name"); + if (!_configService.Current.ShowCharacterNameInsteadOfNotesForVisible) ImGui.EndDisabled(); + ImGui.Unindent(); + + if (ImGui.Checkbox("Set visible pairs as focus targets when clicking the eye", ref useFocusTarget)) + { + _configService.Current.UseFocusTarget = useFocusTarget; + _configService.Save(); + } + + _uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f); + ImGui.TreePop(); + } + + ImGui.Separator(); + if (_uiShared.MediumTreeNode("Profiles", UIColors.Get("LightlessPurple"))) + { + if (ImGui.Checkbox("Show Lightless Profiles on Hover", ref showProfiles)) + { + Mediator.Publish(new ClearProfileDataMessage()); + _configService.Current.ProfilesShow = showProfiles; + _configService.Save(); + } + _uiShared.DrawHelpText("This will show the configured user profile after a set delay"); + ImGui.Indent(); + if (!showProfiles) ImGui.BeginDisabled(); + if (ImGui.Checkbox("Popout profiles on the right", ref profileOnRight)) + { + _configService.Current.ProfilePopoutRight = profileOnRight; + _configService.Save(); + Mediator.Publish(new CompactUiChange(Vector2.Zero, Vector2.Zero)); + } + _uiShared.DrawHelpText("Will show profiles on the right side of the main UI"); + if (ImGui.SliderFloat("Hover Delay", ref profileDelay, 1, 10)) + { + _configService.Current.ProfileDelay = profileDelay; + _configService.Save(); + } + _uiShared.DrawHelpText("Delay until the profile should be displayed"); + if (!showProfiles) ImGui.EndDisabled(); + ImGui.Unindent(); + if (ImGui.Checkbox("Show profiles marked as NSFW", ref showNsfwProfiles)) + { + Mediator.Publish(new ClearProfileDataMessage()); + _configService.Current.ProfilesAllowNsfw = showNsfwProfiles; + _configService.Save(); + } + _uiShared.DrawHelpText("Will show profiles that have the NSFW tag enabled"); + + _uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f); + ImGui.TreePop(); + } + + ImGui.Separator(); + ImGui.Dummy(new Vector2(10)); + _uiShared.BigText("Notifications"); + var disableOptionalPluginWarnings = _configService.Current.DisableOptionalPluginWarnings; var onlineNotifs = _configService.Current.ShowOnlineNotifications; var onlineNotifsPairsOnly = _configService.Current.ShowOnlineNotificationsOnlyForIndividualPairs; var onlineNotifsNamedOnly = _configService.Current.ShowOnlineNotificationsOnlyForNamedPairs; - _uiShared.BigText("Notifications"); - _uiShared.DrawCombo("Info Notification Display##settingsUi", (NotificationLocation[])Enum.GetValues(typeof(NotificationLocation)), (i) => i.ToString(), - (i) => + if (_uiShared.MediumTreeNode("Display", UIColors.Get("LightlessPurple"))) { - _configService.Current.InfoNotification = i; - _configService.Save(); - }, _configService.Current.InfoNotification); - _uiShared.DrawHelpText("The location where \"Info\" notifications will display." - + Environment.NewLine + "'Nowhere' will not show any Info notifications" - + Environment.NewLine + "'Chat' will print Info notifications in chat" - + Environment.NewLine + "'Toast' will show Warning toast notifications in the bottom right corner" - + Environment.NewLine + "'Both' will show chat as well as the toast notification"); + _uiShared.DrawCombo("Info Notification Display##settingsUi", (NotificationLocation[])Enum.GetValues(typeof(NotificationLocation)), (i) => i.ToString(), + (i) => + { + _configService.Current.InfoNotification = i; + _configService.Save(); + }, _configService.Current.InfoNotification); + _uiShared.DrawHelpText("The location where \"Info\" notifications will display." + + Environment.NewLine + "'Nowhere' will not show any Info notifications" + + Environment.NewLine + "'Chat' will print Info notifications in chat" + + Environment.NewLine + "'Toast' will show Warning toast notifications in the bottom right corner" + + Environment.NewLine + "'Both' will show chat as well as the toast notification"); - _uiShared.DrawCombo("Warning Notification Display##settingsUi", (NotificationLocation[])Enum.GetValues(typeof(NotificationLocation)), (i) => i.ToString(), - (i) => - { - _configService.Current.WarningNotification = i; - _configService.Save(); - }, _configService.Current.WarningNotification); - _uiShared.DrawHelpText("The location where \"Warning\" notifications will display." - + Environment.NewLine + "'Nowhere' will not show any Warning notifications" - + Environment.NewLine + "'Chat' will print Warning notifications in chat" - + Environment.NewLine + "'Toast' will show Warning toast notifications in the bottom right corner" - + Environment.NewLine + "'Both' will show chat as well as the toast notification"); + _uiShared.DrawCombo("Warning Notification Display##settingsUi", (NotificationLocation[])Enum.GetValues(typeof(NotificationLocation)), (i) => i.ToString(), + (i) => + { + _configService.Current.WarningNotification = i; + _configService.Save(); + }, _configService.Current.WarningNotification); + _uiShared.DrawHelpText("The location where \"Warning\" notifications will display." + + Environment.NewLine + "'Nowhere' will not show any Warning notifications" + + Environment.NewLine + "'Chat' will print Warning notifications in chat" + + Environment.NewLine + "'Toast' will show Warning toast notifications in the bottom right corner" + + Environment.NewLine + "'Both' will show chat as well as the toast notification"); - _uiShared.DrawCombo("Error Notification Display##settingsUi", (NotificationLocation[])Enum.GetValues(typeof(NotificationLocation)), (i) => i.ToString(), - (i) => - { - _configService.Current.ErrorNotification = i; - _configService.Save(); - }, _configService.Current.ErrorNotification); - _uiShared.DrawHelpText("The location where \"Error\" notifications will display." - + Environment.NewLine + "'Nowhere' will not show any Error notifications" - + Environment.NewLine + "'Chat' will print Error notifications in chat" - + Environment.NewLine + "'Toast' will show Error toast notifications in the bottom right corner" - + Environment.NewLine + "'Both' will show chat as well as the toast notification"); + _uiShared.DrawCombo("Error Notification Display##settingsUi", (NotificationLocation[])Enum.GetValues(typeof(NotificationLocation)), (i) => i.ToString(), + (i) => + { + _configService.Current.ErrorNotification = i; + _configService.Save(); + }, _configService.Current.ErrorNotification); + _uiShared.DrawHelpText("The location where \"Error\" notifications will display." + + Environment.NewLine + "'Nowhere' will not show any Error notifications" + + Environment.NewLine + "'Chat' will print Error notifications in chat" + + Environment.NewLine + "'Toast' will show Error toast notifications in the bottom right corner" + + Environment.NewLine + "'Both' will show chat as well as the toast notification"); - if (ImGui.Checkbox("Disable optional plugin warnings", ref disableOptionalPluginWarnings)) - { - _configService.Current.DisableOptionalPluginWarnings = disableOptionalPluginWarnings; - _configService.Save(); + _uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f); + ImGui.TreePop(); } - _uiShared.DrawHelpText("Enabling this will not show any \"Warning\" labeled messages for missing optional plugins."); - if (ImGui.Checkbox("Enable online notifications", ref onlineNotifs)) - { - _configService.Current.ShowOnlineNotifications = onlineNotifs; - _configService.Save(); - } - _uiShared.DrawHelpText("Enabling this will show a small notification (type: Info) in the bottom right corner when pairs go online."); - using var disabled = ImRaii.Disabled(!onlineNotifs); - if (ImGui.Checkbox("Notify only for individual pairs", ref onlineNotifsPairsOnly)) + ImGui.Separator(); + + if (_uiShared.MediumTreeNode("Toggles", UIColors.Get("LightlessPurple"))) { - _configService.Current.ShowOnlineNotificationsOnlyForIndividualPairs = onlineNotifsPairsOnly; - _configService.Save(); + if (ImGui.Checkbox("Disable optional plugin warnings", ref disableOptionalPluginWarnings)) + { + _configService.Current.DisableOptionalPluginWarnings = disableOptionalPluginWarnings; + _configService.Save(); + } + _uiShared.DrawHelpText("Enabling this will not show any \"Warning\" labeled messages for missing optional plugins."); + if (ImGui.Checkbox("Enable online notifications", ref onlineNotifs)) + { + _configService.Current.ShowOnlineNotifications = onlineNotifs; + _configService.Save(); + } + _uiShared.DrawHelpText("Enabling this will show a small notification (type: Info) in the bottom right corner when pairs go online."); + + using var disabled = ImRaii.Disabled(!onlineNotifs); + if (ImGui.Checkbox("Notify only for individual pairs", ref onlineNotifsPairsOnly)) + { + _configService.Current.ShowOnlineNotificationsOnlyForIndividualPairs = onlineNotifsPairsOnly; + _configService.Save(); + } + _uiShared.DrawHelpText("Enabling this will only show online notifications (type: Info) for individual pairs."); + if (ImGui.Checkbox("Notify only for named pairs", ref onlineNotifsNamedOnly)) + { + _configService.Current.ShowOnlineNotificationsOnlyForNamedPairs = onlineNotifsNamedOnly; + _configService.Save(); + } + _uiShared.DrawHelpText("Enabling this will only show online notifications (type: Info) for pairs where you have set an individual note."); + + _uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f); + ImGui.TreePop(); } - _uiShared.DrawHelpText("Enabling this will only show online notifications (type: Info) for individual pairs."); - if (ImGui.Checkbox("Notify only for named pairs", ref onlineNotifsNamedOnly)) - { - _configService.Current.ShowOnlineNotificationsOnlyForNamedPairs = onlineNotifsNamedOnly; - _configService.Save(); - } - _uiShared.DrawHelpText("Enabling this will only show online notifications (type: Info) for pairs where you have set an individual note."); } private void DrawPerformance() { - _uiShared.BigText("Performance Settings"); + _uiShared.UnderlinedBigText("Performance Settings", UIColors.Get("LightlessBlue")); + ImGui.Dummy(new Vector2(10)); UiSharedService.TextWrapped("The configuration options here are to give you more informed warnings and automation when it comes to other performance-intensive synced players."); - ImGui.Dummy(new Vector2(10)); - ImGui.Separator(); - ImGui.Dummy(new Vector2(10)); + bool showPerformanceIndicator = _playerPerformanceConfigService.Current.ShowPerformanceIndicator; - if (ImGui.Checkbox("Show performance indicator", ref showPerformanceIndicator)) + + if (_uiShared.MediumTreeNode("Warnings", UIColors.Get("LightlessPurple"))) { - _playerPerformanceConfigService.Current.ShowPerformanceIndicator = showPerformanceIndicator; - _playerPerformanceConfigService.Save(); - } - _uiShared.DrawHelpText("Will show a performance indicator when players exceed defined thresholds in Lightless UI." + Environment.NewLine + "Will use warning thresholds."); - bool warnOnExceedingThresholds = _playerPerformanceConfigService.Current.WarnOnExceedingThresholds; - if (ImGui.Checkbox("Warn on loading in players exceeding performance thresholds", ref warnOnExceedingThresholds)) - { - _playerPerformanceConfigService.Current.WarnOnExceedingThresholds = warnOnExceedingThresholds; - _playerPerformanceConfigService.Save(); - } - _uiShared.DrawHelpText("Lightless will print a warning in chat once per session of meeting those people. Will not warn on players with preferred permissions."); - using (ImRaii.Disabled(!warnOnExceedingThresholds && !showPerformanceIndicator)) - { - using var indent = ImRaii.PushIndent(); - var warnOnPref = _playerPerformanceConfigService.Current.WarnOnPreferredPermissionsExceedingThresholds; - if (ImGui.Checkbox("Warn/Indicate also on players with preferred permissions", ref warnOnPref)) + if (ImGui.Checkbox("Show performance indicator", ref showPerformanceIndicator)) { - _playerPerformanceConfigService.Current.WarnOnPreferredPermissionsExceedingThresholds = warnOnPref; + _playerPerformanceConfigService.Current.ShowPerformanceIndicator = showPerformanceIndicator; _playerPerformanceConfigService.Save(); } - _uiShared.DrawHelpText("Lightless will also print warnings and show performance indicator for players where you enabled preferred permissions. If warning in general is disabled, this will not produce any warnings."); - } - using (ImRaii.Disabled(!showPerformanceIndicator && !warnOnExceedingThresholds)) - { - var vram = _playerPerformanceConfigService.Current.VRAMSizeWarningThresholdMiB; - var tris = _playerPerformanceConfigService.Current.TrisWarningThresholdThousands; - ImGui.SetNextItemWidth(100 * ImGuiHelpers.GlobalScale); - if (ImGui.InputInt("Warning VRAM threshold", ref vram)) + _uiShared.DrawHelpText("Will show a performance indicator when players exceed defined thresholds in Lightless UI." + Environment.NewLine + "Will use warning thresholds."); + bool warnOnExceedingThresholds = _playerPerformanceConfigService.Current.WarnOnExceedingThresholds; + if (ImGui.Checkbox("Warn on loading in players exceeding performance thresholds", ref warnOnExceedingThresholds)) { - _playerPerformanceConfigService.Current.VRAMSizeWarningThresholdMiB = vram; + _playerPerformanceConfigService.Current.WarnOnExceedingThresholds = warnOnExceedingThresholds; _playerPerformanceConfigService.Save(); } - ImGui.SameLine(); - ImGui.Text("(MiB)"); - _uiShared.DrawHelpText("Limit in MiB of approximate VRAM usage to trigger warning or performance indicator on UI." + UiSharedService.TooltipSeparator - + "Default: 375 MiB"); - ImGui.SetNextItemWidth(100 * ImGuiHelpers.GlobalScale); - if (ImGui.InputInt("Warning Triangle threshold", ref tris)) + _uiShared.DrawHelpText("Lightless will print a warning in chat once per session of meeting those people. Will not warn on players with preferred permissions."); + using (ImRaii.Disabled(!warnOnExceedingThresholds && !showPerformanceIndicator)) { - _playerPerformanceConfigService.Current.TrisWarningThresholdThousands = tris; - _playerPerformanceConfigService.Save(); + using var indent = ImRaii.PushIndent(); + var warnOnPref = _playerPerformanceConfigService.Current.WarnOnPreferredPermissionsExceedingThresholds; + if (ImGui.Checkbox("Warn/Indicate also on players with preferred permissions", ref warnOnPref)) + { + _playerPerformanceConfigService.Current.WarnOnPreferredPermissionsExceedingThresholds = warnOnPref; + _playerPerformanceConfigService.Save(); + } + _uiShared.DrawHelpText("Lightless will also print warnings and show performance indicator for players where you enabled preferred permissions. If warning in general is disabled, this will not produce any warnings."); } - ImGui.SameLine(); - ImGui.Text("(thousand triangles)"); - _uiShared.DrawHelpText("Limit in approximate used triangles from mods to trigger warning or performance indicator on UI." + UiSharedService.TooltipSeparator - + "Default: 165 thousand"); + using (ImRaii.Disabled(!showPerformanceIndicator && !warnOnExceedingThresholds)) + { + var vram = _playerPerformanceConfigService.Current.VRAMSizeWarningThresholdMiB; + var tris = _playerPerformanceConfigService.Current.TrisWarningThresholdThousands; + ImGui.SetNextItemWidth(100 * ImGuiHelpers.GlobalScale); + if (ImGui.InputInt("Warning VRAM threshold", ref vram)) + { + _playerPerformanceConfigService.Current.VRAMSizeWarningThresholdMiB = vram; + _playerPerformanceConfigService.Save(); + } + ImGui.SameLine(); + ImGui.Text("(MiB)"); + _uiShared.DrawHelpText("Limit in MiB of approximate VRAM usage to trigger warning or performance indicator on UI." + UiSharedService.TooltipSeparator + + "Default: 375 MiB"); + ImGui.SetNextItemWidth(100 * ImGuiHelpers.GlobalScale); + if (ImGui.InputInt("Warning Triangle threshold", ref tris)) + { + _playerPerformanceConfigService.Current.TrisWarningThresholdThousands = tris; + _playerPerformanceConfigService.Save(); + } + ImGui.SameLine(); + ImGui.Text("(thousand triangles)"); + _uiShared.DrawHelpText("Limit in approximate used triangles from mods to trigger warning or performance indicator on UI." + UiSharedService.TooltipSeparator + + "Default: 165 thousand"); + } + + _uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f); + ImGui.TreePop(); } - ImGui.Dummy(new Vector2(10)); + + ImGui.Separator(); + bool autoPause = _playerPerformanceConfigService.Current.AutoPausePlayersExceedingThresholds; bool autoPauseEveryone = _playerPerformanceConfigService.Current.AutoPausePlayersWithPreferredPermissionsExceedingThresholds; - if (ImGui.Checkbox("Automatically pause players exceeding thresholds", ref autoPause)) + + if (_uiShared.MediumTreeNode("Auto Pause", UIColors.Get("LightlessPurple"))) { - _playerPerformanceConfigService.Current.AutoPausePlayersExceedingThresholds = autoPause; - _playerPerformanceConfigService.Save(); - } - _uiShared.DrawHelpText("When enabled, it will automatically pause all players without preferred permissions that exceed the thresholds defined below." + Environment.NewLine - + "Will print a warning in chat when a player got paused automatically." - + UiSharedService.TooltipSeparator + "Warning: this will not automatically unpause those people again, you will have to do this manually."); - using (ImRaii.Disabled(!autoPause)) - { - using var indent = ImRaii.PushIndent(); - if (ImGui.Checkbox("Automatically pause also players with preferred permissions", ref autoPauseEveryone)) - { - _playerPerformanceConfigService.Current.AutoPausePlayersWithPreferredPermissionsExceedingThresholds = autoPauseEveryone; - _playerPerformanceConfigService.Save(); - } - _uiShared.DrawHelpText("When enabled, will automatically pause all players regardless of preferred permissions that exceed thresholds defined below." + UiSharedService.TooltipSeparator + - "Warning: this will not automatically unpause those people again, you will have to do this manually."); - var vramAuto = _playerPerformanceConfigService.Current.VRAMSizeAutoPauseThresholdMiB; - var trisAuto = _playerPerformanceConfigService.Current.TrisAutoPauseThresholdThousands; - ImGui.SetNextItemWidth(100 * ImGuiHelpers.GlobalScale); - if (ImGui.InputInt("Auto Pause VRAM threshold", ref vramAuto)) - { - _playerPerformanceConfigService.Current.VRAMSizeAutoPauseThresholdMiB = vramAuto; - _playerPerformanceConfigService.Save(); - } - ImGui.SameLine(); - ImGui.Text("(MiB)"); - _uiShared.DrawHelpText("When a loading in player and their VRAM usage exceeds this amount, automatically pauses the synced player." + UiSharedService.TooltipSeparator - + "Default: 550 MiB"); - ImGui.SetNextItemWidth(100 * ImGuiHelpers.GlobalScale); - if (ImGui.InputInt("Auto Pause Triangle threshold", ref trisAuto)) - { - _playerPerformanceConfigService.Current.TrisAutoPauseThresholdThousands = trisAuto; - _playerPerformanceConfigService.Save(); - } - ImGui.SameLine(); - ImGui.Text("(thousand triangles)"); - _uiShared.DrawHelpText("When a loading in player and their triangle count exceeds this amount, automatically pauses the synced player." + UiSharedService.TooltipSeparator - + "Default: 250 thousand"); + if (ImGui.Checkbox("Automatically pause players exceeding thresholds", ref autoPause)) + { + _playerPerformanceConfigService.Current.AutoPausePlayersExceedingThresholds = autoPause; + _playerPerformanceConfigService.Save(); + } + _uiShared.DrawHelpText("When enabled, it will automatically pause all players without preferred permissions that exceed the thresholds defined below." + Environment.NewLine + + "Will print a warning in chat when a player got paused automatically." + + UiSharedService.TooltipSeparator + "Warning: this will not automatically unpause those people again, you will have to do this manually."); + using (ImRaii.Disabled(!autoPause)) + { + using var indent = ImRaii.PushIndent(); + if (ImGui.Checkbox("Automatically pause also players with preferred permissions", ref autoPauseEveryone)) + { + _playerPerformanceConfigService.Current.AutoPausePlayersWithPreferredPermissionsExceedingThresholds = autoPauseEveryone; + _playerPerformanceConfigService.Save(); + } + _uiShared.DrawHelpText("When enabled, will automatically pause all players regardless of preferred permissions that exceed thresholds defined below." + UiSharedService.TooltipSeparator + + "Warning: this will not automatically unpause those people again, you will have to do this manually."); + var vramAuto = _playerPerformanceConfigService.Current.VRAMSizeAutoPauseThresholdMiB; + var trisAuto = _playerPerformanceConfigService.Current.TrisAutoPauseThresholdThousands; + ImGui.SetNextItemWidth(100 * ImGuiHelpers.GlobalScale); + if (ImGui.InputInt("Auto Pause VRAM threshold", ref vramAuto)) + { + _playerPerformanceConfigService.Current.VRAMSizeAutoPauseThresholdMiB = vramAuto; + _playerPerformanceConfigService.Save(); + } + ImGui.SameLine(); + ImGui.Text("(MiB)"); + _uiShared.DrawHelpText("When a loading in player and their VRAM usage exceeds this amount, automatically pauses the synced player." + UiSharedService.TooltipSeparator + + "Default: 550 MiB"); + ImGui.SetNextItemWidth(100 * ImGuiHelpers.GlobalScale); + if (ImGui.InputInt("Auto Pause Triangle threshold", ref trisAuto)) + { + _playerPerformanceConfigService.Current.TrisAutoPauseThresholdThousands = trisAuto; + _playerPerformanceConfigService.Save(); + } + ImGui.SameLine(); + ImGui.Text("(thousand triangles)"); + _uiShared.DrawHelpText("When a loading in player and their triangle count exceeds this amount, automatically pauses the synced player." + UiSharedService.TooltipSeparator + + "Default: 250 thousand"); + } + + _uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f); + ImGui.TreePop(); } + + ImGui.Separator(); ImGui.Dummy(new Vector2(10)); - _uiShared.BigText("Whitelisted UIDs"); + + _uiShared.UnderlinedBigText("Whitelisted UIDs", UIColors.Get("LightlessBlue")); + ImGuiHelpers.ScaledDummy(5); + UiSharedService.TextWrapped("The entries in the list below will be ignored for all warnings and auto pause operations."); ImGui.Dummy(new Vector2(10)); ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale); @@ -1328,87 +1423,99 @@ public class SettingsUi : WindowMediatorSubscriberBase _lastTab = "Service Settings"; if (ApiController.ServerAlive) { - _uiShared.BigText("Service Actions"); - ImGuiHelpers.ScaledDummy(new Vector2(5, 5)); - if (ImGui.Button("Delete all my files")) + _uiShared.UnderlinedBigText("Service Actions", UIColors.Get("LightlessBlue")); + + ImGui.Dummy(new Vector2(10)); + if (_uiShared.MediumTreeNode("Deletion", UIColors.Get("DimRed"))) { - _deleteFilesPopupModalShown = true; - ImGui.OpenPopup("Delete all your files?"); - } - - _uiShared.DrawHelpText("Completely deletes all your uploaded files on the service."); - - if (ImGui.BeginPopupModal("Delete all your files?", ref _deleteFilesPopupModalShown, UiSharedService.PopupWindowFlags)) - { - UiSharedService.TextWrapped( - "All your own uploaded files on the service will be deleted.\nThis operation cannot be undone."); - ImGui.TextUnformatted("Are you sure you want to continue?"); - ImGui.Separator(); - ImGui.Spacing(); - - var buttonSize = (ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X - - ImGui.GetStyle().ItemSpacing.X) / 2; - - if (ImGui.Button("Delete everything", new Vector2(buttonSize, 0))) + ImGuiHelpers.ScaledDummy(new Vector2(5, 5)); + if (ImGui.Button("Delete all my files")) { - _ = Task.Run(_fileTransferManager.DeleteAllFiles); - _deleteFilesPopupModalShown = false; + _deleteFilesPopupModalShown = true; + ImGui.OpenPopup("Delete all your files?"); } + _uiShared.DrawHelpText("Completely deletes all your uploaded files on the service."); + + if (ImGui.BeginPopupModal("Delete all your files?", ref _deleteFilesPopupModalShown, UiSharedService.PopupWindowFlags)) + { + UiSharedService.TextWrapped( + "All your own uploaded files on the service will be deleted.\nThis operation cannot be undone."); + ImGui.TextUnformatted("Are you sure you want to continue?"); + ImGui.Separator(); + ImGui.Spacing(); + + var buttonSize = (ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X - + ImGui.GetStyle().ItemSpacing.X) / 2; + + if (ImGui.Button("Delete everything", new Vector2(buttonSize, 0))) + { + _ = Task.Run(_fileTransferManager.DeleteAllFiles); + _deleteFilesPopupModalShown = false; + } + + ImGui.SameLine(); + + if (ImGui.Button("Cancel##cancelDelete", new Vector2(buttonSize, 0))) + { + _deleteFilesPopupModalShown = false; + } + + UiSharedService.SetScaledWindowSize(325); + ImGui.EndPopup(); + } ImGui.SameLine(); - - if (ImGui.Button("Cancel##cancelDelete", new Vector2(buttonSize, 0))) + if (ImGui.Button("Delete account")) { - _deleteFilesPopupModalShown = false; + _deleteAccountPopupModalShown = true; + ImGui.OpenPopup("Delete your account?"); } - UiSharedService.SetScaledWindowSize(325); - ImGui.EndPopup(); - } - ImGui.SameLine(); - if (ImGui.Button("Delete account")) - { - _deleteAccountPopupModalShown = true; - ImGui.OpenPopup("Delete your account?"); - } + _uiShared.DrawHelpText("Completely deletes your account and all uploaded files to the service."); - _uiShared.DrawHelpText("Completely deletes your account and all uploaded files to the service."); - - if (ImGui.BeginPopupModal("Delete your account?", ref _deleteAccountPopupModalShown, UiSharedService.PopupWindowFlags)) - { - UiSharedService.TextWrapped( - "Your account and all associated files and data on the service will be deleted."); - UiSharedService.TextWrapped("Your UID will be removed from all pairing lists."); - ImGui.TextUnformatted("Are you sure you want to continue?"); - ImGui.Separator(); - ImGui.Spacing(); - - var buttonSize = (ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X - - ImGui.GetStyle().ItemSpacing.X) / 2; - - if (ImGui.Button("Delete account", new Vector2(buttonSize, 0))) + if (ImGui.BeginPopupModal("Delete your account?", ref _deleteAccountPopupModalShown, UiSharedService.PopupWindowFlags)) { - _ = Task.Run(ApiController.UserDelete); - _deleteAccountPopupModalShown = false; - Mediator.Publish(new SwitchToIntroUiMessage()); + UiSharedService.TextWrapped( + "Your account and all associated files and data on the service will be deleted."); + UiSharedService.TextWrapped("Your UID will be removed from all pairing lists."); + ImGui.TextUnformatted("Are you sure you want to continue?"); + ImGui.Separator(); + ImGui.Spacing(); + + var buttonSize = (ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X - + ImGui.GetStyle().ItemSpacing.X) / 2; + + if (ImGui.Button("Delete account", new Vector2(buttonSize, 0))) + { + _ = Task.Run(ApiController.UserDelete); + _deleteAccountPopupModalShown = false; + Mediator.Publish(new SwitchToIntroUiMessage()); + } + + ImGui.SameLine(); + + if (ImGui.Button("Cancel##cancelDelete", new Vector2(buttonSize, 0))) + { + _deleteAccountPopupModalShown = false; + } + + UiSharedService.SetScaledWindowSize(325); + ImGui.EndPopup(); } - ImGui.SameLine(); - - if (ImGui.Button("Cancel##cancelDelete", new Vector2(buttonSize, 0))) - { - _deleteAccountPopupModalShown = false; - } - - UiSharedService.SetScaledWindowSize(325); - ImGui.EndPopup(); + _uiShared.ColoredSeparator(UIColors.Get("DimRed"), 1.5f); + ImGui.TreePop(); } + ImGui.Separator(); } - _uiShared.BigText("Service & Character Settings"); - ImGuiHelpers.ScaledDummy(new Vector2(5, 5)); + ImGui.Dummy(new Vector2(10)); + _uiShared.MediumText("Service & Character Settings", UIColors.Get("LightlessPurple")); + ImGui.Dummy(new Vector2(5)); + var sendCensus = _serverConfigurationManager.SendCensusData; + if (ImGui.Checkbox("Send Statistical Census Data", ref sendCensus)) { _serverConfigurationManager.SendCensusData = sendCensus; @@ -1881,6 +1988,8 @@ public class SettingsUi : WindowMediatorSubscriberBase } ImGui.EndTabBar(); } + + ImGui.Dummy(new Vector2(10)); } private int _lastSelectedServerIndex = -1; diff --git a/LightlessSync/UI/UIColors.cs b/LightlessSync/UI/UIColors.cs index e86d564..a93f904 100644 --- a/LightlessSync/UI/UIColors.cs +++ b/LightlessSync/UI/UIColors.cs @@ -8,9 +8,10 @@ namespace LightlessSync.UI private static readonly Dictionary HexColors = new(StringComparer.OrdinalIgnoreCase) { { "LightlessPurple", "#ad8af5" }, - { "LightlessBlue", "#64c7e8" }, - { "PairBlue", "#4e98b1" }, - { "DimRed", "#bd0000" }, + { "LightlessBlue", "#a6c2ff" }, + { "LightlessYellow", "#ffe97a" }, + { "PairBlue", "#88a2db" }, + { "DimRed", "#d44444" }, }; public static Vector4 Get(string name) diff --git a/LightlessSync/UI/UISharedService.cs b/LightlessSync/UI/UISharedService.cs index 79cbba1..acd8c1c 100644 --- a/LightlessSync/UI/UISharedService.cs +++ b/LightlessSync/UI/UISharedService.cs @@ -114,6 +114,15 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase SizePx = 35 })); }); + + MediumFont = _pluginInterface.UiBuilder.FontAtlas.NewDelegateFontHandle(e => + { + e.OnPreBuild(tk => tk.AddDalamudAssetFont(Dalamud.DalamudAsset.NotoSansJpMedium, new() + { + SizePx = 22, + })); + }); + GameFont = _pluginInterface.UiBuilder.FontAtlas.NewGameFontHandle(new(GameFontFamilyAndSize.Axis12)); IconFont = _pluginInterface.UiBuilder.IconFontFixedWidthHandle; } @@ -133,6 +142,8 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase public string PlayerName => _dalamudUtil.GetPlayerName(); public IFontHandle UidFont { get; init; } + public IFontHandle MediumFont { get; init; } + public Dictionary WorldData => _dalamudUtil.WorldData.Value; public uint WorldId => _dalamudUtil.GetHomeWorldId(); @@ -434,6 +445,79 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase FontText(text, UidFont, color); } + public void UnderlinedBigText( + string text, + Vector4? textColor = null, + Vector4? underlineColor = null, + float underlineThickness = 2f) + { + using var font = UidFont.Push(); + + var drawList = ImGui.GetWindowDrawList(); + var textSize = ImGui.CalcTextSize(text); + var pos = ImGui.GetCursorScreenPos(); + var text_color = textColor ?? ImGuiColors.DalamudWhite; + var line_color = underlineColor ?? text_color; + + ImGui.PushStyleColor(ImGuiCol.Text, text_color); + ImGui.TextUnformatted(text); + ImGui.PopStyleColor(); + + var lineY = pos.Y + textSize.Y + 2f; + drawList.AddLine( + new Vector2(pos.X, lineY), + new Vector2(pos.X + textSize.X, lineY), + ImGui.GetColorU32(line_color), + underlineThickness * ImGuiHelpers.GlobalScale + ); + } + + public void ColoredSeparator(Vector4? color = null, float thickness = 1f, float indent = 0f) + { + var drawList = ImGui.GetWindowDrawList(); + var min = ImGui.GetCursorScreenPos(); + var max = new Vector2(min.X + ImGui.GetContentRegionAvail().X, min.Y); + + min.X += indent; + max.X -= indent; + + drawList.AddLine( + min, + new Vector2(max.X, min.Y), + ImGui.GetColorU32(color ?? ImGuiColors.DalamudGrey), + thickness * ImGuiHelpers.GlobalScale + ); + + ImGui.Dummy(new Vector2(0, thickness * ImGuiHelpers.GlobalScale)); + } + + public void MediumText(string text, Vector4? color = null) + { + FontText(text, MediumFont, color); + } + + public bool MediumTreeNode(string label, Vector4? textColor = null, float lineWidth = 2f, ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags.SpanAvailWidth) + { + using var font = MediumFont.Push(); + var lineColor = textColor ?? ImGuiColors.DalamudWhite; + + var textSize = ImGui.CalcTextSize(label); + var cursorScreen = ImGui.GetCursorScreenPos(); + var cursorLocal = ImGui.GetCursorPos(); + + ImGui.GetWindowDrawList().AddLine( + new Vector2(cursorScreen.X, cursorScreen.Y), + new Vector2(cursorScreen.X, cursorScreen.Y + textSize.Y), + ImGui.GetColorU32(lineColor), + lineWidth * ImGuiHelpers.GlobalScale + ); + + ImGui.SetCursorPosX(cursorLocal.X + 6f); + using var color = ImRaii.PushColor(ImGuiCol.Text, lineColor); + + return ImGui.TreeNodeEx(label, flags); + } + public void BooleanToColoredIcon(bool value, bool inline = true) { using var colorgreen = ImRaii.PushColor(ImGuiCol.Text, UIColors.Get("LightlessBlue"), value); @@ -1085,6 +1169,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase UidFont.Dispose(); GameFont.Dispose(); + MediumFont.Dispose(); } private static void CenterWindow(float width, float height, ImGuiCond cond = ImGuiCond.None)