diff --git a/assemblies/mshtml.dll b/assemblies/mshtml.dll new file mode 100644 index 000000000..ef85196b6 Binary files /dev/null and b/assemblies/mshtml.dll differ diff --git a/source/Grabacr07.KanColleViewer/App.config b/source/Grabacr07.KanColleViewer/App.config index ac9f095cd..5289d41fa 100644 --- a/source/Grabacr07.KanColleViewer/App.config +++ b/source/Grabacr07.KanColleViewer/App.config @@ -39,6 +39,9 @@ display:none!important; } + + http://shatteredskies.blob.core.windows.net/kancolle/sally.json + diff --git a/source/Grabacr07.KanColleViewer/KanColleViewer.csproj b/source/Grabacr07.KanColleViewer/KanColleViewer.csproj index b22df4556..5981b82f6 100644 --- a/source/Grabacr07.KanColleViewer/KanColleViewer.csproj +++ b/source/Grabacr07.KanColleViewer/KanColleViewer.csproj @@ -69,6 +69,10 @@ ..\packages\LivetExtensions.1.1.0.0\lib\net45\Livet.Extensions.dll + + ..\packages\log4net.2.0.3\lib\net40-full\log4net.dll + True + False ..\..\assemblies\Microsoft.Expression.Drawing.dll @@ -77,10 +81,19 @@ ..\packages\LivetCask.1.3.1.0\lib\net45\Microsoft.Expression.Interactions.dll True + + ..\..\assemblies\mshtml.dll + True + + + ..\packages\Nekoxy.1.5.1.19\lib\net45\Nekoxy.dll + True + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll True @@ -114,6 +127,10 @@ 4.0 + + ..\packages\Nekoxy.1.5.1.19\lib\net45\TrotiNet.dll + True + ..\..\assemblies\Vannatech.CoreAudio.dll @@ -141,6 +158,7 @@ + @@ -601,15 +619,6 @@ - - {3050F1C5-98B5-11CF-BB82-00AA00BDCE0B} - 4 - 0 - 0 - primary - False - True - {EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B} 1 diff --git a/source/Grabacr07.KanColleViewer/Models/Helper.cs b/source/Grabacr07.KanColleViewer/Models/Helper.cs index d48da22b2..6df78c50e 100644 --- a/source/Grabacr07.KanColleViewer/Models/Helper.cs +++ b/source/Grabacr07.KanColleViewer/Models/Helper.cs @@ -4,13 +4,17 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Net; +using System.Net.Http; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using System.Windows; +using System.Windows.Media; using Grabacr07.KanColleViewer.Win32; using Microsoft.Win32; +using Nekoxy; namespace Grabacr07.KanColleViewer.Models { @@ -141,69 +145,62 @@ private static bool DeleteInternetCacheCore() } - /// - /// 指定した文字列を暗号化します。 - /// - /// 暗号化する文字列。 - /// 暗号化に使用するパスワード。 - /// 暗号化された文字列。 - public static string EncryptString(string source, string password) - { - using (var rijndael = new RijndaelManaged()) - { - byte[] key, iv; - GenerateKeyFromPassword(password, rijndael.KeySize, out key, rijndael.BlockSize, out iv); - rijndael.Key = key; - rijndael.IV = iv; - - using (var encryptor = rijndael.CreateEncryptor()) - { - var strBytes = Encoding.UTF8.GetBytes(source); - var encBytes = encryptor.TransformFinalBlock(strBytes, 0, strBytes.Length); - return Convert.ToBase64String(encBytes); - } - } - } - - /// - /// 指定された文字列を複合化します。 - /// - /// 暗号化された文字列。 - /// 暗号化に使用したパスワード。 - /// 復号化された文字列。 - public static string DecryptString(string source, string password) + public static Color StringToColor(string colorCode) { try { - using (var rijndael = new RijndaelManaged()) + if (colorCode.StartsWith("#")) { - byte[] key, iv; - GenerateKeyFromPassword(password, rijndael.KeySize, out key, rijndael.BlockSize, out iv); - rijndael.Key = key; - rijndael.IV = iv; - - using (var decryptor = rijndael.CreateDecryptor()) + if (colorCode.Length == 7) + { + // #rrggbb style + return Color.FromRgb( + Convert.ToByte(colorCode.Substring(1, 2), 16), + Convert.ToByte(colorCode.Substring(3, 2), 16), + Convert.ToByte(colorCode.Substring(5, 2), 16)); + } + if (colorCode.Length == 9) { - var strBytes = Convert.FromBase64String(source); - var decBytes = decryptor.TransformFinalBlock(strBytes, 0, strBytes.Length); - return Encoding.UTF8.GetString(decBytes); + // #aarrggbb style + return Color.FromArgb( + Convert.ToByte(colorCode.Substring(1, 2), 16), + Convert.ToByte(colorCode.Substring(3, 2), 16), + Convert.ToByte(colorCode.Substring(5, 2), 16), + Convert.ToByte(colorCode.Substring(7, 2), 16)); } } } catch (Exception ex) { - Debug.WriteLine(ex); - return null; + // 雑 + System.Diagnostics.Debug.WriteLine(ex); } + + return Colors.Transparent; } - private static void GenerateKeyFromPassword(string password, int keySize, out byte[] key, int blockSize, out byte[] iv) + public static HttpClientHandler GetProxyConfiguredHandler() { - var salt = Encoding.UTF8.GetBytes("C98534F6-7286-4BED-83A6-10FD5052ABA6"); - using (var deriveBytes = new Rfc2898DeriveBytes(password, salt) { IterationCount = 1000 }) + switch (HttpProxy.UpstreamProxyConfig.Type) { - key = deriveBytes.GetBytes(keySize / 8); - iv = deriveBytes.GetBytes(blockSize / 8); + case ProxyConfigType.DirectAccess: + return new HttpClientHandler + { + UseProxy = false, + }; + + case ProxyConfigType.SpecificProxy: + return new HttpClientHandler + { + UseProxy = true, + Proxy = new WebProxy($"{HttpProxy.UpstreamProxyConfig.SpecificProxyHost}:{HttpProxy.UpstreamProxyConfig.SpecificProxyPort}"), + }; + + case ProxyConfigType.SystemProxy: + return new HttpClientHandler(); + + default: + return new HttpClientHandler(); } } } diff --git a/source/Grabacr07.KanColleViewer/Models/SallyArea.cs b/source/Grabacr07.KanColleViewer/Models/SallyArea.cs new file mode 100644 index 000000000..ee7a747b6 --- /dev/null +++ b/source/Grabacr07.KanColleViewer/Models/SallyArea.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using System.Windows.Media; +using Codeplex.Data; + +namespace Grabacr07.KanColleViewer.Models +{ + public class SallyArea + { + public int Area { get; private set; } + + public string Name { get; private set; } + + public Color Color { get; private set; } = Colors.Transparent; + + private SallyArea() { } + + public static SallyArea Default { get; } = new SallyArea(); + + public static async Task GetAsync() + { + using (var client = new HttpClient(Helper.GetProxyConfiguredHandler())) + { + try + { + var uri = new Uri(Properties.Settings.Default.SallyAreaSource); + var response = await client.GetAsync(uri); + if (response.IsSuccessStatusCode) + { + var content = await response.Content.ReadAsStringAsync(); + var json = DynamicJson.Parse(content); + var result = ((object[])json) + .Select(x => (dynamic)x) + .Select(x => + new SallyArea + { + Area = (int)x.area, + Name = (string)x.name, + Color = Helper.StringToColor(x.color) + }) + .ToArray(); + + return result; + } + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine(ex); + StatusService.Current.Notify("出撃海域の取得に失敗しました: " + ex); + } + } + + return new SallyArea[0]; + } + } +} diff --git a/source/Grabacr07.KanColleViewer/Properties/AssemblyInfo.cs b/source/Grabacr07.KanColleViewer/Properties/AssemblyInfo.cs index 0f8406576..569c9ad3b 100644 --- a/source/Grabacr07.KanColleViewer/Properties/AssemblyInfo.cs +++ b/source/Grabacr07.KanColleViewer/Properties/AssemblyInfo.cs @@ -52,4 +52,4 @@ // すべての値を指定するか、下のように '*' を使ってビルドおよびリビジョン番号を // 既定値にすることができます: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("4.1.6.7")] +[assembly: AssemblyVersion("4.1.7.0")] diff --git a/source/Grabacr07.KanColleViewer/Properties/Settings.Designer.cs b/source/Grabacr07.KanColleViewer/Properties/Settings.Designer.cs index a5536cc8b..ae24ca0d0 100644 --- a/source/Grabacr07.KanColleViewer/Properties/Settings.Designer.cs +++ b/source/Grabacr07.KanColleViewer/Properties/Settings.Designer.cs @@ -60,5 +60,14 @@ public string OverrideStyleSheet { return ((string)(this["OverrideStyleSheet"])); } } + + [global::System.Configuration.ApplicationScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("http://shatteredskies.blob.core.windows.net/kancolle/sally.json")] + public string SallyAreaSource { + get { + return ((string)(this["SallyAreaSource"])); + } + } } } diff --git a/source/Grabacr07.KanColleViewer/Properties/Settings.settings b/source/Grabacr07.KanColleViewer/Properties/Settings.settings index 720cd67f8..bb97b9072 100644 --- a/source/Grabacr07.KanColleViewer/Properties/Settings.settings +++ b/source/Grabacr07.KanColleViewer/Properties/Settings.settings @@ -31,5 +31,8 @@ display:none!important; } + + http://shatteredskies.blob.core.windows.net/kancolle/sally.json + \ No newline at end of file diff --git a/source/Grabacr07.KanColleViewer/ViewModels/Catalogs/ShipCatalogFilter.cs b/source/Grabacr07.KanColleViewer/ViewModels/Catalogs/ShipCatalogFilter.cs index 4d23fdc4c..0b1d59e1f 100644 --- a/source/Grabacr07.KanColleViewer/ViewModels/Catalogs/ShipCatalogFilter.cs +++ b/source/Grabacr07.KanColleViewer/ViewModels/Catalogs/ShipCatalogFilter.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Grabacr07.KanColleViewer.Models; using Grabacr07.KanColleWrapper; using Grabacr07.KanColleWrapper.Models; using Livet; @@ -458,118 +459,148 @@ public void SetFleets(MemberTable fleets) public class ShipSallyAreaFilter : ShipCatalogFilter { - #region None 変更通知プロパティ + #region IsEnabled 変更通知プロパティ - private bool _None = true; + private bool _IsEnabled; - public bool None + public bool IsEnabled { - get { return this._None; } + get { return this._IsEnabled; } set { - if (this._None != value) + if (this._IsEnabled != value) { - this._None = value; + this._IsEnabled = value; + this.ColumnWidth = value ? 65.0 : .0; this.RaisePropertyChanged(); - this.Update(); } } } #endregion - #region E1And2 変更通知プロパティ + #region SallyAreas 変更通知プロパティ - private bool _E1And2 = true; + private SallyAreaFilterChild[] _SallyAreas; - public bool E1And2 + public SallyAreaFilterChild[] SallyAreas { - get { return this._E1And2; } + get { return this._SallyAreas; } set { - if (this._E1And2 != value) + if (this._SallyAreas != value) { - this._E1And2 = value; + this._SallyAreas = value; this.RaisePropertyChanged(); - this.Update(); } } } #endregion - #region E3And6 変更通知プロパティ + #region ColumnWidth 変更通知プロパティ - private bool _E3And6 = true; + private double _ColumnWidth; - public bool E3And6 + public double ColumnWidth { - get { return this._E3And6; } + get { return this._ColumnWidth; } set { - if (this._E3And6 != value) + if (this._ColumnWidth != value) { - this._E3And6 = value; + this._ColumnWidth = value; this.RaisePropertyChanged(); - this.Update(); } } } #endregion - #region E4 変更通知プロパティ - private bool _E4 = true; + public ShipSallyAreaFilter(Action updateAction) : base(updateAction) { } + + public override bool Predicate(Ship ship) + { + // 出撃海域がない or 取得できなかったときは全艦通す + return !this.IsEnabled || this.SallyAreas.Any(x => x.Predicate(ship)); + } - public bool E4 + public void SetSallyArea(SallyArea[] areas) { - get { return this._E4; } - set + if (areas == null || areas.Length == 0) { - if (this._E4 != value) - { - this._E4 = value; - this.RaisePropertyChanged(); - this.Update(); - } + this.IsEnabled = false; + this.SallyAreas = new SallyAreaFilterChild[0]; + } + else + { + this.SallyAreas = EnumerableEx + .Return(null) + .Concat(areas) + .Select(x => new SallyAreaFilterChild(x, this)) + .ToArray(); + this.IsEnabled = true; } + + this.Update(); } - #endregion + public class SallyAreaFilterChild : ViewModel + { + private readonly SallyArea model; + private readonly ShipSallyAreaFilter owner; - #region E5 変更通知プロパティ + #region Name 変更通知プロパティ - private bool _E5 = true; + private string _Name; - public bool E5 - { - get { return this._E5; } - set + public string Name { - if (this._E5 != value) + get { return this._Name; } + set { - this._E5 = value; - this.RaisePropertyChanged(); - this.Update(); + if (this._Name != value) + { + this._Name = value; + this.RaisePropertyChanged(); + } } } - } - #endregion + #endregion + #region IsChecked 変更通知プロパティ - public ShipSallyAreaFilter(Action updateAction) : base(updateAction) { } + private bool _IsChecked = true; - public override bool Predicate(Ship ship) - { - if (this.None && ship.SallyArea == 0) return true; - if (this.E1And2 && ship.SallyArea == 1) return true; - if (this.E3And6 && ship.SallyArea == 2) return true; - if (this.E4 && ship.SallyArea == 3) return true; - if (this.E5 && ship.SallyArea == 4) return true; + public bool IsChecked + { + get { return this._IsChecked; } + set + { + if (this._IsChecked != value) + { + this._IsChecked = value; + this.RaisePropertyChanged(); + this.owner.Update(); + } + } + } - return false; + #endregion + + public SallyAreaFilterChild(SallyArea area, ShipSallyAreaFilter owner) + { + this.model = area ?? SallyArea.Default; + this.owner = owner; + this.Name = area?.Name ?? "出撃海域なし"; + } + + public bool Predicate(Ship ship) + { + return this.IsChecked && this.model.Area == ship.SallyArea; + } } } } diff --git a/source/Grabacr07.KanColleViewer/ViewModels/Catalogs/ShipCatalogWindowViewModel.cs b/source/Grabacr07.KanColleViewer/ViewModels/Catalogs/ShipCatalogWindowViewModel.cs index ff2025e38..e0748d91d 100644 --- a/source/Grabacr07.KanColleViewer/ViewModels/Catalogs/ShipCatalogWindowViewModel.cs +++ b/source/Grabacr07.KanColleViewer/ViewModels/Catalogs/ShipCatalogWindowViewModel.cs @@ -4,6 +4,8 @@ using System.Reactive; using System.Reactive.Linq; using System.Reactive.Subjects; +using System.Reactive.Threading.Tasks; +using Grabacr07.KanColleViewer.Models; using Grabacr07.KanColleViewer.Models.Settings; using Grabacr07.KanColleViewer.Properties; using Grabacr07.KanColleWrapper; @@ -15,6 +17,7 @@ public class ShipCatalogWindowViewModel : WindowViewModel { private readonly Subject updateSource = new Subject(); private readonly Homeport homeport = KanColleClient.Current.Homeport; + private SallyArea[] sallyAreas; public ShipCatalogWindowSettings Settings { get; } @@ -142,11 +145,10 @@ public ShipCatalogWindowViewModel() this.updateSource .Do(_ => this.IsReloading = true) - // ☟ 連続で艦種選択できるように猶予を設けるつもりだったけど、 - //   ソートだけしたいケースとかだと遅くてイラ壁なので迷う - .Throttle(TimeSpan.FromMilliseconds(7.0)) - .Do(_ => this.UpdateCore()) - .Subscribe(_ => this.IsReloading = false) + .SelectMany(_ => this.GetSallyAreaAsync()) + .SelectMany(x => this.UpdateAsync(x)) + .Do(_ => this.IsReloading = false) + .Subscribe() .AddTo(this); this.homeport.Organization @@ -154,7 +156,6 @@ public ShipCatalogWindowViewModel() .AddTo(this); } - public void Update() { this.ShipExpeditionFilter.SetFleets(this.homeport.Organization.Fleets); @@ -163,24 +164,40 @@ public void Update() this.updateSource.OnNext(Unit.Default); } - private void UpdateCore() + private IObservable UpdateAsync(SallyArea[] areas) { - var list = this.homeport.Organization.Ships - .Select(kvp => kvp.Value) - .Where(x => this.ShipTypes.Where(t => t.IsSelected).Any(t => x.Info.ShipType.Id == t.Id)) - .Where(this.ShipLevelFilter.Predicate) - .Where(this.ShipLockFilter.Predicate) - .Where(this.ShipSpeedFilter.Predicate) - .Where(this.ShipModernizeFilter.Predicate) - .Where(this.ShipRemodelingFilter.Predicate) - .Where(this.ShipExpeditionFilter.Predicate) - .Where(this.ShipSallyAreaFilter.Predicate); - - this.Ships = this.SortWorker.Sort(list) - .Select((x, i) => new ShipViewModel(i + 1, x)) - .ToList(); + return Observable.Start(() => + { + var list = this.homeport.Organization.Ships + .Select(kvp => kvp.Value) + .Where(x => this.ShipTypes.Where(t => t.IsSelected).Any(t => x.Info.ShipType.Id == t.Id)) + .Where(this.ShipLevelFilter.Predicate) + .Where(this.ShipLockFilter.Predicate) + .Where(this.ShipSpeedFilter.Predicate) + .Where(this.ShipModernizeFilter.Predicate) + .Where(this.ShipRemodelingFilter.Predicate) + .Where(this.ShipExpeditionFilter.Predicate) + .Where(this.ShipSallyAreaFilter.Predicate); + + this.Ships = this.SortWorker.Sort(list) + .Select((x, i) => new ShipViewModel(i + 1, x, areas.FirstOrDefault(y => y.Area == x.SallyArea))) + .ToList(); + }); } + private IObservable GetSallyAreaAsync() + { + return this.sallyAreas == null + ? SallyArea.GetAsync() + .ToObservable() + .Do(x => + { + // これはひどい + this.sallyAreas = x; + this.ShipSallyAreaFilter.SetSallyArea(x); + }) + : Observable.Return(this.sallyAreas); + } public void SetShipType(int[] ids) { diff --git a/source/Grabacr07.KanColleViewer/ViewModels/Catalogs/ShipViewModel.cs b/source/Grabacr07.KanColleViewer/ViewModels/Catalogs/ShipViewModel.cs index d81d75f2d..d1c1b7d8d 100644 --- a/source/Grabacr07.KanColleViewer/ViewModels/Catalogs/ShipViewModel.cs +++ b/source/Grabacr07.KanColleViewer/ViewModels/Catalogs/ShipViewModel.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Grabacr07.KanColleViewer.Models; using Grabacr07.KanColleWrapper.Models; using Livet; @@ -13,10 +14,13 @@ public class ShipViewModel : ViewModel public Ship Ship { get; } - public ShipViewModel(int index, Ship ship) + public SallyArea SallyArea { get; } + + public ShipViewModel(int index, Ship ship, SallyArea sallyArea) { this.Index = index; this.Ship = ship; + this.SallyArea = sallyArea ?? SallyArea.Default; } } } diff --git a/source/Grabacr07.KanColleViewer/Views/Catalogs/ShipCatalogWindow.xaml b/source/Grabacr07.KanColleViewer/Views/Catalogs/ShipCatalogWindow.xaml index c9b6292cf..a11560dc1 100644 --- a/source/Grabacr07.KanColleViewer/Views/Catalogs/ShipCatalogWindow.xaml +++ b/source/Grabacr07.KanColleViewer/Views/Catalogs/ShipCatalogWindow.xaml @@ -404,29 +404,28 @@ - + Padding="5" + Visibility="{Binding ShipSallyAreaFilter.IsEnabled, Converter={StaticResource BooleanToVisibilityConverter}}"> + - - - - - - - + + + + + + + + + + + + + @@ -784,7 +783,7 @@ - + @@ -792,49 +791,13 @@ - + + + - - - - - - - - - - - - - - - - - - diff --git a/source/Grabacr07.KanColleViewer/packages.config b/source/Grabacr07.KanColleViewer/packages.config index 4eff8e787..c0fec3cee 100644 --- a/source/Grabacr07.KanColleViewer/packages.config +++ b/source/Grabacr07.KanColleViewer/packages.config @@ -2,6 +2,8 @@ + + diff --git a/source/Plugins/WindowsNotifier/BalloonNotifier.cs b/source/Plugins/WindowsNotifier/BalloonNotifier.cs index d753a4a14..898aafd15 100644 --- a/source/Plugins/WindowsNotifier/BalloonNotifier.cs +++ b/source/Plugins/WindowsNotifier/BalloonNotifier.cs @@ -27,30 +27,36 @@ protected override void InitializeCore() if (streamResourceInfo == null) return; - using (var stream = streamResourceInfo.Stream) + System.Windows.Application.Current.Dispatcher.Invoke(() => { - this.notifyIcon = new NotifyIcon + using (var stream = streamResourceInfo.Stream) { - Text = ProductInfo.Title, - Icon = new Icon(stream), - Visible = true, - }; - } + this.notifyIcon = new NotifyIcon + { + Text = ProductInfo.Title, + Icon = new Icon(stream), + Visible = true, + }; + } + }); } protected override void NotifyCore(string header, string body, Action activated, Action failed) { if (this.notifyIcon == null) return; - if (activated != null) + System.Windows.Application.Current.Dispatcher.Invoke(() => { - this.notifyIcon.BalloonTipClicked -= this.activatedAction; + if (activated != null) + { + this.notifyIcon.BalloonTipClicked -= this.activatedAction; - this.activatedAction = (sender, args) => activated(); - this.notifyIcon.BalloonTipClicked += this.activatedAction; - } + this.activatedAction = (sender, args) => activated(); + this.notifyIcon.BalloonTipClicked += this.activatedAction; + } - this.notifyIcon.ShowBalloonTip(1000, header, body, ToolTipIcon.None); + this.notifyIcon.ShowBalloonTip(1000, header, body, ToolTipIcon.None); + }); } public override void Dispose()