From 2abd2837ed60495f6ffafca40b290b40e2df9bbd Mon Sep 17 00:00:00 2001 From: Kazuhiro Fujieda Date: Sat, 25 Apr 2020 15:38:53 +0900 Subject: [PATCH] =?utf8?q?=E9=80=9A=E7=9F=A5=E3=81=AB=E9=96=A2=E3=81=99?= =?utf8?q?=E3=82=8B=E3=82=AF=E3=83=A9=E3=82=B9=E3=81=AE=E5=90=8D=E5=89=8D?= =?utf8?q?=E3=81=A8=E5=90=8D=E5=89=8D=E7=A9=BA=E9=96=93=E3=82=92=E5=A4=89?= =?utf8?q?=E6=9B=B4=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- KancolleSniffer.Test/NotificationManagerTest.cs | 29 +- KancolleSniffer/ConfigDialog.cs | 4 +- KancolleSniffer/KancolleSniffer.csproj | 14 +- KancolleSniffer/MainForm.cs | 41 +-- .../ConfigDialog.Designer.cs} | 6 +- .../ConfigDialog.cs} | 22 +- .../ConfigDialog.resx} | 0 KancolleSniffer/Notification/Formatter.cs | 208 +++++++++++++ KancolleSniffer/Notification/Scheduler.cs | 156 ++++++++++ KancolleSniffer/NotificationManager.cs | 345 --------------------- 10 files changed, 431 insertions(+), 394 deletions(-) rename KancolleSniffer/{NotificationConfigDialog.Designer.cs => Notification/ConfigDialog.Designer.cs} (97%) rename KancolleSniffer/{NotificationConfigDialog.cs => Notification/ConfigDialog.cs} (87%) rename KancolleSniffer/{NotificationConfigDialog.resx => Notification/ConfigDialog.resx} (100%) create mode 100644 KancolleSniffer/Notification/Formatter.cs create mode 100644 KancolleSniffer/Notification/Scheduler.cs delete mode 100644 KancolleSniffer/NotificationManager.cs diff --git a/KancolleSniffer.Test/NotificationManagerTest.cs b/KancolleSniffer.Test/NotificationManagerTest.cs index 79da93f..5825f82 100644 --- a/KancolleSniffer.Test/NotificationManagerTest.cs +++ b/KancolleSniffer.Test/NotificationManagerTest.cs @@ -14,6 +14,7 @@ using System; using ExpressionToCodeLib; +using KancolleSniffer.Notification; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace KancolleSniffer.Test @@ -55,7 +56,7 @@ namespace KancolleSniffer.Test var time = new TimeProvider(); Message result = null; var manager = - new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); + new Scheduler((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); manager.Enqueue("遠征終了", 1, "防空射撃演習"); manager.Flash(); PAssert.That(() => new Message {Title = "遠征が終わりました", Body = "第二艦隊 防空射撃演習", Name = "遠征終了"}.Equals(result)); @@ -70,7 +71,7 @@ namespace KancolleSniffer.Test var time = new TimeProvider(); Message result = null; var manager = - new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); + new Scheduler((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); manager.Enqueue("遠征終了", 1, "防空射撃演習"); manager.Enqueue("疲労回復49", 1, "cond49"); manager.Flash(); @@ -91,7 +92,7 @@ namespace KancolleSniffer.Test var time = new TimeProvider(); Message result = null; var manager = - new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); + new Scheduler((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); manager.Enqueue("建造完了", 0, ""); manager.Flash(); PAssert.That(() => new Message {Title = "建造が終わりました", Body = "第一ドック", Name = "建造完了"}.Equals(result)); @@ -110,7 +111,7 @@ namespace KancolleSniffer.Test var time = new TimeProvider(); Message result = null; var manager = - new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); + new Scheduler((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); var expected = new Message {Title = "遠征が終わりました", Body = "第二艦隊 防空射撃演習", Name = "遠征終了"}; var elapsed = 0; while (true) @@ -149,7 +150,7 @@ namespace KancolleSniffer.Test var time = new TimeProvider(); Message result = null; var manager = - new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); + new Scheduler((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); var ensei = new Message {Title = "遠征が終わりました", Body = "第二艦隊 防空射撃演習", Name = "遠征終了"}; var hakuchi = new Message {Title = "泊地修理 第一艦隊", Body = "20分経過しました。", Name = "泊地修理20分経過"}; var elapsed = 0; @@ -194,7 +195,7 @@ namespace KancolleSniffer.Test var time = new TimeProvider(); Message result = null; var manager = - new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); + new Scheduler((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); var ensei = new Message {Title = "遠征が終わりました", Body = "第二艦隊 防空射撃演習", Name = "遠征終了"}; var hakuchi = new Message {Title = "泊地修理 第一艦隊", Body = "20分経過しました。", Name = "泊地修理20分経過"}; var elapsed = 0; @@ -242,7 +243,7 @@ namespace KancolleSniffer.Test var time = new TimeProvider(); Message result = null; var manager = - new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); + new Scheduler((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); var ensei = new Message {Title = "遠征が終わりました", Body = "第二艦隊 防空射撃演習", Name = "遠征終了"}; var nyukyo = new Message {Title = "入渠が終わりました", Body = "第一ドック 綾波改二", Name = "入渠終了"}; var elapsed = 0; @@ -291,7 +292,7 @@ namespace KancolleSniffer.Test var time = new TimeProvider(); Message result = null; var manager = - new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); + new Scheduler((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); var expected = new Message {Title = "遠征が終わりました", Body = "第二艦隊 防空射撃演習", Name = "遠征終了"}; var elapsed = 0; while (true) @@ -334,7 +335,7 @@ namespace KancolleSniffer.Test var time = new TimeProvider(); Message result = null; var manager = - new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); + new Scheduler((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); var ensei = new Message {Title = "遠征が終わりました", Body = "第二艦隊 防空射撃演習", Name = "遠征終了"}; var taiha = new Message {Title = "大破した艦娘がいます", Body = "摩耶改二", Name = "大破警告"}; var elapsed = 0; @@ -387,7 +388,7 @@ namespace KancolleSniffer.Test var time = new TimeProvider(); Message result = null; var manager = - new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); + new Scheduler((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); var expected1 = new Message {Title = "遠征が終わりました", Body = "第二艦隊 防空射撃演習", Name = "遠征終了"}; var expected2 = new Message {Title = "遠征が終わりました", Body = "第三艦隊 海上護衛任務", Name = "遠征終了"}; var elapsed = 0; @@ -435,7 +436,7 @@ namespace KancolleSniffer.Test var time = new TimeProvider(); Message result = null; var manager = - new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); + new Scheduler((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); var expected1 = new Message {Title = "遠征が終わりました", Body = "第二艦隊 防空射撃演習", Name = "遠征終了"}; var expected2 = new Message {Title = "遠征が終わりました", Body = "第二艦隊 ", Name = "遠征終了"}; var elapsed = 0; @@ -482,7 +483,7 @@ namespace KancolleSniffer.Test var time = new TimeProvider(); Message result = null; var manager = - new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); + new Scheduler((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); var expected = new Message {Title = "[予告] 遠征が終わりました", Body = "第二艦隊 防空射撃演習", Name = "遠征終了"}; manager.Enqueue("遠征終了", 1, "防空射撃演習", 0, true); manager.Flash(); @@ -498,7 +499,7 @@ namespace KancolleSniffer.Test var time = new TimeProvider(); Message result = null; var manager = - new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); + new Scheduler((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); manager.Enqueue("遠征終了", 1, "防空射撃演習", 10); manager.Enqueue("遠征終了", 2, "海上護衛任務", 10); manager.Flash(); @@ -515,7 +516,7 @@ namespace KancolleSniffer.Test var time = new TimeProvider(); Message result = null; var manager = - new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); + new Scheduler((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, time.GetNow); var expected1 = new Message {Title = "遠征が終わりました", Body = "第二艦隊 防空射撃演習\r\n第三艦隊 海上護衛任務", Name = "遠征終了"}; var expected2 = new Message {Title = "遠征が終わりました", Body = "第三艦隊 海上護衛任務", Name = "遠征終了"}; var elapsed = 0; diff --git a/KancolleSniffer/ConfigDialog.cs b/KancolleSniffer/ConfigDialog.cs index 9537b27..120a3c8 100644 --- a/KancolleSniffer/ConfigDialog.cs +++ b/KancolleSniffer/ConfigDialog.cs @@ -36,7 +36,7 @@ namespace KancolleSniffer private Point _prevPosition = new Point(int.MinValue, int.MinValue); public List RepeatSettingsChanged { get; } = new List(); - public NotificationConfigDialog NotificationConfigDialog { get; } + public Notification.ConfigDialog NotificationConfigDialog { get; } public ConfigDialog(MainForm main) { @@ -47,7 +47,7 @@ namespace KancolleSniffer listBoxSoundFile.Items.AddRange(Config.NotificationNames); numericUpDownMaterialLogInterval.Maximum = 1440; - NotificationConfigDialog = new NotificationConfigDialog(_notificationSettings, + NotificationConfigDialog = new Notification.ConfigDialog(_notificationSettings, new Dictionary { {NotificationType.FlashWindow, checkBoxFlash}, diff --git a/KancolleSniffer/KancolleSniffer.csproj b/KancolleSniffer/KancolleSniffer.csproj index c4d067f..e407909 100644 --- a/KancolleSniffer/KancolleSniffer.csproj +++ b/KancolleSniffer/KancolleSniffer.csproj @@ -68,6 +68,7 @@ + @@ -167,13 +168,13 @@ - + Form - - NotificationConfigDialog.cs + + ConfigDialog.cs - + @@ -242,8 +243,8 @@ MainForm.cs - - NotificationConfigDialog.cs + + ConfigDialog.cs ResXFileCodeGenerator @@ -275,6 +276,7 @@ + COPY $(SolutionDir)\Data\*.* $(TargetDir) diff --git a/KancolleSniffer/MainForm.cs b/KancolleSniffer/MainForm.cs index 1574f25..0337c79 100644 --- a/KancolleSniffer/MainForm.cs +++ b/KancolleSniffer/MainForm.cs @@ -31,6 +31,7 @@ using DynaJson; using KancolleSniffer.Log; using KancolleSniffer.Model; using KancolleSniffer.Net; +using KancolleSniffer.Notification; using KancolleSniffer.Util; using KancolleSniffer.View; using Microsoft.CSharp.RuntimeBinder; @@ -47,7 +48,7 @@ namespace KancolleSniffer private readonly ResizableToolTip _tooltipCopy = new ResizableToolTip {ShowAlways = false, AutomaticDelay = 0}; private readonly ListFormGroup _listFormGroup; - private readonly NotificationManager _notificationManager; + private readonly Scheduler _notificationScheduler; private bool _started; private bool _timerEnabled; private string _debugLogFile; @@ -75,7 +76,7 @@ namespace KancolleSniffer Config.Load(); _configDialog = new ConfigDialog(this); _listFormGroup = new ListFormGroup(this); - _notificationManager = new NotificationManager(Alarm); + _notificationScheduler = new Scheduler(Alarm); SetupView(); _proxyManager = new ProxyManager(this); _proxyManager.UpdatePacFile(); @@ -106,7 +107,7 @@ namespace KancolleSniffer hqPanel, missionPanel, kdockPanel, ndockPanel, materialHistoryPanel, shipInfoPanel, chargeStatus1, chargeStatus2, chargeStatus3, chargeStatus4 }; - var context = new UpdateContext(Sniffer, Config, new NotifySubmitter(_notificationManager), () => _now); + var context = new UpdateContext(Sniffer, Config, new NotifySubmitter(_notificationScheduler), () => _now); foreach (var updateable in _updateable) updateable.Context = context; _timers = new IUpdateTimers[] {missionPanel, kdockPanel, ndockPanel, shipInfoPanel}; @@ -128,9 +129,9 @@ namespace KancolleSniffer private class NotifySubmitter : INotifySubmitter { - private readonly NotificationManager _manager; + private readonly Scheduler _manager; - public NotifySubmitter(NotificationManager manager) + public NotifySubmitter(Scheduler manager) { _manager = manager; } @@ -183,12 +184,12 @@ namespace KancolleSniffer private class RepeatingTimerController : Sniffer.IRepeatingTimerController { - private readonly NotificationManager _manager; + private readonly Scheduler _manager; private readonly Config _config; public RepeatingTimerController(MainForm main) { - _manager = main._notificationManager; + _manager = main._notificationScheduler; _config = main.Config; } @@ -300,7 +301,7 @@ namespace KancolleSniffer hqPanel.Login.Visible = false; shipInfoPanel.Guide.Visible = false; _started = true; - _notificationManager.StopAllRepeat(); + _notificationScheduler.StopAllRepeat(); return; } if (!_started) @@ -475,7 +476,7 @@ namespace KancolleSniffer private void StopRepeatingTimer(IEnumerable names) { foreach (var name in names) - _notificationManager.StopRepeat(name); + _notificationScheduler.StopRepeat(name); } private void PerformZoom() @@ -674,11 +675,11 @@ namespace KancolleSniffer private void NotifyDamagedShip() { - _notificationManager.StopRepeat("大破警告"); + _notificationScheduler.StopRepeat("大破警告"); if (!Sniffer.BadlyDamagedShips.Any()) return; SetNotification("大破警告", string.Join(" ", Sniffer.BadlyDamagedShips)); - _notificationManager.Flash(); + _notificationScheduler.Flash(); } private void UpdateBattleInfo() @@ -740,7 +741,7 @@ namespace KancolleSniffer } NotifyCondTimers(); NotifyAkashiTimer(); - _notificationManager.Flash(); + _notificationScheduler.Flash(); } private void CheckAlarm(string key, AlarmTimer timer, int fleet, string subject) @@ -783,12 +784,12 @@ namespace KancolleSniffer var msgs = akashi.GetNotice(_prev, _now); if (msgs.Length == 0) { - _notificationManager.StopRepeat("泊地修理"); + _notificationScheduler.StopRepeat("泊地修理"); return; } if (!akashi.CheckRepairing(_now) && !(akashi.CheckPresetRepairing() && Config.UsePresetAkashi)) { - _notificationManager.StopRepeat("泊地修理"); + _notificationScheduler.StopRepeat("泊地修理"); return; } var skipPreliminary = false; @@ -820,16 +821,16 @@ namespace KancolleSniffer private void SetNotification(string key, int fleet, string subject) { - var spec = Config.Notifications[_notificationManager.KeyToName(key)]; - _notificationManager.Enqueue(key, fleet, subject, + var spec = Config.Notifications[_notificationScheduler.KeyToName(key)]; + _notificationScheduler.Enqueue(key, fleet, subject, (spec.Flags & Config.NotificationFlags & NotificationType.Repeat) == 0 ? 0 : spec.RepeatInterval); } private void SetPreNotification(string key, int fleet, string subject) { - var spec = Config.Notifications[_notificationManager.KeyToName(key)]; + var spec = Config.Notifications[_notificationScheduler.KeyToName(key)]; if ((spec.Flags & NotificationType.Preliminary) != 0) - _notificationManager.Enqueue(key, fleet, subject, 0, true); + _notificationScheduler.Enqueue(key, fleet, subject, 0, true); } private void UpdateRepairList() @@ -851,8 +852,8 @@ namespace KancolleSniffer foreach (var questName in notify) SetNotification("任務達成", 0, questName); foreach (var questName in stop) - _notificationManager.StopRepeat("任務達成", questName); - _notificationManager.Flash(); + _notificationScheduler.StopRepeat("任務達成", questName); + _notificationScheduler.Flash(); } private void Alarm(string balloonTitle, string balloonMessage, string name) diff --git a/KancolleSniffer/NotificationConfigDialog.Designer.cs b/KancolleSniffer/Notification/ConfigDialog.Designer.cs similarity index 97% rename from KancolleSniffer/NotificationConfigDialog.Designer.cs rename to KancolleSniffer/Notification/ConfigDialog.Designer.cs index 7d7b59d..c9ff0d6 100644 --- a/KancolleSniffer/NotificationConfigDialog.Designer.cs +++ b/KancolleSniffer/Notification/ConfigDialog.Designer.cs @@ -1,6 +1,6 @@ -namespace KancolleSniffer +namespace KancolleSniffer.Notification { - partial class NotificationConfigDialog + partial class ConfigDialog { /// /// Required designer variable. @@ -202,7 +202,7 @@ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; this.MaximizeBox = false; this.MinimizeBox = false; - this.Name = "NotificationConfigDialog"; + this.Name = "ConfigDialog"; this.ShowIcon = false; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "通知方法の詳細設定"; diff --git a/KancolleSniffer/NotificationConfigDialog.cs b/KancolleSniffer/Notification/ConfigDialog.cs similarity index 87% rename from KancolleSniffer/NotificationConfigDialog.cs rename to KancolleSniffer/Notification/ConfigDialog.cs index 852c233..c08c243 100644 --- a/KancolleSniffer/NotificationConfigDialog.cs +++ b/KancolleSniffer/Notification/ConfigDialog.cs @@ -1,19 +1,33 @@ -using System; +// Copyright (C) 2017 Kazuhiro Fujieda +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; using KancolleSniffer.View; -namespace KancolleSniffer +namespace KancolleSniffer.Notification { - public partial class NotificationConfigDialog : Form + public partial class ConfigDialog : Form { private readonly Dictionary _notifications; private readonly Dictionary _configCheckBoxes; private readonly ResizableToolTip _toolTip = new ResizableToolTip(); - public NotificationConfigDialog(Dictionary notifications, + public ConfigDialog(Dictionary notifications, Dictionary checkBoxes) { InitializeComponent(); diff --git a/KancolleSniffer/NotificationConfigDialog.resx b/KancolleSniffer/Notification/ConfigDialog.resx similarity index 100% rename from KancolleSniffer/NotificationConfigDialog.resx rename to KancolleSniffer/Notification/ConfigDialog.resx diff --git a/KancolleSniffer/Notification/Formatter.cs b/KancolleSniffer/Notification/Formatter.cs new file mode 100644 index 0000000..ff07f07 --- /dev/null +++ b/KancolleSniffer/Notification/Formatter.cs @@ -0,0 +1,208 @@ +// Copyright (C) 2020 Kazuhiro Fujieda +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections.Generic; +using System.IO; +using DynaJson; + +namespace KancolleSniffer.Notification +{ + public class Formatter + { + public class Message + { + public string Title { get; set; } + public string Body { get; set; } + public string Name { get; set; } + } + + private readonly Dictionary _config = new Dictionary(); + + private readonly Dictionary _default = new Dictionary + { + { + "遠征終了", new Message + { + Title = "遠征が終わりました", + Body = "%f艦隊 %s" + } + }, + { + "入渠終了", new Message + { + Title = "入渠が終わりました", + Body = "%fドック %s" + } + }, + { + "建造完了", new Message + { + Title = "建造が終わりました", + Body = "%fドック" + } + }, + { + "艦娘数超過", new Message + { + Title = "艦娘が多すぎます", + Body = "%s" + } + }, + { + "装備数超過", new Message + { + Title = "装備が多すぎます", + Body = "%s" + } + }, + { + "大破警告", new Message + { + Title = "大破した艦娘がいます", + Body = "%s" + } + }, + { + "泊地修理20分経過", new Message + { + Title = "泊地修理 %f艦隊", + Body = "20分経過しました。" + } + }, + { + "泊地修理進行", new Message + { + Title = "泊地修理 %f艦隊", + Body = "修理進行:%s" + } + }, + { + "泊地修理完了", new Message + { + Title = "泊地修理 %f艦隊", + Body = "修理完了:%s" + } + }, + { + "疲労回復40", new Message + { + Title = "疲労が回復しました", + Body = "%f艦隊 残り9分" + } + }, + { + "疲労回復49", new Message + { + Title = "疲労が回復しました", + Body = "%f艦隊" + } + }, + { + "任務達成", new Message + { + Title = "任務を達成しました", + Body = "%s" + } + } + }; + + public static string KeyToName(string key) => key.StartsWith("疲労回復") ? key.Substring(0, 4) : key; + + private void LoadConfig() + { + const string fileName = "notification.json"; + _config.Clear(); + try + { + dynamic config = JsonObject.Parse(File.ReadAllText(fileName)); + foreach (var entry in config) + { + if (!_default.ContainsKey(entry.key)) + continue; + _config[entry.key] = new Message + { + Title = entry.title, + Body = entry.body + }; + } + } + catch (FileNotFoundException) + { + } + catch (Exception ex) + { + throw new Exception($"{fileName}に誤りがあります。: ${ex.Message}", ex); + } + } + + public Message GenerateMessage(Scheduler.Notification notification) + { + LoadConfig(); + var format = _config.TryGetValue(notification.Key, out Message value) + ? value + : _default[notification.Key]; + var prefix = new[] {"", "[リピート] ", "[継続] ", "[予告] "}[(int)notification.Mode]; + return new Message + { + Title = prefix + ProcessFormatString(format.Title, notification.Fleet, notification.Subject), + Body = ProcessFormatString(format.Body, notification.Fleet, notification.Subject), + Name = KeyToName(notification.Key) + }; + } + + private string ProcessFormatString(string format, int fleet, string subject) + { + var fn = new[] {"第一", "第二", "第三", "第四"}; + var result = ""; + var percent = false; + foreach (var ch in format) + { + if (ch == '%') + { + if (percent) + { + percent = false; + result += '%'; + } + else + { + percent = true; + } + } + else if (percent) + { + percent = false; + switch (ch) + { + case 'f': + result += fn[fleet]; + break; + case 's': + result += subject; + break; + default: + result += '%'.ToString() + ch; + break; + } + } + else + { + result += ch; + } + } + return result; + } + } +} \ No newline at end of file diff --git a/KancolleSniffer/Notification/Scheduler.cs b/KancolleSniffer/Notification/Scheduler.cs new file mode 100644 index 0000000..d793a4d --- /dev/null +++ b/KancolleSniffer/Notification/Scheduler.cs @@ -0,0 +1,156 @@ +// Copyright (C) 2017 Kazuhiro Fujieda +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace KancolleSniffer.Notification +{ + public class Scheduler + { + private readonly Action _alarm; + private readonly List _queue = new List(); + private readonly Func _nowFunc = () => DateTime.Now; + private readonly Formatter _formatter = new Formatter(); + private DateTime _lastAlarm; + private bool _suspend; + private string _suspendException; + + public enum Mode + { + Normal, + Repeat, + Cont, + Preliminary + } + + public class Notification + { + public string Key { get; set; } + public int Fleet { get; set; } + public string Subject { get; set; } + public int Repeat { get; set; } + public Mode Mode { get; set; } + public DateTime Schedule { get; set; } + } + + public Scheduler(Action alarm, Func nowFunc = null) + { + _alarm = alarm; + if (nowFunc != null) + _nowFunc = nowFunc; + } + + public void Enqueue(string key, int fleet, string subject, int repeat = 0, bool preliminary = false) + { + _queue.Add(new Notification + { + Key = key, + Fleet = fleet, + Subject = subject, + Repeat = repeat, + Mode = preliminary ? Mode.Preliminary : Mode.Normal + }); + } + + public void Enqueue(string key, string subject, int repeat = 0) + { + Enqueue(key, 0, subject, repeat); + } + + public void Flash() + { + Alarm(); + } + + public void StopRepeat(string key, bool cont = false) + { + if (!cont) + { + _queue.RemoveAll(n => IsMatch(n, key)); + } + else + { + foreach (var n in _queue.Where(n => IsMatch(n, key))) + { + n.Subject = ""; + n.Mode = Mode.Cont; + } + } + } + + public void StopRepeat(string key, int fleet) + { + _queue.RemoveAll(n => IsMatch(n, key) && n.Fleet == fleet); + } + + public void StopRepeat(string key, string subject) + { + _queue.RemoveAll(n => IsMatch(n, key) && n.Subject == subject); + } + + public void StopAllRepeat() + { + _queue.RemoveAll(n => n.Schedule != default); + } + + public void SuspendRepeat(string exception = "") + { + _suspend = true; + _suspendException = exception; + } + + public void ResumeRepeat() + { + _suspend = false; + } + + public string KeyToName(string key) => Formatter.KeyToName(key); + + private bool IsMatch(Notification n, string key) => + n.Key.Substring(0, 4) == key.Substring(0, 4) && n.Schedule != default; + + private void Alarm() + { + var now = _nowFunc(); + if (now - _lastAlarm < TimeSpan.FromSeconds(2)) + return; + var first = _queue.FirstOrDefault(n => n.Schedule.CompareTo(now) <= 0 && + !(n.Schedule != default && _suspend && n.Key != _suspendException)); + if (first == null) + return; + var message = _formatter.GenerateMessage(first); + var similar = _queue.Where(n => + _formatter.GenerateMessage(n).Name == message.Name && n.Schedule.CompareTo(now) <= 0) + .ToArray(); + var body = string.Join("\r\n", similar.Select(n => _formatter.GenerateMessage(n).Body)); + foreach (var n in similar) + { + if (n.Repeat == 0) + { + _queue.Remove(n); + } + else + { + n.Schedule = now + TimeSpan.FromSeconds(n.Repeat); + if (n.Mode == Mode.Normal) + n.Mode = Mode.Repeat; + } + } + _alarm(message.Title, body, message.Name); + _lastAlarm = now; + } + } +} \ No newline at end of file diff --git a/KancolleSniffer/NotificationManager.cs b/KancolleSniffer/NotificationManager.cs deleted file mode 100644 index dbae8a1..0000000 --- a/KancolleSniffer/NotificationManager.cs +++ /dev/null @@ -1,345 +0,0 @@ -// Copyright (C) 2017 Kazuhiro Fujieda -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using DynaJson; - -namespace KancolleSniffer -{ - public class NotificationManager - { - private readonly Action _alarm; - private readonly List _queue = new List(); - private readonly Func _nowFunc = () => DateTime.Now; - private readonly NotificationConfig _notificationConfig = new NotificationConfig(); - private DateTime _lastAlarm; - private bool _suspend; - private string _suspendException; - - private enum Mode - { - Normal, - Repeat, - Cont, - Preliminary - } - - private class Notification - { - public string Key { get; set; } - public int Fleet { get; set; } - public string Subject { get; set; } - public int Repeat { get; set; } - public Mode Mode { get; set; } - public DateTime Schedule { get; set; } - } - - public NotificationManager(Action alarm, Func nowFunc = null) - { - _alarm = alarm; - if (nowFunc != null) - _nowFunc = nowFunc; - } - - public void Enqueue(string key, int fleet, string subject, int repeat = 0, bool preliminary = false) - { - _queue.Add(new Notification - { - Key = key, - Fleet = fleet, - Subject = subject, - Repeat = repeat, - Mode = preliminary ? Mode.Preliminary : Mode.Normal - }); - } - - public void Enqueue(string key, string subject, int repeat = 0) - { - Enqueue(key, 0, subject, repeat); - } - - public void Flash() - { - Alarm(); - } - - public void StopRepeat(string key, bool cont = false) - { - if (!cont) - { - _queue.RemoveAll(n => IsMatch(n, key)); - } - else - { - foreach (var n in _queue.Where(n => IsMatch(n, key))) - { - n.Subject = ""; - n.Mode = Mode.Cont; - } - } - } - - public void StopRepeat(string key, int fleet) - { - _queue.RemoveAll(n => IsMatch(n, key) && n.Fleet == fleet); - } - - public void StopRepeat(string key, string subject) - { - _queue.RemoveAll(n => IsMatch(n, key) && n.Subject == subject); - } - - public void StopAllRepeat() - { - _queue.RemoveAll(n => n.Schedule != default); - } - - public void SuspendRepeat(string exception = "") - { - _suspend = true; - _suspendException = exception; - } - - public void ResumeRepeat() - { - _suspend = false; - } - - public string KeyToName(string key) => NotificationConfig.KeyToName(key); - - private bool IsMatch(Notification n, string key) => - n.Key.Substring(0, 4) == key.Substring(0, 4) && n.Schedule != default; - - private void Alarm() - { - var now = _nowFunc(); - if (now - _lastAlarm < TimeSpan.FromSeconds(2)) - return; - var first = _queue.FirstOrDefault(n => n.Schedule.CompareTo(now) <= 0 && - !(n.Schedule != default && _suspend && n.Key != _suspendException)); - if (first == null) - return; - var message = _notificationConfig.GenerateMessage(first); - var similar = _queue.Where(n => - _notificationConfig.GenerateMessage(n).Name == message.Name && n.Schedule.CompareTo(now) <= 0) - .ToArray(); - var body = string.Join("\r\n", similar.Select(n => _notificationConfig.GenerateMessage(n).Body)); - foreach (var n in similar) - { - if (n.Repeat == 0) - { - _queue.Remove(n); - } - else - { - n.Schedule = now + TimeSpan.FromSeconds(n.Repeat); - if (n.Mode == Mode.Normal) - n.Mode = Mode.Repeat; - } - } - _alarm(message.Title, body, message.Name); - _lastAlarm = now; - } - - private class NotificationConfig - { - public class Message - { - public string Title { get; set; } - public string Body { get; set; } - public string Name { get; set; } - } - - private readonly Dictionary _config = new Dictionary(); - - private readonly Dictionary _default = new Dictionary - { - { - "遠征終了", new Message - { - Title = "遠征が終わりました", - Body = "%f艦隊 %s" - } - }, - { - "入渠終了", new Message - { - Title = "入渠が終わりました", - Body = "%fドック %s" - } - }, - { - "建造完了", new Message - { - Title = "建造が終わりました", - Body = "%fドック" - } - }, - { - "艦娘数超過", new Message - { - Title = "艦娘が多すぎます", - Body = "%s" - } - }, - { - "装備数超過", new Message - { - Title = "装備が多すぎます", - Body = "%s" - } - }, - { - "大破警告", new Message - { - Title = "大破した艦娘がいます", - Body = "%s" - } - }, - { - "泊地修理20分経過", new Message - { - Title = "泊地修理 %f艦隊", - Body = "20分経過しました。" - } - }, - { - "泊地修理進行", new Message - { - Title = "泊地修理 %f艦隊", - Body = "修理進行:%s" - } - }, - { - "泊地修理完了", new Message - { - Title = "泊地修理 %f艦隊", - Body = "修理完了:%s" - } - }, - { - "疲労回復40", new Message - { - Title = "疲労が回復しました", - Body = "%f艦隊 残り9分" - } - }, - { - "疲労回復49", new Message - { - Title = "疲労が回復しました", - Body = "%f艦隊" - } - }, - { - "任務達成", new Message - { - Title = "任務を達成しました", - Body = "%s" - } - } - }; - - public static string KeyToName(string key) => key.StartsWith("疲労回復") ? key.Substring(0, 4) : key; - - private void LoadConfig() - { - const string fileName = "notification.json"; - _config.Clear(); - try - { - dynamic config = JsonObject.Parse(File.ReadAllText(fileName)); - foreach (var entry in config) - { - if (!_default.ContainsKey(entry.key)) - continue; - _config[entry.key] = new Message - { - Title = entry.title, - Body = entry.body - }; - } - } - catch (FileNotFoundException) - { - } - catch (Exception ex) - { - throw new Exception($"{fileName}に誤りがあります。: ${ex.Message}", ex); - } - } - - public Message GenerateMessage(Notification notification) - { - LoadConfig(); - var format = _config.TryGetValue(notification.Key, out Message value) - ? value - : _default[notification.Key]; - var prefix = new[] {"", "[リピート] ", "[継続] ", "[予告] "}[(int)notification.Mode]; - return new Message - { - Title = prefix + ProcessFormatString(format.Title, notification.Fleet, notification.Subject), - Body = ProcessFormatString(format.Body, notification.Fleet, notification.Subject), - Name = KeyToName(notification.Key) - }; - } - - private string ProcessFormatString(string format, int fleet, string subject) - { - var fn = new[] {"第一", "第二", "第三", "第四"}; - var result = ""; - var percent = false; - foreach (var ch in format) - { - if (ch == '%') - { - if (percent) - { - percent = false; - result += '%'; - } - else - { - percent = true; - } - } - else if (percent) - { - percent = false; - switch (ch) - { - case 'f': - result += fn[fleet]; - break; - case 's': - result += subject; - break; - default: - result += '%'.ToString() + ch; - break; - } - } - else - { - result += ch; - } - } - return result; - } - } - } -} \ No newline at end of file -- 2.11.0