diff --git a/EngageTimer.sln.DotSettings b/EngageTimer.sln.DotSettings
index 0df9d57..94fd139 100644
--- a/EngageTimer.sln.DotSettings
+++ b/EngageTimer.sln.DotSettings
@@ -1,9 +1,6 @@
-
+
This file is part of EngageTimer
-Copyright (C) $CURRENT_YEAR$ Xorus <xorus@posteo.net>
+Copyright (C) ${CurrentDate.Year} Xorus <xorus@posteo.net>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
@@ -15,4 +12,5 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see <https://www.gnu.org/licenses/>.
\ No newline at end of file
+along with this program. If not, see <https://www.gnu.org/licenses/>.
+ True
\ No newline at end of file
diff --git a/Plugin/Configuration/Legacy/CombatAlarmsConfiguration.cs b/Plugin/Configuration/CombatAlarmsConfiguration.cs
similarity index 97%
rename from Plugin/Configuration/Legacy/CombatAlarmsConfiguration.cs
rename to Plugin/Configuration/CombatAlarmsConfiguration.cs
index ea94f13..0570feb 100644
--- a/Plugin/Configuration/Legacy/CombatAlarmsConfiguration.cs
+++ b/Plugin/Configuration/CombatAlarmsConfiguration.cs
@@ -16,7 +16,7 @@
using System.Collections.Generic;
using System.Numerics;
-namespace EngageTimer.Configuration.Legacy;
+namespace EngageTimer.Configuration;
public class CombatAlarmsConfiguration
{
diff --git a/Plugin/Plugin.cs b/Plugin/Plugin.cs
index 1d2f2cc..622110b 100644
--- a/Plugin/Plugin.cs
+++ b/Plugin/Plugin.cs
@@ -50,7 +50,7 @@ public sealed class Plugin : IDalamudPlugin
private static FrameworkThings FrameworkThings { get; set; } = null!;
private static MainCommand MainCommand { get; set; } = null!;
private static SettingsCommand SettingsCommand { get; set; } = null!;
- private static CombatAlarm CombatAlarm { get; set; } = null!;
+ public static CombatAlarm CombatAlarm { get; set; } = null!;
public static SfxPlay SfxPlay { get; set; } = null!;
public Plugin(DalamudPluginInterface pluginInterface)
diff --git a/Plugin/Properties/Resources.Designer.cs b/Plugin/Properties/Resources.Designer.cs
index 8480d16..81ce3a5 100644
--- a/Plugin/Properties/Resources.Designer.cs
+++ b/Plugin/Properties/Resources.Designer.cs
@@ -77,6 +77,15 @@ internal static string AlarmEdit_Active_Tooltip {
}
}
+ ///
+ /// Looks up a localized string similar to Create new.
+ ///
+ internal static string AlarmEdit_Add {
+ get {
+ return ResourceManager.GetString("AlarmEdit_Add", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Blink.
///
@@ -95,6 +104,24 @@ internal static string AlarmEdit_Blink_Tooltip {
}
}
+ ///
+ /// Looks up a localized string similar to Clear all.
+ ///
+ internal static string AlarmEdit_Clear {
+ get {
+ return ResourceManager.GetString("AlarmEdit_Clear", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Do you really want to remove all the alarms?.
+ ///
+ internal static string AlarmEdit_Clear_Confirm {
+ get {
+ return ResourceManager.GetString("AlarmEdit_Clear_Confirm", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Color.
///
@@ -131,6 +158,51 @@ internal static string AlarmEdit_Duration_Tooltip {
}
}
+ ///
+ /// Looks up a localized string similar to Export.
+ ///
+ internal static string AlarmEdit_Export {
+ get {
+ return ResourceManager.GetString("AlarmEdit_Export", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Select file to export.
+ ///
+ internal static string AlarmEdit_Export_File {
+ get {
+ return ResourceManager.GetString("AlarmEdit_Export_File", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Exports the active alarms to a file.
+ ///
+ internal static string AlarmEdit_Export_Tooltip {
+ get {
+ return ResourceManager.GetString("AlarmEdit_Export_Tooltip", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Import.
+ ///
+ internal static string AlarmEdit_Import {
+ get {
+ return ResourceManager.GetString("AlarmEdit_Import", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Select file to import.
+ ///
+ internal static string AlarmEdit_Import_File {
+ get {
+ return ResourceManager.GetString("AlarmEdit_Import_File", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Sound.
///
@@ -194,6 +266,15 @@ internal static string AlarmEdit_Text_Clear {
}
}
+ ///
+ /// Looks up a localized string similar to Test.
+ ///
+ internal static string AlarmEdit_Text_Test {
+ get {
+ return ResourceManager.GetString("AlarmEdit_Text_Test", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Text.
///
@@ -248,6 +329,51 @@ internal static string AlarmEdit_Type_GameToast {
}
}
+ ///
+ /// Looks up a localized string similar to Could not save the file in this directory (access denied). Please try again with another directory..
+ ///
+ internal static string CombatAlarm_AccessDenied {
+ get {
+ return ResourceManager.GetString("CombatAlarm_AccessDenied", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to An empty or invalid alarm list was imported.
+ ///
+ internal static string CombatAlarm_ImportedEmpty {
+ get {
+ return ResourceManager.GetString("CombatAlarm_ImportedEmpty", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The alarms file format is incompatible or incorrect.
+ ///
+ internal static string CombatAlarm_IncorrectFormat {
+ get {
+ return ResourceManager.GetString("CombatAlarm_IncorrectFormat", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to An error occured while trying to read the alarms to {0}: {1}..
+ ///
+ internal static string CombatAlarm_ReadGeneric {
+ get {
+ return ResourceManager.GetString("CombatAlarm_ReadGeneric", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to An error occured while trying to save the alarms to {0}: {1}..
+ ///
+ internal static string CombatAlarm_SaveGeneric {
+ get {
+ return ResourceManager.GetString("CombatAlarm_SaveGeneric", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Unrecognized argument for {0}: {1}.
///
@@ -347,6 +473,33 @@ internal static string MainCommand_Status_On {
}
}
+ ///
+ /// Looks up a localized string similar to Cancel.
+ ///
+ internal static string Modal_Cancel {
+ get {
+ return ResourceManager.GetString("Modal_Cancel", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Confirm.
+ ///
+ internal static string Modal_Confirm {
+ get {
+ return ResourceManager.GetString("Modal_Confirm", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to OK.
+ ///
+ internal static string Modal_Ok {
+ get {
+ return ResourceManager.GetString("Modal_Ok", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to This page allows you to set alarms based on elapsed combat time..
///
diff --git a/Plugin/Properties/Resources.resx b/Plugin/Properties/Resources.resx
index b3c723c..da6cde3 100644
--- a/Plugin/Properties/Resources.resx
+++ b/Plugin/Properties/Resources.resx
@@ -566,4 +566,55 @@ help text for the /eg settings command
A common use is to notify you of the potion window.
+
+ Create new
+
+
+ Clear all
+
+
+ Do you really want to remove all the alarms?
+
+
+ Export
+
+
+ Import
+
+
+ Test
+
+
+ Exports the active alarms to a file
+
+
+ Select file to import
+
+
+ Select file to export
+
+
+ OK
+
+
+ Cancel
+
+
+ Confirm
+
+
+ Could not save the file in this directory (access denied). Please try again with another directory.
+
+
+ An error occured while trying to save the alarms to {0}: {1}.
+
+
+ An error occured while trying to read the alarms to {0}: {1}.
+
+
+ The alarms file format is incompatible or incorrect
+
+
+ An empty or invalid alarm list was imported
+
\ No newline at end of file
diff --git a/Plugin/Status/CombatAlarm.cs b/Plugin/Status/CombatAlarm.cs
index dacfea8..c2d6930 100644
--- a/Plugin/Status/CombatAlarm.cs
+++ b/Plugin/Status/CombatAlarm.cs
@@ -15,11 +15,14 @@
using System;
using System.Collections.Generic;
+using System.IO;
using Dalamud.Game.Text;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Plugin.Services;
-using EngageTimer.Configuration.Legacy;
+using EngageTimer.Configuration;
using EngageTimer.Game;
+using EngageTimer.Ui;
+using Newtonsoft.Json;
namespace EngageTimer.Status;
@@ -50,6 +53,57 @@ public CombatAlarm()
Plugin.State.InCombatChanged += InCombatChanged;
}
+ public static string? Import(string fileName)
+ {
+ try
+ {
+ var text = File.ReadAllText(fileName);
+ var data = JsonConvert.DeserializeObject(text,
+ new JsonSerializerSettings
+ {
+ // using "TypeNameHandling.Objects" causes a "resolving to a collectible assembly is not supported"
+ TypeNameHandling = TypeNameHandling.None
+ });
+ if (data == null || data.Alarms.Count == 0) return Translator.Tr("CombatAlarm_ImportedEmpty");
+ Plugin.Config.CombatAlarms.Alarms.AddRange(data.Alarms);
+ }
+ catch (JsonSerializationException e)
+ {
+ Plugin.Logger.Error(e, $"Could not parse file {fileName}");
+ return Translator.Tr("CombatAlarm_IncorrectFormat");
+ }
+ catch (Exception e)
+ {
+ Plugin.Logger.Error(e, $"Could not read file {fileName}");
+ return Translator.Tr("CombatAlarm_ReadGeneric", fileName, e.Message);
+ }
+
+ return null;
+ }
+
+ public static string? Export(string fileName)
+ {
+ try
+ {
+ File.WriteAllText(fileName,
+ JsonConvert.SerializeObject(Plugin.Config.CombatAlarms, Formatting.Indented,
+ new JsonSerializerSettings
+ {
+ TypeNameHandling = TypeNameHandling.None
+ }));
+ }
+ catch (UnauthorizedAccessException)
+ {
+ return Translator.Tr("CombatAlarm_AccessDenied");
+ }
+ catch (Exception e)
+ {
+ Plugin.Logger.Error(e, $"Could not save file {fileName}");
+ return Translator.Tr("CombatAlarm_SaveGeneric", fileName, e.Message);
+ }
+
+ return null;
+ }
private void ConfigurationChanged(object? sender, EventArgs e)
{
@@ -88,7 +142,7 @@ private void FrameworkUpdate(IFramework framework)
if (!Plugin.State.InCombat) return;
// only run once a second
- var time = (int)Math.Floor(Plugin.State.CombatDuration.TotalSeconds);
+ var time = (int) Math.Floor(Plugin.State.CombatDuration.TotalSeconds);
if (_lastCheck == time) return;
_lastCheck = time;
@@ -107,14 +161,14 @@ public static void AlarmSfx(CombatAlarmsConfiguration.Alarm alarm)
{
if (alarm.Sfx != null)
{
- Plugin.SfxPlay.SoundEffect((uint)(SfxPlay.FirstSeSfx + alarm.Sfx));
+ Plugin.SfxPlay.SoundEffect((uint) (SfxPlay.FirstSeSfx + alarm.Sfx));
}
}
public static void AlarmText(CombatAlarmsConfiguration.Alarm alarm)
{
var trimText = alarm.Text?.Trim();
- if (trimText is not { Length: > 0 }) return;
+ if (trimText is not {Length: > 0}) return;
switch (alarm.TextType)
{
case CombatAlarmsConfiguration.TextType.DalamudNotification:
diff --git a/Plugin/Ui/Components.cs b/Plugin/Ui/Components.cs
index 30f119d..454c21f 100644
--- a/Plugin/Ui/Components.cs
+++ b/Plugin/Ui/Components.cs
@@ -322,4 +322,20 @@ public static void TooltipOnItemHovered(string text)
ImGui.PopTextWrapPos();
ImGui.EndTooltip();
}
+
+ public delegate void DrawAction();
+
+ public static void LeftRight(string id, DrawAction left, DrawAction right)
+ {
+ if (!ImGui.BeginTable(id, 3, ImGuiTableFlags.SizingFixedFit)) return;
+ ImGui.TableSetupColumn("left");
+ ImGui.TableSetupColumn("spacer", ImGuiTableColumnFlags.WidthStretch, 100);
+ ImGui.TableSetupColumn("right");
+ ImGui.TableNextColumn();
+ left();
+ ImGui.TableNextColumn();
+ ImGui.TableNextColumn();
+ right();
+ ImGui.EndTable();
+ }
}
\ No newline at end of file
diff --git a/Plugin/Ui/Modal.cs b/Plugin/Ui/Modal.cs
new file mode 100644
index 0000000..dc62816
--- /dev/null
+++ b/Plugin/Ui/Modal.cs
@@ -0,0 +1,73 @@
+// This file is part of EngageTimer
+// Copyright (C) 2024 Xorus
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+using System;
+using System.Numerics;
+using ImGuiNET;
+
+namespace EngageTimer.Ui;
+
+public class Modal
+{
+ private bool _visible = false;
+ private const string Title = "EngageTimer####egmodal";
+ private string _message = "";
+ private Action? _validate = null;
+
+ public void Draw()
+ {
+ if (_visible)
+ {
+ var center = ImGui.GetMainViewport().GetCenter();
+ ImGui.SetNextWindowPos(center, ImGuiCond.Always, new Vector2(0.5f, 0.5f));
+ ImGui.SetNextWindowSize(new Vector2(300, 0));
+ }
+
+ if (!ImGui.BeginPopupModal(Title, ref _visible)) return;
+ ImGui.TextWrapped(_message);
+
+ if (_validate != null)
+ {
+ if (ImGui.Button(Translator.Tr("Modal_Cancel"), new Vector2(120, 0)))
+ ImGui.CloseCurrentPopup();
+ ImGui.SameLine();
+ if (ImGui.Button(Translator.Tr("Modal_Confirm"), new Vector2(120, 0)))
+ {
+ ImGui.CloseCurrentPopup();
+ _validate();
+ }
+ }
+ else if (ImGui.Button(Translator.Tr("Modal_Ok"), new Vector2(120, 0)))
+ ImGui.CloseCurrentPopup();
+
+ ImGui.EndPopup();
+ }
+
+ public void Show(string message)
+ {
+ _message = message;
+ _visible = true;
+ _validate = null;
+ ImGui.OpenPopup(Title);
+ }
+
+ public void Confirm(string message, Action validate)
+ {
+ _message = message;
+ _validate = validate;
+ _visible = true;
+ ImGui.OpenPopup(Title);
+ }
+}
\ No newline at end of file
diff --git a/Plugin/Ui/SettingsTab/AlarmsTab.cs b/Plugin/Ui/SettingsTab/AlarmsTab.cs
index a28c990..a5cde89 100644
--- a/Plugin/Ui/SettingsTab/AlarmsTab.cs
+++ b/Plugin/Ui/SettingsTab/AlarmsTab.cs
@@ -15,12 +15,10 @@
using System;
using System.Collections.Generic;
-using System.Numerics;
using Dalamud.Interface;
using Dalamud.Interface.Components;
-using Dalamud.Interface.Utility;
-using EngageTimer.Configuration.Legacy;
-using EngageTimer.Game;
+using Dalamud.Interface.ImGuiFileDialog;
+using EngageTimer.Configuration;
using EngageTimer.Status;
using ImGuiNET;
@@ -28,6 +26,9 @@ namespace EngageTimer.Ui.SettingsTab;
public static class AlarmsTab
{
+ private static readonly FileDialogManager Fdm = new();
+ private static readonly Modal Modal = new();
+
private static void Header(bool tooltip = false)
{
ImGui.TableNextColumn();
@@ -36,6 +37,11 @@ private static void Header(bool tooltip = false)
if (tooltip) Components.TooltipOnItemHovered(Translator.Tr(str + "_Tooltip"));
}
+ /**
+ * Can't open a popup from within a table apparently
+ */
+ private static bool _openConfirmClear = false;
+
private static readonly List EditingTexts = new();
public static void Draw()
@@ -53,12 +59,14 @@ public static void Draw()
ImGui.TableSetupColumn("AlarmEdit_Blink");
ImGui.TableSetupColumn("AlarmEdit_Duration");
ImGui.TableSetupColumn("AlarmEdit_Sound");
- ImGui.TableSetupColumn("AlarmEdit_Text");
+ ImGui.TableSetupColumn("AlarmEdit_Text", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableNextRow(ImGuiTableRowFlags.Headers);
// trash can
- ImGui.TableNextColumn();
- ImGui.Text("");
+ {
+ ImGui.TableNextColumn();
+ ImGui.Text("");
+ }
Header(true); // active
Header(true); // start time
Header(true); // color
@@ -69,23 +77,95 @@ public static void Draw()
for (var index = 0; index < Plugin.Config.CombatAlarms.Alarms.Count; index++)
{
+ ImGui.PushID("alarm" + index);
AlarmElement(index, Plugin.Config.CombatAlarms.Alarms[index]);
+ ImGui.PopID();
}
ImGui.EndTable();
}
- if (ImGuiComponents.IconButton($"{FontAwesomeIcon.Plus.ToIconString()}###add"))
+ Components.LeftRight("buttons", () =>
{
+ if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.FileImport, Translator.Tr("AlarmEdit_Import")))
+ {
+ Fdm.OpenFileDialog(
+ Translator.Tr("AlarmEdit_Import_File"),
+ ".json",
+ (ok, path) =>
+ {
+ if (!ok) return;
+ foreach (var p in path)
+ {
+ var error = CombatAlarm.Import(p);
+ if (error != null) Modal.Show(error);
+ }
+ },
+ 0,
+ null,
+ true
+ );
+ }
+
+
+ ImGui.SameLine();
+ if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.FileExport, Translator.Tr("AlarmEdit_Export")))
+ {
+ Fdm.SaveFileDialog(
+ Translator.Tr("AlarmEdit_Export_File"),
+ ".json",
+ "EngageTimerAlarms.json",
+ "json",
+ (ok, path) =>
+ {
+ if (ok)
+ {
+ var error = CombatAlarm.Export(path);
+ Plugin.Logger.Info("got error" + error);
+ if (error != null) Modal.Show(error);
+ }
+
+ Plugin.Logger.Info($"got {ok} file {path}");
+ },
+ null,
+ true
+ );
+ }
+
+ Components.TooltipOnItemHovered("AlarmEdit_Export_Tooltip");
+
+ ImGui.SameLine();
+ // clear all button
+ if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Trash, Translator.Tr("AlarmEdit_Clear")))
+ {
+ if (Plugin.Config.CombatAlarms.Alarms.Count == 0) return;
+ _openConfirmClear = true;
+ }
+ }, () =>
+ {
+ if (!ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Plus, Translator.Tr("AlarmEdit_Add"))) return;
Plugin.Config.CombatAlarms.Alarms.Add(new CombatAlarmsConfiguration.Alarm());
Plugin.Config.Save();
+ });
+
+ if (_openConfirmClear)
+ {
+ _openConfirmClear = false;
+ Modal.Confirm(Translator.Tr("AlarmEdit_Clear_Confirm"), () =>
+ {
+ Plugin.Config.CombatAlarms.Alarms.Clear();
+ Plugin.Config.Save();
+ });
}
+
+ Fdm.Draw();
+ Modal.Draw();
}
private static void AlarmElement(int index, CombatAlarmsConfiguration.Alarm alarm)
{
+ ImGui.TableNextRow();
{
- ImGui.TableNextRow();
ImGui.TableNextColumn();
ImGui.PushID("alarm_" + index);
Components.IconButton(FontAwesomeIcon.Trash, "delete" + index,
@@ -166,13 +246,13 @@ private static void AlarmElement(int index, CombatAlarmsConfiguration.Alarm alar
ImGui.TableNextColumn();
if (EditingTexts.Contains(index))
{
- var type = (int)alarm.TextType;
+ var type = (int) alarm.TextType;
ImGui.PushItemWidth(150f);
if (ImGui.Combo("Type", ref type, Translator.Tr("AlarmEdit_Type_ChatLog") + "\0"
+ Translator.Tr("AlarmEdit_Type_DalamudNotification") + "\0"
+ Translator.Tr("AlarmEdit_Type_GameToast") + "\0"))
{
- alarm.TextType = (CombatAlarmsConfiguration.TextType)type;
+ alarm.TextType = (CombatAlarmsConfiguration.TextType) type;
Plugin.Config.Save();
}
@@ -186,7 +266,7 @@ private static void AlarmElement(int index, CombatAlarmsConfiguration.Alarm alar
ImGui.PopItemWidth();
- if (ImGui.Button(Translator.Tr("AlarmEdit_Text_Type")))
+ if (ImGui.Button(Translator.Tr("AlarmEdit_Text_Test")))
{
CombatAlarm.AlarmText(alarm);
}
@@ -240,7 +320,6 @@ private static void AlarmElement(int index, CombatAlarmsConfiguration.Alarm alar
}
}
}
-
ImGui.PopID();
}
}
\ No newline at end of file