using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Numerics; using System.Runtime.CompilerServices; using Dalamud.Bindings.ImGui; using Dalamud.Game.Text; using Dalamud.Interface; using Dalamud.Interface.Utility.Raii; using Dalamud.Plugin; using Dalamud.Utility; using LLib.Notifications; namespace Questionable.Windows.ConfigComponents; internal sealed class NotificationConfigComponent : ConfigComponent { private static readonly string[] CuratedSoundNames; private readonly OutOfGameNotifier _notifier; private readonly string[] _soundFiles; private readonly string[] _soundLabels; private readonly XivChatType[] _xivChatTypes; private readonly string[] _chatTypeNames; private string _chatChannelSearchText = string.Empty; private string _soundSearchText = string.Empty; public NotificationConfigComponent(IDalamudPluginInterface pluginInterface, Configuration configuration, OutOfGameNotifier notifier) : base(pluginInterface, configuration) { _notifier = notifier; _soundFiles = CuratedSoundNames.Where((string n) => WindowsSounds.ResolvePath(n) != null).ToArray(); _soundLabels = _soundFiles.Select(SoundLabel).ToArray(); _xivChatTypes = (from x in Enum.GetValues() where x != XivChatType.StandardEmote select x).ToArray(); _chatTypeNames = _xivChatTypes.Select((XivChatType t) => t.GetAttribute()?.FancyName ?? t.ToString()).ToArray(); } private static string SoundLabel(string value) { if (!string.IsNullOrEmpty(value)) { return Path.GetFileNameWithoutExtension(value); } return "(Default beep)"; } public override void DrawTab() { UiThemeUtils.SectionHeader("Notifications"); (Vector2 ContentStartPos, float AvailableWidth, ImDrawListPtr DrawList) tuple = UiThemeUtils.BeginCard(); Vector2 item = tuple.ContentStartPos; float item2 = tuple.AvailableWidth; ImDrawListPtr item3 = tuple.DrawList; bool value = base.Configuration.Notifications.Enabled; if (UiThemeUtils.WrappedCheckbox("Enable notifications when manual interaction is required", ref value)) { base.Configuration.Notifications.Enabled = value; Save(); } using (ImRaii.Disabled(!base.Configuration.Notifications.Enabled)) { int currentItem = Array.IndexOf(_xivChatTypes, base.Configuration.Notifications.ChatType); if (currentItem == -1) { currentItem = 0; } float width = MathF.Min(260f, ImGui.GetContentRegionAvail().X); if (UiThemeUtils.SearchableCombo("Chat channel", ref currentItem, _chatTypeNames, ref _chatChannelSearchText, width)) { base.Configuration.Notifications.ChatType = _xivChatTypes[currentItem]; Save(); } } UiThemeUtils.EndCard(item, item2, item3); using (ImRaii.Disabled(!base.Configuration.Notifications.Enabled)) { UiThemeUtils.SectionSpacing(); UiThemeUtils.SectionHeader("Out-of-game notifications"); (Vector2 ContentStartPos, float AvailableWidth, ImDrawListPtr DrawList) tuple2 = UiThemeUtils.BeginCard(); Vector2 item4 = tuple2.ContentStartPos; float item5 = tuple2.AvailableWidth; ImDrawListPtr item6 = tuple2.DrawList; bool value2 = base.Configuration.Notifications.FlashTaskbar; if (UiThemeUtils.WrappedCheckbox("Flash taskbar icon", ref value2)) { base.Configuration.Notifications.FlashTaskbar = value2; Save(); } bool value3 = base.Configuration.Notifications.ShowTrayMessage; if (UiThemeUtils.WrappedCheckbox("Show tray notification", ref value3)) { base.Configuration.Notifications.ShowTrayMessage = value3; Save(); } bool value4 = base.Configuration.Notifications.PlaySound; if (UiThemeUtils.WrappedCheckbox("Play a sound", ref value4)) { base.Configuration.Notifications.PlaySound = value4; Save(); } using (ImRaii.Disabled(!base.Configuration.Notifications.PlaySound)) { using (ImRaii.PushIndent()) { int currentItem2 = Array.IndexOf(_soundFiles, base.Configuration.Notifications.SoundFile); float width2 = MathF.Min(ImGui.GetContentRegionAvail().X * 0.6f, 260f); string previewOverride = ((currentItem2 < 0) ? SoundLabel(base.Configuration.Notifications.SoundFile) : null); if (UiThemeUtils.SearchableCombo("Sound", ref currentItem2, _soundLabels, ref _soundSearchText, width2, previewOverride)) { base.Configuration.Notifications.SoundFile = _soundFiles[currentItem2]; Save(); } ImGui.SameLine(); if (UiThemeUtils.IconTextButton(FontAwesomeIcon.Play, "Test")) { _notifier.PlayAlertSound(WindowsSounds.ResolvePath(base.Configuration.Notifications.SoundFile)); } } } bool value5 = base.Configuration.Notifications.OnlyWhenUnfocused; if (UiThemeUtils.WrappedCheckbox("Only when the game is not focused", ref value5, "Tray notification and sound are suppressed while the game window is focused. Taskbar flashing already stops when you focus the game.")) { base.Configuration.Notifications.OnlyWhenUnfocused = value5; Save(); } UiThemeUtils.EndCard(item4, item5, item6); UiThemeUtils.SectionSpacing(); UiThemeUtils.SectionHeader("Alert for"); ImGui.SameLine(); UiThemeUtils.InfoIcon("Which situations raise an out-of-game alert (taskbar / tray / sound): when a step needs you, when an auto-run duty / single-player duty finishes, and when a stop condition halts automation."); (Vector2 ContentStartPos, float AvailableWidth, ImDrawListPtr DrawList) tuple3 = UiThemeUtils.BeginCard(); Vector2 item7 = tuple3.ContentStartPos; float item8 = tuple3.AvailableWidth; ImDrawListPtr item9 = tuple3.DrawList; InlineArray4 buffer = default(InlineArray4); global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef, UiThemeUtils.GridCheckbox>(ref buffer, 0) = new UiThemeUtils.GridCheckbox("Duties", base.Configuration.Notifications.AlertForDuties); global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef, UiThemeUtils.GridCheckbox>(ref buffer, 1) = new UiThemeUtils.GridCheckbox("Single-player duties", base.Configuration.Notifications.AlertForSinglePlayerDuties); global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef, UiThemeUtils.GridCheckbox>(ref buffer, 2) = new UiThemeUtils.GridCheckbox("Snipe steps", base.Configuration.Notifications.AlertForSnipe); global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef, UiThemeUtils.GridCheckbox>(ref buffer, 3) = new UiThemeUtils.GridCheckbox("Stop conditions", base.Configuration.Notifications.AlertForStopConditions); ReadOnlySpan items = global::_003CPrivateImplementationDetails_003E.InlineArrayAsReadOnlySpan, UiThemeUtils.GridCheckbox>(in buffer, 4); switch (UiThemeUtils.CheckboxGrid("alertfor", items)) { case 0: base.Configuration.Notifications.AlertForDuties = !base.Configuration.Notifications.AlertForDuties; Save(); break; case 1: base.Configuration.Notifications.AlertForSinglePlayerDuties = !base.Configuration.Notifications.AlertForSinglePlayerDuties; Save(); break; case 2: base.Configuration.Notifications.AlertForSnipe = !base.Configuration.Notifications.AlertForSnipe; Save(); break; case 3: base.Configuration.Notifications.AlertForStopConditions = !base.Configuration.Notifications.AlertForStopConditions; Save(); break; } UiThemeUtils.EndCard(item7, item8, item9); } } static NotificationConfigComponent() { List list = new List(); list.AddRange(from i in Enumerable.Range(1, 10) select $"Alarm{i:D2}.wav"); list.AddRange(from i in Enumerable.Range(1, 10) select $"Ring{i:D2}.wav"); CuratedSoundNames = list.ToArray(); } }