Files
LightlessClient/LightlessSync/UI/EventViewerUI.cs
defnotken 835a0a637d
All checks were successful
Tag and Release Lightless / tag-and-release (push) Successful in 2m27s
2.0.0 (#92)
2.0.0 Changes:

- Reworked shell finder UI with compact or list view with profile tags showing with the listing, allowing moderators to broadcast the syncshell as well to have it be used more.
- Reworked user list in syncshell admin screen to have filter visible and moved away from table to its own thing, allowing to copy uid/note/alias when clicking on the name.
- Reworked download bars and download box to make it look more modern, removed the jitter around, so it shouldn't vibrate around much.
- Chat has been added to the top menu, working in Zone or in Syncshells to be used there.
- Paired system has been revamped to make pausing and unpausing faster, and loading people should be faster as well.
- Moved to the internal object table to have faster load times for users; people should load in faster
- Compactor is running on a multi-threaded level instead of single-threaded; this should increase the speed of compacting files
- Nameplate Service has been reworked so it wouldn't use the nameplate handler anymore.
- Files can be resized when downloading to reduce load on users if they aren't compressed. (can be toggled to resize all).
- Penumbra Collections are now only made when people are visible, reducing the load on boot-up when having many syncshells in your list.
- Lightfinder plates have been moved away from using Nameplates, but will use an overlay.
- Main UI has been changed a bit with a gradient, and on hover will glow up now.
- Reworked Profile UI for Syncshell and Users to be more user-facing with more customizable items.
- Reworked Settings UI to look more modern.
- Performance should be better due to new systems that would dispose of the collections and better caching of items.

Co-authored-by: defnotken <itsdefnotken@gmail.com>
Co-authored-by: azyges <aaaaaa@aaa.aaa>
Co-authored-by: choco <choco@patat.nl>
Co-authored-by: cake <admin@cakeandbanana.nl>
Co-authored-by: Minmoose <KennethBohr@outlook.com>
Reviewed-on: #92
2025-12-21 17:19:34 +00:00

242 lines
9.6 KiB
C#

using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Utility.Raii;
using LightlessSync.Services;
using LightlessSync.Services.Events;
using LightlessSync.Services.Mediator;
using LightlessSync.Utils;
using Microsoft.Extensions.Logging;
using System.Diagnostics;
using System.Globalization;
using System.Numerics;
namespace LightlessSync.UI;
internal class EventViewerUI : WindowMediatorSubscriberBase
{
private readonly EventAggregator _eventAggregator;
private readonly UiSharedService _uiSharedService;
private List<Event> _currentEvents = new();
private Lazy<List<Event>> _filteredEvents;
private string _filterFreeText = string.Empty;
private string _filterCharacter = string.Empty;
private string _filterUid = string.Empty;
private string _filterSource = string.Empty;
private string _filterEvent = string.Empty;
private List<Event> CurrentEvents
{
get
{
return _currentEvents;
}
set
{
_currentEvents = value;
_filteredEvents = RecreateFilter();
}
}
public EventViewerUI(ILogger<EventViewerUI> logger, LightlessMediator mediator,
EventAggregator eventAggregator, UiSharedService uiSharedService, PerformanceCollectorService performanceCollectorService)
: base(logger, mediator, "Event Viewer", performanceCollectorService)
{
_eventAggregator = eventAggregator;
_uiSharedService = uiSharedService;
WindowBuilder.For(this)
.SetSizeConstraints(new Vector2(600, 500), new Vector2(1000, 2000))
.Apply();
_filteredEvents = RecreateFilter();
}
private Lazy<List<Event>> RecreateFilter()
{
return new(() =>
CurrentEvents.Where(f =>
(string.IsNullOrEmpty(_filterFreeText)
|| (f.EventSource.Contains(_filterFreeText, StringComparison.OrdinalIgnoreCase)
|| f.Character.Contains(_filterFreeText, StringComparison.OrdinalIgnoreCase)
|| f.UID.Contains(_filterFreeText, StringComparison.OrdinalIgnoreCase)
|| f.Message.Contains(_filterFreeText, StringComparison.OrdinalIgnoreCase)
))
&&
(string.IsNullOrEmpty(_filterUid)
|| (f.UID.Contains(_filterUid, StringComparison.OrdinalIgnoreCase))
)
&&
(string.IsNullOrEmpty(_filterSource)
|| (f.EventSource.Contains(_filterSource, StringComparison.OrdinalIgnoreCase))
)
&&
(string.IsNullOrEmpty(_filterCharacter)
|| (f.Character.Contains(_filterCharacter, StringComparison.OrdinalIgnoreCase))
)
&&
(string.IsNullOrEmpty(_filterEvent)
|| (f.Message.Contains(_filterEvent, StringComparison.OrdinalIgnoreCase))
)
).ToList());
}
private void ClearFilters()
{
_filterFreeText = string.Empty;
_filterCharacter = string.Empty;
_filterUid = string.Empty;
_filterSource = string.Empty;
_filterEvent = string.Empty;
_filteredEvents = RecreateFilter();
}
public override void OnOpen()
{
CurrentEvents = _eventAggregator.EventList.Value.OrderByDescending(f => f.EventTime).ToList();
ClearFilters();
}
protected override void DrawInternal()
{
using (ImRaii.Disabled(!_eventAggregator.NewEventsAvailable))
{
if (_uiSharedService.IconTextButton(FontAwesomeIcon.ArrowsToCircle, "Refresh events"))
{
CurrentEvents = _eventAggregator.EventList.Value.OrderByDescending(f => f.EventTime).ToList();
}
}
if (_eventAggregator.NewEventsAvailable)
{
ImGui.SameLine();
ImGui.AlignTextToFramePadding();
UiSharedService.ColorTextWrapped("New events are available, press refresh to update", UIColors.Get("LightlessYellow"));
}
var buttonSize = _uiSharedService.GetIconTextButtonSize(FontAwesomeIcon.FolderOpen, "Open EventLog Folder");
var dist = ImGui.GetWindowContentRegionMax().X - buttonSize;
ImGui.SameLine(dist);
if (_uiSharedService.IconTextButton(FontAwesomeIcon.FolderOpen, "Open EventLog folder"))
{
ProcessStartInfo ps = new()
{
FileName = _eventAggregator.EventLogFolder,
UseShellExecute = true,
WindowStyle = ProcessWindowStyle.Normal
};
Process.Start(ps);
}
_uiSharedService.BigText("Last Events");
var foldOut = ImRaii.TreeNode("Filter");
if (foldOut)
{
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Ban, "Clear Filters"))
{
ClearFilters();
}
bool changedFilter = false;
ImGui.SetNextItemWidth(200);
changedFilter |= ImGui.InputText("Search all columns", ref _filterFreeText, 50);
ImGui.SetNextItemWidth(200);
changedFilter |= ImGui.InputText("Filter by Source", ref _filterSource, 50);
ImGui.SetNextItemWidth(200);
changedFilter |= ImGui.InputText("Filter by UID", ref _filterUid, 50);
ImGui.SetNextItemWidth(200);
changedFilter |= ImGui.InputText("Filter by Character", ref _filterCharacter, 50);
ImGui.SetNextItemWidth(200);
changedFilter |= ImGui.InputText("Filter by Event", ref _filterEvent, 50);
if (changedFilter) _filteredEvents = RecreateFilter();
}
foldOut.Dispose();
var cursorPos = ImGui.GetCursorPosY();
var max = ImGui.GetWindowContentRegionMax();
var min = ImGui.GetWindowContentRegionMin();
var width = max.X - min.X;
var height = max.Y - cursorPos;
using var table = ImRaii.Table("eventTable", 6, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.ScrollY | ImGuiTableFlags.RowBg,
new Vector2(width, height));
if (table)
{
ImGui.TableSetupScrollFreeze(0, 1);
ImGui.TableSetupColumn(string.Empty, ImGuiTableColumnFlags.NoSort);
ImGui.TableSetupColumn("Time");
ImGui.TableSetupColumn("Source");
ImGui.TableSetupColumn("UID");
ImGui.TableSetupColumn("Character");
ImGui.TableSetupColumn("Event");
ImGui.TableHeadersRow();
foreach (var ev in _filteredEvents.Value)
{
var icon = ev.EventSeverity switch
{
EventSeverity.Informational => FontAwesomeIcon.InfoCircle,
EventSeverity.Warning => FontAwesomeIcon.ExclamationTriangle,
EventSeverity.Error => FontAwesomeIcon.Cross,
_ => FontAwesomeIcon.QuestionCircle
};
var iconColor = ev.EventSeverity switch
{
EventSeverity.Informational => new Vector4(),
EventSeverity.Warning => UIColors.Get("LightlessYellow"),
EventSeverity.Error => ImGuiColors.DalamudRed,
_ => new Vector4()
};
ImGui.TableNextColumn();
_uiSharedService.IconText(icon, iconColor == new Vector4() ? null : iconColor);
UiSharedService.AttachToolTip(ev.EventSeverity.ToString());
ImGui.TableNextColumn();
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted(ev.EventTime.ToString("G", CultureInfo.CurrentCulture));
ImGui.TableNextColumn();
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted(ev.EventSource);
ImGui.TableNextColumn();
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted(string.IsNullOrEmpty(ev.UID) ? "--" : ev.UID);
ImGui.TableNextColumn();
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted(string.IsNullOrEmpty(ev.Character) ? "--" : ev.Character);
ImGui.TableNextColumn();
ImGui.AlignTextToFramePadding();
var posX = ImGui.GetCursorPosX();
var maxTextLength = ImGui.GetWindowContentRegionMax().X - posX;
var textSize = ImGui.CalcTextSize(ev.Message).X;
var msg = ev.Message ?? string.Empty;
var maxEventTextLength = ImGui.GetContentRegionAvail().X;
if (maxEventTextLength <= 0f)
{
ImGui.TextUnformatted(string.Empty);
return;
}
var eventTextSize = ImGui.CalcTextSize(msg).X;
if (eventTextSize > maxEventTextLength)
{
const string ellipsis = "...";
while (eventTextSize > maxTextLength && msg.Length > ellipsis.Length)
{
var cut = Math.Min(5, msg.Length - ellipsis.Length);
msg = msg[..^cut] + ellipsis;
eventTextSize = ImGui.CalcTextSize(msg).X;
}
if (textSize > maxEventTextLength)
msg = ellipsis;
}
ImGui.TextUnformatted(msg);
if (!string.Equals(msg, ev.Message, StringComparison.Ordinal))
UiSharedService.AttachToolTip(ev.Message);
}
}
}
}