code refactor + images for currencies

main
Camille 2022-09-14 18:35:53 +02:00
parent f563fb778f
commit d0e239a0c1
33 changed files with 500 additions and 433 deletions

View File

@ -1,14 +0,0 @@
using System;
namespace CurrencyAlert.Enum
{
internal class CategoryAttribute : Attribute
{
public CategoryAttribute(string v)
{
Value = v;
}
public string Value { get; }
}
}

View File

@ -1,14 +0,0 @@
using System;
namespace CurrencyAlert
{
internal class DefaultThresholdAttribute : Attribute
{
public DefaultThresholdAttribute(int v)
{
Value = v;
}
public int Value { get; }
}
}

View File

@ -1,14 +0,0 @@
using System;
namespace CurrencyAlert
{
internal class ItemIDAttribute : Attribute
{
public ItemIDAttribute(int v)
{
Value = v;
}
public int Value { get; }
}
}

View File

@ -1,14 +0,0 @@
using System;
namespace CurrencyAlert.Enum
{
internal class NameAttribute : Attribute
{
public NameAttribute(string v)
{
Value = v;
}
public string Value { get; }
}
}

View File

@ -1,4 +1,5 @@
using CurrencyAlert.Enum; using CurrencyAlert.Helper;
using CurrencyAlert.Provider;
using Dalamud.Configuration; using Dalamud.Configuration;
using Dalamud.Plugin; using Dalamud.Plugin;
using System; using System;
@ -11,30 +12,27 @@ namespace CurrencyAlert
{ {
public int Version { get; set; } = 5; public int Version { get; set; } = 5;
public Dictionary<Currency, bool> AlertEnabled { get; set; } = new Dictionary<Currency, bool>(); public bool UiLocked { get; set; } = false;
public Dictionary<Currency, int> Threshold { get; set; } = new Dictionary<Currency , int>(); public Dictionary<int, bool> AlertEnabled { get; } = new Dictionary<int, bool>();
public Dictionary<int, int> Threshold { get; } = new Dictionary<int, int>();
[NonSerialized]
private DalamudPluginInterface? pluginInterface;
public Configuration() public Configuration()
{ {
EnumHelper.Each<Currency>(currency => foreach (var currency in CurrencyProvider.Instance.GetAll())
{ {
this.AlertEnabled[currency] = true; this.AlertEnabled[currency.Id] = true;
var defaultValue = EnumHelper.GetAttributeOfType<DefaultThresholdAttribute>(currency); this.Threshold[currency.Id] = currency.DefaultThreshold;
this.Threshold[currency] = defaultValue.Value; }
});
} }
public void Initialize(DalamudPluginInterface pluginInterface) public void Initialize()
{ {
this.pluginInterface = pluginInterface;
} }
public void Save() public void Save()
{ {
this.pluginInterface!.SavePluginConfig(this); PluginHelper.PluginInterface.SavePluginConfig(this);
} }
} }
} }

View File

@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<Authors></Authors> <Authors></Authors>
<Company></Company> <Company></Company>
<Version>0.3.3.1</Version> <Version>0.4.0.0</Version>
<Description>Currency Alert</Description> <Description>Currency Alert</Description>
<Copyright></Copyright> <Copyright></Copyright>
<PackageProjectUrl>https://github.com/Lharz/xiv-currency-alert</PackageProjectUrl> <PackageProjectUrl>https://github.com/Lharz/xiv-currency-alert</PackageProjectUrl>
@ -25,6 +25,7 @@
<DalamudLibPath>$(appdata)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath> <DalamudLibPath>$(appdata)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath>
<RepositoryUrl>https://github.com/Lharz/xiv-currency-alert</RepositoryUrl> <RepositoryUrl>https://github.com/Lharz/xiv-currency-alert</RepositoryUrl>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
<BaseOutputPath>bin\</BaseOutputPath>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@ -59,4 +60,8 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Content Include="images\**" Link="images\%(RecursiveDir)\%(Filename)%(Extension)" CopyToOutputDirectory="Always" />
</ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,26 @@
using CurrencyAlert.Enum;
using CurrencyAlert.Helper;
using ImGuiScene;
namespace CurrencyAlert.Entity
{
internal class Currency
{
public int Id { get; }
public string Name { get; }
public CurrencyType Type { get; }
public Category Category { get; }
public TextureWrap? Image { get; }
public int DefaultThreshold { get; }
public Currency(int id, string name, CurrencyType type, Category category, int defaultThreshold)
{
Id = id;
Name = name;
Type = type;
Category = category;
DefaultThreshold = defaultThreshold;
Image = ImageHelper.LoadImage(id.ToString());
}
}
}

View File

@ -0,0 +1,9 @@
namespace CurrencyAlert.Enum
{
public enum Category
{
Common,
Battle,
Other
}
}

View File

@ -1,50 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CurrencyAlert.Enum
{
public enum Currency
{
[Name("Tomestones of Poetics"), ItemID(28), DefaultThreshold(1400), Category("Battle")]
TomestoneOfPoetics,
[Name("Tomestones of Astronomy"), ItemID(43), DefaultThreshold(1700), Category("Battle")]
TomestoneOfAstronomy,
[Name("Tomestones of Causality"), ItemID(44), DefaultThreshold(1700), Category("Battle")]
TomestoneOfCausality,
[Name("Storm Seals"), ItemID(20), DefaultThreshold(75000), Category("Common")]
StormSeal,
[Name("Serpent Seals"), ItemID(21), DefaultThreshold(75000), Category("Common")]
SerpentSeal,
[Name("Flame Seals"), ItemID(22), DefaultThreshold(75000), Category("Common")]
FlameSeal,
[Name("Wolf Marks"), ItemID(25), DefaultThreshold(18000), Category("Battle")]
WolfMark,
[Name("Trophy Crystals"), ItemID(36656), DefaultThreshold(18000), Category("Battle")]
TrophyCrystal,
[Name("Allied Seals"), ItemID(27), DefaultThreshold(3500), Category("Battle")]
AlliedSeal,
[Name("Centurio Seals"), ItemID(10307), DefaultThreshold(3500), Category("Battle")]
CenturioSeal,
[Name("Sack of Nuts"), ItemID(26533), DefaultThreshold(3500), Category("Battle")]
SackOfNut,
[Name("Bicolor Gemstone"), ItemID(26807), DefaultThreshold(800), Category("Battle")]
BicolorGemstone,
[Name("White Crafters' Scrip"), ItemID(25199), DefaultThreshold(1500), Category("Other")]
WhiteCraftersScrip,
[Name("Purple Crafters' Scrip"), ItemID(33913), DefaultThreshold(1500), Category("Other")]
PurpleCraftersScrip,
[Name("White Gatherers' Scrip"), ItemID(25200), DefaultThreshold(1500), Category("Other")]
WhiteGatherersScrip,
[Name("Purple Gatherers' Scrip"), ItemID(33914), DefaultThreshold(1500), Category("Other")]
PurpleGatherersScrip,
[Name("Skybuilders' Scrip"), ItemID(28063), DefaultThreshold(7500), Category("Other")]
SkybuildersScrip
}
}

View File

@ -0,0 +1,28 @@
namespace CurrencyAlert.Enum
{
public enum CurrencyType
{
TomestoneOfPoetics,
TomestoneOfAphorism,
TomestoneOfAstronomy,
TomestoneOfCausality,
StormSeal,
SerpentSeal,
FlameSeal,
WolfMark,
TrophyCrystal,
AlliedSeal,
CenturioSeal,
SackOfNut,
BicolorGemstone,
WhiteCraftersScrip,
PurpleCraftersScrip,
WhiteGatherersScrip,
PurpleGatherersScrip,
SkybuildersScrip
}
}

View File

@ -1,32 +0,0 @@
 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CurrencyAlert
{
public static class EnumHelper
{
/// <summary>
/// Gets an attribute on an enum field value
/// </summary>
/// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
/// <param name="enumVal">The enum value</param>
/// <returns>The attribute of type T that exists on the enum value</returns>
/// <example><![CDATA[string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description;]]></example>
public static T GetAttributeOfType<T>(this System.Enum enumVal) where T : System.Attribute
{
var type = enumVal.GetType();
var memInfo = type.GetMember(enumVal.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(T), false);
return (attributes.Length > 0) ? (T)attributes[0] : null;
}
public static void Each<T>(Action<T> action)
{
foreach (var item in System.Enum.GetValues(typeof(T)))
action((T)item);
}
}
}

View File

@ -0,0 +1,24 @@
using ImGuiScene;
using System;
using System.IO;
namespace CurrencyAlert.Helper
{
internal class ImageHelper
{
public static TextureWrap? LoadImage(string imageName)
{
var assemblyLocation = PluginHelper.PluginInterface.AssemblyLocation.DirectoryName!;
var imagePath = Path.Combine(assemblyLocation, $@"images\{imageName}.png");
try
{
return PluginHelper.PluginInterface.UiBuilder.LoadImage(imagePath);
}
catch (SystemException e)
{
return null;
}
}
}
}

View File

@ -0,0 +1,16 @@
using Dalamud.Game.ClientState;
using Dalamud.Game.Command;
using Dalamud.Game.Gui;
using Dalamud.IoC;
using Dalamud.Plugin;
namespace CurrencyAlert.Helper
{
internal class PluginHelper
{
[PluginService] public static DalamudPluginInterface PluginInterface { get; private set; } = null!;
[PluginService] public static ClientState ClientState { get; private set; } = null!;
[PluginService] public static CommandManager CommandManager { get; private set; } = null!;
[PluginService] public static ChatGui Chat { get; private set; } = null!;
}
}

View File

@ -1,10 +1,13 @@
using CurrencyAlert.Enum; using CurrencyAlert.Helper;
using CurrencyAlert.Provider;
using Dalamud.Game.Command; using Dalamud.Game.Command;
using Dalamud.Game.Gui; using Dalamud.Game.Gui;
using Dalamud.IoC; using Dalamud.IoC;
using Dalamud.Plugin; using Dalamud.Plugin;
using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game;
using System.IO; using ImGuiNET;
using Newtonsoft.Json;
using System;
using System.Reflection; using System.Reflection;
namespace CurrencyAlert namespace CurrencyAlert
@ -15,39 +18,47 @@ namespace CurrencyAlert
private const string commandName = "/currencyalert"; private const string commandName = "/currencyalert";
private DalamudPluginInterface PluginInterface { get; init; }
private CommandManager CommandManager { get; init; }
private Configuration Configuration { get; init; } private Configuration Configuration { get; init; }
private PluginUI PluginUI { get; init; } private PluginUI PluginUI { get; init; }
[PluginService] public static ChatGui Chat { get; private set; } = null!; [PluginService] public static ChatGui Chat { get; private set; } = null!;
public Plugin( private bool LoggedIn => PluginHelper.ClientState.LocalPlayer != null && PluginHelper.ClientState.LocalContentId != 0;
[RequiredVersion("1.0")] DalamudPluginInterface pluginInterface,
[RequiredVersion("1.0")] CommandManager commandManager)
{
this.PluginInterface = pluginInterface;
this.CommandManager = commandManager;
this.Configuration = this.PluginInterface.GetPluginConfig() as Configuration ?? new Configuration(); public Plugin(DalamudPluginInterface pluginInterface)
this.Configuration.Initialize(this.PluginInterface); {
pluginInterface.Create<PluginHelper>();
try
{
this.Configuration = PluginHelper.PluginInterface.GetPluginConfig() as Configuration ?? new Configuration();
}
catch (Exception e)
{
this.Configuration = new Configuration();
this.Configuration.Save();
PluginHelper.Chat.Print("Your CurrencyAlert configuration has been reset because of compatibility issues. Please check the plugin configuration window.");
}
this.Configuration.Initialize();
var assemblyLocation = Assembly.GetExecutingAssembly().Location; var assemblyLocation = Assembly.GetExecutingAssembly().Location;
this.PluginUI = new PluginUI(this.Configuration); this.PluginUI = new PluginUI(this.Configuration);
this.CommandManager.AddHandler(commandName, new CommandInfo(OnCommand) PluginHelper.CommandManager.AddHandler(commandName, new CommandInfo(OnCommand)
{ {
HelpMessage = "Lets you configure alert thresholds for various currencies" HelpMessage = "Lets you configure alert thresholds for various currencies"
}); });
this.PluginInterface.UiBuilder.Draw += DrawUI; PluginHelper.PluginInterface.UiBuilder.Draw += DrawUI;
this.PluginInterface.UiBuilder.OpenConfigUi += DrawConfigUI; PluginHelper.PluginInterface.UiBuilder.OpenConfigUi += DrawConfigUI;
} }
public void Dispose() public void Dispose()
{ {
this.PluginUI.Dispose(); this.PluginUI.Dispose();
this.CommandManager.RemoveHandler(commandName); PluginHelper.CommandManager.RemoveHandler(commandName);
} }
private void OnCommand(string command, string args) private void OnCommand(string command, string args)
@ -56,29 +67,37 @@ namespace CurrencyAlert
} }
private void DrawUI() private void DrawUI()
{
if (!this.LoggedIn)
return;
this.UpdateAlerts();
this.PluginUI.Draw();
}
private void UpdateAlerts()
{ {
// TODO: move this logic elsewhere // TODO: move this logic elsewhere
// TODO: do this only every X seconds
unsafe unsafe
{ {
InventoryManager* inventoryManager = InventoryManager.Instance(); InventoryManager* inventoryManager = InventoryManager.Instance();
EnumHelper.Each<Currency>(currency => foreach (var currency in CurrencyProvider.Instance.GetAll())
{ {
var itemID = EnumHelper.GetAttributeOfType<ItemIDAttribute>(currency).Value; int quantity = inventoryManager->GetInventoryItemCount((uint)currency.Id);
int quantity = inventoryManager->GetInventoryItemCount((uint)itemID);
if (this.Configuration.AlertEnabled[currency] && quantity >= this.Configuration.Threshold[currency]) if (this.Configuration.AlertEnabled[currency.Id] && quantity >= this.Configuration.Threshold[currency.Id])
{ {
this.PluginUI.AlertVisible[currency] = true; this.PluginUI.AlertVisible[currency.Id] = true;
} }
else else
{ {
this.PluginUI.AlertVisible[currency] = false; this.PluginUI.AlertVisible[currency.Id] = false;
}
} }
});
} }
this.PluginUI.Draw();
} }
private void DrawConfigUI() private void DrawConfigUI()

View File

@ -1,7 +1,4 @@
using CurrencyAlert.Enum; using CurrencyAlert.Provider;
using Dalamud.Game.Gui;
using Dalamud.IoC;
using FFXIVClientStructs.FFXIV.Client.Game;
using ImGuiNET; using ImGuiNET;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -19,13 +16,16 @@ namespace CurrencyAlert
get { return settingsVisible; } get { return settingsVisible; }
set { settingsVisible = value; } set { settingsVisible = value; }
} }
public Dictionary<Currency, bool> AlertVisible { get; set; } = new Dictionary<Currency, bool>(); public Dictionary<int, bool> AlertVisible { get; set; } = new Dictionary<int, bool>();
public PluginUI(Configuration configuration) public PluginUI(Configuration configuration)
{ {
this.configuration = configuration; this.configuration = configuration;
EnumHelper.Each<Currency>(currency => this.AlertVisible[currency] = false); foreach (var currency in CurrencyProvider.Instance.GetAll())
{
this.AlertVisible[currency.Id] = false;
}
} }
public void Dispose() public void Dispose()
@ -43,30 +43,42 @@ namespace CurrencyAlert
public void DrawMainWindow() public void DrawMainWindow()
{ {
EnumHelper.Each<Currency>(currency => foreach (var currency in CurrencyProvider.Instance.GetAll())
{ {
if (!this.AlertVisible[currency]) if (!this.AlertVisible[currency.Id])
return; continue;
ImGui.SetNextWindowSize(new Vector2(375, 10), ImGuiCond.FirstUseEver); ImGui.SetNextWindowSize(new Vector2(375, 10), ImGuiCond.FirstUseEver);
ImGui.SetNextWindowSizeConstraints(new Vector2(375, 10), new Vector2(float.MaxValue, float.MaxValue)); ImGui.SetNextWindowSizeConstraints(new Vector2(375, 10), new Vector2(float.MaxValue, float.MaxValue));
var isVisible = this.AlertVisible[currency]; var isVisible = this.AlertVisible[currency.Id];
if (ImGui.Begin("Currency Alert", ref isVisible, var guiOptions = ImGuiWindowFlags.NoScrollbar |
ImGuiWindowFlags.NoScrollbar |
ImGuiWindowFlags.NoScrollWithMouse | ImGuiWindowFlags.NoScrollWithMouse |
ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.AlwaysAutoResize |
ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoTitleBar |
ImGuiWindowFlags.NoFocusOnAppearing ImGuiWindowFlags.NoFocusOnAppearing;
))
if (configuration.UiLocked)
guiOptions |= ImGuiWindowFlags.NoMove;
if (ImGui.Begin("Currency Alert", ref isVisible, guiOptions))
{ {
var name = EnumHelper.GetAttributeOfType<NameAttribute>(currency).Value; ImGui.Text($"You need to spend your");
ImGui.Text($"You need to spend your {name}");
if (currency.Image != null)
{
ImGui.SameLine();
ImGui.Image(currency.Image.ImGuiHandle, new Vector2(22, 22));
} }
ImGui.SameLine();
ImGui.Text($"{currency.Name}");
ImGui.End(); ImGui.End();
}); }
}
} }
public void DrawSettingsWindow() public void DrawSettingsWindow()
@ -74,38 +86,60 @@ namespace CurrencyAlert
ImGui.SetNextWindowSize(new Vector2(700, 500), ImGuiCond.FirstUseEver); ImGui.SetNextWindowSize(new Vector2(700, 500), ImGuiCond.FirstUseEver);
if (ImGui.Begin("Currency Alert Configuration Window", ref this.settingsVisible)) if (ImGui.Begin("Currency Alert Configuration Window", ref this.settingsVisible))
{ {
var uiLocked = this.configuration.UiLocked;
if (ImGui.Checkbox("Lock alert window", ref uiLocked))
{
this.configuration.UiLocked = uiLocked;
this.configuration.Save();
}
if (ImGui.BeginTabBar("AlertsConfiguration_Tabs")) if (ImGui.BeginTabBar("AlertsConfiguration_Tabs"))
{ {
EnumHelper.Each<Currency>(currency => foreach (var currency in CurrencyProvider.Instance.GetAll())
{ {
var name = EnumHelper.GetAttributeOfType<NameAttribute>(currency).Value; var name = currency.Name;
var category = EnumHelper.GetAttributeOfType<CategoryAttribute>(currency).Value; var category = currency.Category;
var alertEnabled = this.configuration.AlertEnabled[currency]; var alertEnabled = this.configuration.AlertEnabled[currency.Id];
if (ImGui.BeginTabItem(category)) if (ImGui.BeginTabItem(category.ToString()))
{ {
if (ImGui.Checkbox($"{name} Alert Enabled", ref alertEnabled)) if (currency.Image != null)
{ {
this.configuration.AlertEnabled[currency] = alertEnabled; ImGui.Image(currency.Image.ImGuiHandle, new Vector2(22, 22));
ImGui.SameLine();
}
ImGui.Text($"{currency.Name}");
if (ImGui.Checkbox($"Enabled##{name}", ref alertEnabled))
{
this.configuration.AlertEnabled[currency.Id] = alertEnabled;
this.configuration.Save(); this.configuration.Save();
} }
var thresholdValue = this.configuration.Threshold[currency]; ImGui.SameLine();
if (ImGui.InputInt($"{name} Threshold Value", ref thresholdValue, 1, 1, var thresholdValue = this.configuration.Threshold[currency.Id];
this.configuration.AlertEnabled[currency] ? ImGuiInputTextFlags.None : ImGuiInputTextFlags.ReadOnly))
if (ImGui.InputInt($"Threshold##{name}", ref thresholdValue, 1, 1,
this.configuration.AlertEnabled[currency.Id] ? ImGuiInputTextFlags.None : ImGuiInputTextFlags.ReadOnly))
{ {
this.configuration.Threshold[currency] = thresholdValue; this.configuration.Threshold[currency.Id] = thresholdValue;
this.configuration.Save(); this.configuration.Save();
} }
ImGui.Separator();
ImGui.EndTabItem(); ImGui.EndTabItem();
} }
});
} }
ImGui.EndTabBar();
} }
ImGui.End(); ImGui.End();
} }
} }
} }
}

View File

@ -0,0 +1,46 @@
using CurrencyAlert.Entity;
using System.Collections.Generic;
namespace CurrencyAlert.Provider
{
internal sealed class CurrencyProvider
{
private static CurrencyProvider? instance = null;
public static CurrencyProvider Instance => instance ??= new CurrencyProvider();
private readonly List<Currency> currencies;
public CurrencyProvider()
{
currencies = new List<Currency>
{
new Currency(28, "Tomestones of Poetics", Enum.CurrencyType.TomestoneOfPoetics, Enum.Category.Battle, 1400),
new Currency(43, "Tomestones of Astronomy", Enum.CurrencyType.TomestoneOfAstronomy, Enum.Category.Battle, 1700),
new Currency(44, "Tomestones of Causality", Enum.CurrencyType.TomestoneOfCausality, Enum.Category.Battle, 1700),
new Currency(20, "Storm Seals", Enum.CurrencyType.StormSeal, Enum.Category.Common, 75000),
new Currency(21, "Serpent Seals", Enum.CurrencyType.SerpentSeal, Enum.Category.Common, 75000),
new Currency(22, "Flame Seals", Enum.CurrencyType.FlameSeal, Enum.Category.Common, 75000),
new Currency(25, "Wolf Marks", Enum.CurrencyType.WolfMark, Enum.Category.Battle, 18000),
new Currency(36656, "Trophy Crystals", Enum.CurrencyType.TrophyCrystal, Enum.Category.Battle, 18000),
new Currency(27, "Allied Seals", Enum.CurrencyType.AlliedSeal, Enum.Category.Battle, 3500),
new Currency(10307, "Centurio Seals", Enum.CurrencyType.CenturioSeal, Enum.Category.Battle, 3500),
new Currency(26533, "Sack of Nuts", Enum.CurrencyType.SackOfNut, Enum.Category.Battle, 3500),
new Currency(26807, "Bicolor Gemstone", Enum.CurrencyType.BicolorGemstone, Enum.Category.Battle, 800),
new Currency(25199, "White Crafters' Scrip", Enum.CurrencyType.WhiteCraftersScrip, Enum.Category.Other, 1500),
new Currency(33913, "Purple Crafters' Scrip", Enum.CurrencyType.PurpleCraftersScrip, Enum.Category.Other, 1500),
new Currency(25200, "White Gatherers' Scrip", Enum.CurrencyType.WhiteGatherersScrip, Enum.Category.Other, 1500),
new Currency(33914, "Purple Gatherers' Scrip", Enum.CurrencyType.PurpleGatherersScrip, Enum.Category.Other, 1500),
new Currency(28063, "Skybuilders' Scrip", Enum.CurrencyType.SkybuildersScrip, Enum.Category.Other, 7500),
};
}
public IEnumerable<Currency> GetAll()
{
return currencies;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
CurrencyAlert/images/20.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
CurrencyAlert/images/21.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
CurrencyAlert/images/22.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
CurrencyAlert/images/25.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
CurrencyAlert/images/27.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

BIN
CurrencyAlert/images/28.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
CurrencyAlert/images/43.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
CurrencyAlert/images/44.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB