diff --git a/Priceall/App.config b/Priceall/App.config index e061132..7b1781d 100644 --- a/Priceall/App.config +++ b/Priceall/App.config @@ -1,12 +1,12 @@ - + - -
+ +
- + @@ -68,10 +68,10 @@ 0 - + - + False @@ -84,4 +84,4 @@ - \ No newline at end of file + diff --git a/Priceall/Appraisal/AppraisalMarket.cs b/Priceall/Appraisal/AppraisalMarket.cs index 24f5e01..627ca5b 100644 --- a/Priceall/Appraisal/AppraisalMarket.cs +++ b/Priceall/Appraisal/AppraisalMarket.cs @@ -8,12 +8,15 @@ namespace Priceall.Appraisal [Flags] enum AppraisalMarket { - Universe = 0b_0000_0001, - Jita = 0b_0000_0010, - TheForge = 0b_0000_0100, - Amarr = 0b_0000_1000, - Dodixie = 0b_0001_0000, - Hek = 0b_0010_0000, - Rens = 0b_0100_0000, + Universe = 0b_0000_0000_0001, // A_ + Jita = 0b_0000_0000_0010, // AJ + TheForge = 0b_0000_0000_0100, // _J + Amarr = 0b_0000_0000_1000, // A_ + Dodixie = 0b_0000_0001_0000, // A_ + Hek = 0b_0000_0010_0000, // A_ + Rens = 0b_0000_0100_0000, // A_ + Perimeter = 0b_0000_1000_0000, // AJ + SystemR1OGn = 0b_0001_0000_0000, // _J + NPC = 0b_0010_0000_0000 // _J } } diff --git a/Priceall/Appraisal/AppraisalSetting.cs b/Priceall/Appraisal/AppraisalSetting.cs new file mode 100644 index 0000000..db57e5e --- /dev/null +++ b/Priceall/Appraisal/AppraisalSetting.cs @@ -0,0 +1,41 @@ +using System; +using System.ComponentModel; +using Priceall.Services; + +namespace Priceall.Appraisal +{ + /// + /// A custom setting supported by an appraisal service. + /// + /// The type of the setting value. + internal class AppraisalSetting : JsonSetting, INotifyPropertyChanged where T : struct + { + private Action _onSet; + + public AppraisalSetting(JsonSetting setting, Action onSet = null) : base(setting) + { + _onSet = onSet; + } + + public override T Value + { + get => base.Value; + set + { + // Updates backing setting, fires IPropertyChanged, calls optional action + base.Value = value; + _onSet?.Invoke(value); + OnPropertyChanged(nameof(Value)); + } + } + + #region Binding + public event PropertyChangedEventHandler PropertyChanged; + + protected void OnPropertyChanged(string name) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); + } + #endregion + } +} diff --git a/Priceall/Appraisal/AppraisalSettings.cs b/Priceall/Appraisal/AppraisalSettings.cs deleted file mode 100644 index a716cd7..0000000 --- a/Priceall/Appraisal/AppraisalSettings.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.ComponentModel; - -namespace Priceall.Appraisal -{ - abstract class AppraisalSettings - { - public string Name { get; protected set; } - } - - /// - /// A custom settings supported by an appraisal service. - /// - /// The type of the settings value. - class AppraisalSettings : AppraisalSettings, INotifyPropertyChanged where T : struct - { - - private T _value; - - public T Value - { - get => _value; - set - { - _value = value; - _onSet(value); - OnPropertyChanged(nameof(Value)); - } - } - - private Action _onSet; - - public AppraisalSettings(string name, Action onSet, T value = default) - { - _onSet = onSet; - Name = name; - Value = value; - } - - #region Binding - public event PropertyChangedEventHandler PropertyChanged; - - protected void OnPropertyChanged(string name) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); - } - #endregion - } -} diff --git a/Priceall/Appraisal/Services/CeveMarketAppraisalService.cs b/Priceall/Appraisal/Services/CeveMarketAppraisalService.cs index 0864953..f34c19f 100644 --- a/Priceall/Appraisal/Services/CeveMarketAppraisalService.cs +++ b/Priceall/Appraisal/Services/CeveMarketAppraisalService.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; +using Priceall.Services; namespace Priceall.Appraisal { @@ -15,7 +16,7 @@ public AppraisalMarket GetAvailableMarkets() throw new System.NotImplementedException(); } - public IReadOnlyCollection GetCustomSettings() + public IReadOnlyCollection GetCustomSettings() { throw new System.NotImplementedException(); } diff --git a/Priceall/Appraisal/Services/EvepraisalAppraisalService.cs b/Priceall/Appraisal/Services/EvepraisalAppraisalService.cs index d7d08fd..516aa5b 100644 --- a/Priceall/Appraisal/Services/EvepraisalAppraisalService.cs +++ b/Priceall/Appraisal/Services/EvepraisalAppraisalService.cs @@ -5,40 +5,39 @@ using System.Collections.Generic; using System.Threading.Tasks; using System.Web; +using Priceall.Services; namespace Priceall.Appraisal { class EvepraisalAppraisalService : IAppraisalService { - public const string Endpoint = "https://evepraisal.com/appraisal.json"; + private const string Endpoint = "https://evepraisal.com/appraisal.json"; - // private AppraisalSettings _persistSetting; - - // private AppraisalSettings[] _customSettings; + private readonly UriBuilder _uriBuilder; - private AppraisalMarket _market/* = AppraisalMarket.Jita*/; + private readonly AppraisalSetting _persistSetting; - // private bool _isPersist; - - private readonly UriBuilder _uriBuilder; + private readonly AppraisalSetting _marketSetting; public EvepraisalAppraisalService() { - // _persistSetting = new AppraisalSettings( - // "Persist", (isPersist) => { _isPersist = isPersist; }); - // _customSettings = new AppraisalSettings[] { _persistSetting }; - _uriBuilder = new UriBuilder(Endpoint); + _persistSetting = + new AppraisalSetting( + JsonSettingsService.CreateSetting("Persist", false)); + _marketSetting = + new AppraisalSetting( + JsonSettingsService.CreateSetting("Market", AppraisalMarket.Jita)); } private void BuildUrl() { var qs = HttpUtility.ParseQueryString(String.Empty); - qs["market"] = _market.ToString().ToLower(); - //if (!_isPersist) - //{ - // qs["persist"] = "no"; - //} + qs["market"] = _marketSetting.Value.ToString().ToLower(); + if (!_persistSetting.Value) + { + qs["persist"] = "no"; + } _uriBuilder.Query = qs.ToString(); } @@ -77,11 +76,13 @@ private AppraisalResult ParseResponse(string response) return new AppraisalResult(AppraisalStatus.ContentError, error.ToObject()); } - AppraisalResult res = new AppraisalResult(AppraisalStatus.Successful); - res.Kind = j.SelectToken("appraisal.kind").ToObject(); - res.BuyValue = j.SelectToken("appraisal.totals.buy").ToObject(); - res.SellValue = j.SelectToken("appraisal.totals.sell").ToObject(); - res.Volume = j.SelectToken("appraisal.totals.volume").ToObject(); + var res = new AppraisalResult(AppraisalStatus.Successful) + { + Kind = j.SelectToken("appraisal.kind").ToObject(), + BuyValue = j.SelectToken("appraisal.totals.buy").ToObject(), + SellValue = j.SelectToken("appraisal.totals.sell").ToObject(), + Volume = j.SelectToken("appraisal.totals.volume").ToObject() + }; return res; } @@ -95,15 +96,13 @@ public AppraisalMarket GetAvailableMarkets() | AppraisalMarket.Universe; } - public IReadOnlyCollection GetCustomSettings() - { - return Array.Empty(); - // return _customSettings; - } + public IReadOnlyCollection GetCustomSettings() + => Array.Empty(); + // => new JsonSetting[] { _persistSetting }; public void SetCurrentMarket(AppraisalMarket market) { - _market = market; + _marketSetting.Value = market; } } } diff --git a/Priceall/Appraisal/Services/IAppraisalService.cs b/Priceall/Appraisal/Services/IAppraisalService.cs index 64849eb..ea139cd 100644 --- a/Priceall/Appraisal/Services/IAppraisalService.cs +++ b/Priceall/Appraisal/Services/IAppraisalService.cs @@ -1,8 +1,12 @@ using System.Collections.Generic; using System.Threading.Tasks; +using Priceall.Services; namespace Priceall.Appraisal { + /// + /// An online appraisal service. + /// interface IAppraisalService { /// @@ -21,8 +25,13 @@ interface IAppraisalService /// Gets a collection of custom settings used by the appraisal service. /// /// A read-only collection of custom settings. - IReadOnlyCollection GetCustomSettings(); + IReadOnlyCollection GetCustomSettings(); + /// + /// Asynchronously runs an appraisal. + /// + /// The content to appraise. + /// Appraisal result. Task AppraiseAsync(string content); } } diff --git a/Priceall/Appraisal/Services/JaniceAppraisalService.cs b/Priceall/Appraisal/Services/JaniceAppraisalService.cs index c84c926..a13d654 100644 --- a/Priceall/Appraisal/Services/JaniceAppraisalService.cs +++ b/Priceall/Appraisal/Services/JaniceAppraisalService.cs @@ -1,10 +1,9 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Priceall.Http; +using Priceall.Services; using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading.Tasks; using System.Web; @@ -12,24 +11,34 @@ namespace Priceall.Appraisal { class JaniceAppraisalService : IAppraisalService { - public const string Endpoint = "https://janice.e-351.com/api/rest/v1/appraisal"; + private const string Endpoint = "https://janice.e-351.com/api/rest/v1/appraisal"; private const string ApiKey = "A3lmazJdrn52ugFuVFrLd0mVqxfApYSx"; - private AppraisalMarket _market; - private readonly UriBuilder _uriBuilder; + private AppraisalSetting _marketSetting; + public JaniceAppraisalService() { _uriBuilder = new UriBuilder(Endpoint); + _marketSetting = new AppraisalSetting( + JsonSettingsService.CreateSetting("Market", AppraisalMarket.TheForge)); } private void BuildUrl() { var qs = HttpUtility.ParseQueryString(String.Empty); qs["key"] = ApiKey; - qs["market"] = _market == AppraisalMarket.TheForge ? "1" : "2"; + qs["market"] = _marketSetting.Value switch + { + AppraisalMarket.Jita => "2", + AppraisalMarket.SystemR1OGn => "3", + AppraisalMarket.Perimeter => "4", + AppraisalMarket.TheForge => "5", + AppraisalMarket.NPC => "6", + _ => throw new ArgumentOutOfRangeException() + }; qs["designation"] = "100"; // appraisal qs["pricing"] = "200"; // split _uriBuilder.Query = qs.ToString(); @@ -86,17 +95,16 @@ private AppraisalResult ParseResponse(string response) public AppraisalMarket GetAvailableMarkets() { - return AppraisalMarket.Jita | AppraisalMarket.TheForge; + return AppraisalMarket.Jita | AppraisalMarket.SystemR1OGn | AppraisalMarket.Perimeter | + AppraisalMarket.TheForge | AppraisalMarket.NPC; } - public IReadOnlyCollection GetCustomSettings() - { - return Array.Empty(); - } + public IReadOnlyCollection GetCustomSettings() + => Array.Empty(); public void SetCurrentMarket(AppraisalMarket market) { - _market = market; + _marketSetting.Value = market; } } } diff --git a/Priceall/Bindings/UiStyleBinding.cs b/Priceall/Bindings/UiStyleBinding.cs index 9a19666..843bcf1 100644 --- a/Priceall/Bindings/UiStyleBinding.cs +++ b/Priceall/Bindings/UiStyleBinding.cs @@ -22,7 +22,7 @@ protected void OnPropertyChanged(string name) public UiStyleBinding() { - Settings.Default.PropertyChanged += (object sender, PropertyChangedEventArgs e) => + Settings.Default.PropertyChanged += (sender, e) => { OnPropertyChanged(e.PropertyName); }; @@ -33,7 +33,7 @@ public UiStyleBinding() /// public double WindowOpacity { - get { return Settings.Default.WindowOpacity; } + get => Settings.Default.WindowOpacity; set { // brilliant idea from karl-kaefer: 0.0 makes the window click-through @@ -45,7 +45,7 @@ public double WindowOpacity public int WindowWidth { - get { return Settings.Default.WindowWidth; } + get => Settings.Default.WindowWidth; set { if (value < 60) value = 60; @@ -56,7 +56,7 @@ public int WindowWidth public int WindowHeight { - get { return Settings.Default.WindowHeight; } + get => Settings.Default.WindowHeight; set { if (value < 20) value = 20; @@ -67,7 +67,7 @@ public int WindowHeight public double WindowTopPos { - get { return Settings.Default.WindowTopPos; } + get => Settings.Default.WindowTopPos; set { if (value < 0) value = 0; @@ -78,7 +78,7 @@ public double WindowTopPos public double WindowLeftPos { - get { return Settings.Default.WindowLeftPos; } + get => Settings.Default.WindowLeftPos; set { if (value < 0) value = 0; diff --git a/Priceall/MainWindow.xaml b/Priceall/MainWindow.xaml index 1b4bb5b..c4d9206 100644 --- a/Priceall/MainWindow.xaml +++ b/Priceall/MainWindow.xaml @@ -73,7 +73,7 @@ diff --git a/Priceall/MainWindow.xaml.cs b/Priceall/MainWindow.xaml.cs index 24b04f6..91a32ed 100644 --- a/Priceall/MainWindow.xaml.cs +++ b/Priceall/MainWindow.xaml.cs @@ -75,7 +75,7 @@ protected override void OnSourceInitialized(EventArgs e) if (!HotkeyManager.InitializeHook()) { - _infoBinding.Price = "Hotkey service error."; + _infoBinding.Price = "Hotkeys are disabled."; } else { diff --git a/Priceall/Priceall.csproj b/Priceall/Priceall.csproj index 6ae8da4..2d220a8 100644 --- a/Priceall/Priceall.csproj +++ b/Priceall/Priceall.csproj @@ -8,11 +8,13 @@ WinExe Priceall Priceall - v4.6.1 + latest + v4.8 512 {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 true + AnyCPU @@ -64,7 +66,7 @@ - + @@ -84,6 +86,7 @@ + diff --git a/Priceall/Properties/AssemblyInfo.cs b/Priceall/Properties/AssemblyInfo.cs index d3b8ebd..3866831 100644 --- a/Priceall/Properties/AssemblyInfo.cs +++ b/Priceall/Properties/AssemblyInfo.cs @@ -10,12 +10,12 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Priceall")] -[assembly: AssemblyCopyright("Made by Github.com/xyx0826. Licensed under MIT.")] +[assembly: AssemblyCopyright("Copyright 2021 xyx0826. Licensed under The MIT License.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("0")] -[assembly: AssemblyFileVersion("0")] +[assembly: AssemblyVersion("1.6")] +[assembly: AssemblyFileVersion("12")] // 将 ComVisible 设置为 false 会使此程序集中的类型 //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 diff --git a/Priceall/Properties/Settings.Designer.cs b/Priceall/Properties/Settings.Designer.cs index a7a9f2b..0e49daf 100644 --- a/Priceall/Properties/Settings.Designer.cs +++ b/Priceall/Properties/Settings.Designer.cs @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------ // -// 此代码由工具生成。 -// 运行时版本:4.0.30319.42000 +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // -// 对此文件的更改可能会导致不正确的行为,并且如果 -// 重新生成代码,这些更改将会丢失。 +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // //------------------------------------------------------------------------------ @@ -12,7 +12,7 @@ namespace Priceall.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.6.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); diff --git a/Priceall/Services/JsonSettingsService.cs b/Priceall/Services/JsonSettingsService.cs new file mode 100644 index 0000000..ec54828 --- /dev/null +++ b/Priceall/Services/JsonSettingsService.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using Newtonsoft.Json.Linq; + +namespace Priceall.Services +{ + internal abstract class JsonSetting + { + /// + /// Setting name. + /// + public readonly string Name; + + protected JsonSetting(string name) + { + Name = name; + } + } + + internal class JsonSetting : JsonSetting where T : struct + { + /// + /// Backing setting value. + /// + protected T _value; + + /// + /// Delegate to be called to persist a new value into the store. + /// + protected Action _valueSetter; + + /// + /// Setting default value. + /// + public readonly T DefaultValue; + + public JsonSetting(string name, T defaultValue, T value, Action valueSetter) : base(name) + { + DefaultValue = defaultValue; + _value = value; + _valueSetter = valueSetter; + } + + protected JsonSetting(JsonSetting setting) : base(setting.Name) + { + DefaultValue = setting.DefaultValue; + _value = setting._value; + _valueSetter = setting._valueSetter; + } + + /// + /// Setting current value. + /// + public virtual T Value + { + get => _value; + set + { + _value = value; + _valueSetter(value); + } + } + } + + /// + /// A settings store using JSON as storage. + /// + internal static class JsonSettingsService + { + private const string FileName = "Priceall.json"; + + private static string _settingsPath; + + private static JObject _settings; + + private static Dictionary _settingObjects; + + /// + /// Loads the settings file if there is one, or create empty settings otherwise. + /// + private static void Initialize() + { + var dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + _settingsPath = Path.Combine(dir, FileName); + if (File.Exists(_settingsPath)) + { + _settings = JObject.Parse(File.ReadAllText(_settingsPath)); + } + else + { + _settings = new JObject(); + } + + _settingObjects = new Dictionary(); + } + + private static void SetSetting(string name, T value) where T : struct + { + if (_settings == null) + { + throw new Exception( + "Attempted to set a setting while the service is not yet initialized."); + } + + _settings[name] = JToken.FromObject(value); + File.WriteAllText(_settingsPath, _settings.ToString()); + } + + public static JsonSetting CreateSetting(string name, T defaultValue) where T : struct + { + if (_settings == null) + { + Initialize(); + } + + // Do we have this setting singleton already? + if (_settingObjects.TryGetValue(name, out var s)) + { + if (s is JsonSetting sT) + { + return sT; + } + + throw new Exception($"A setting named {name} already exists " + + $"and has a different type than {typeof(T)}."); + } + + // Do we have this key in settings already? + T value; + if (_settings.TryGetValue(name, out var v)) + { + value = v.ToObject(); + } + else + { + value = defaultValue; + } + + var setting = new JsonSetting(name, defaultValue, value, + newValue => SetSetting(name, newValue)); + _settingObjects[name] = setting; + return setting; + } + } +} diff --git a/Priceall/SettingsWindow.xaml b/Priceall/SettingsWindow.xaml index cfd0740..c0f8045 100644 --- a/Priceall/SettingsWindow.xaml +++ b/Priceall/SettingsWindow.xaml @@ -159,13 +159,13 @@