{\r
private class MockTimer : NotificationManager.ITimer\r
{\r
- private int _elapsed;\r
+ private int _elapsed, _totalElapsed;\r
private bool _enabled;\r
+ private DateTime _start = new DateTime(2017, 11, 1);\r
+ private DateTime _now;\r
+\r
+ public MockTimer()\r
+ {\r
+ _now = _start;\r
+ }\r
\r
public int Interval { get; set; }\r
\r
set\r
{\r
_enabled = value;\r
+ _start += TimeSpan.FromMilliseconds(_elapsed);\r
_elapsed = 0;\r
}\r
}\r
Enabled = false;\r
}\r
\r
+ public DateTime Now => _now;\r
+\r
+ public int Elapsed => _totalElapsed;\r
+\r
public void ElapseTime(int millis)\r
{\r
+ _totalElapsed += millis;\r
if (!Enabled)\r
+ {\r
+ _now = _start += TimeSpan.FromMilliseconds(millis);\r
return;\r
+ }\r
var after = _elapsed + millis;\r
for (var n = _elapsed / Interval; n < after / Interval; n++)\r
{\r
+ _now = _start + TimeSpan.FromMilliseconds((n + 1) * Interval);\r
Tick?.Invoke(this, EventArgs.Empty);\r
}\r
_elapsed = after;\r
+ _now = _start + TimeSpan.FromMilliseconds(_elapsed);\r
}\r
}\r
\r
timer.ElapseTime(1000);\r
PAssert.That(() => new Message {Title = "建造が終わりました", Body = "第二ドック", Name = "建造完了"}.Equals(result));\r
}\r
+\r
+ /// <summary>\r
+ /// 通知をリピートさせる\r
+ /// </summary>\r
+ [TestMethod]\r
+ public void SingleRepeatableNotification()\r
+ {\r
+ var timer = new MockTimer();\r
+ Message result = null;\r
+ var manager =\r
+ new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, timer);\r
+ var expected = new Message {Title = "遠征が終わりました", Body = "防空射撃演習", Name = "遠征終了"};\r
+ while (true)\r
+ {\r
+ switch (timer.Elapsed)\r
+ {\r
+ case 0:\r
+ manager.Enqueue("遠征終了", "防空射撃演習", 2);\r
+ PAssert.That(() => expected.Equals(result));\r
+ break;\r
+ case 2000:\r
+ PAssert.That(() => expected.Equals(result));\r
+ break;\r
+ case 4000:\r
+ PAssert.That(() => expected.Equals(result));\r
+ return;\r
+ default:\r
+ PAssert.That(() => result == null, timer.Elapsed.ToString());\r
+ break;\r
+ }\r
+ result = null;\r
+ timer.ElapseTime(1000);\r
+ }\r
+ }\r
+\r
+ /// <summary>\r
+ /// 二つの通知をリピートさせる\r
+ /// </summary>\r
+ [TestMethod]\r
+ public void TwoRepeatableNotofication()\r
+ {\r
+ var timer = new MockTimer();\r
+ Message result = null;\r
+ var manager =\r
+ new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, timer);\r
+ var ensei = new Message {Title = "遠征が終わりました", Body = "防空射撃演習", Name = "遠征終了"};\r
+ var hakuchi = new Message {Title = "泊地修理 第一艦隊", Body = "20分経過しました。", Name = "泊地修理20分経過"};\r
+ while (true)\r
+ {\r
+ switch (timer.Elapsed)\r
+ {\r
+ case 0:\r
+ manager.Enqueue("遠征終了", "防空射撃演習", 10);\r
+ PAssert.That(() => ensei.Equals(result));\r
+ break;\r
+ case 2000:\r
+ manager.Enqueue("泊地修理20分経過", 0, "", 5);\r
+ PAssert.That(() => hakuchi.Equals(result));\r
+ break;\r
+ case 7000:\r
+ PAssert.That(() => hakuchi.Equals(result), "泊地修理2回目");\r
+ break;\r
+ case 10000:\r
+ PAssert.That(() => ensei.Equals(result), "遠征終了2回目");\r
+ return;\r
+ default:\r
+ PAssert.That(() => result == null, timer.Elapsed.ToString());\r
+ break;\r
+ }\r
+ result = null;\r
+ timer.ElapseTime(1000);\r
+ }\r
+ }\r
+\r
+ /// <summary>\r
+ /// スケジュールがぶつかる二つの通知をリピートさせる\r
+ /// </summary>\r
+ [TestMethod]\r
+ public void TwoRepeatableNotification1SecDelay()\r
+ {\r
+ var timer = new MockTimer();\r
+ Message result = null;\r
+ var manager =\r
+ new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, timer);\r
+ var ensei = new Message {Title = "遠征が終わりました", Body = "防空射撃演習", Name = "遠征終了"};\r
+ var hakuchi = new Message {Title = "泊地修理 第一艦隊", Body = "20分経過しました。", Name = "泊地修理20分経過"};\r
+ while (true)\r
+ {\r
+ switch (timer.Elapsed)\r
+ {\r
+ case 0:\r
+ manager.Enqueue("遠征終了", "防空射撃演習", 3);\r
+ PAssert.That(() => ensei.Equals(result));\r
+ break;\r
+ case 1000:\r
+ manager.Enqueue("泊地修理20分経過", 0, "", 2);\r
+ break;\r
+ case 2000:\r
+ PAssert.That(() => hakuchi.Equals(result));\r
+ break;\r
+ case 4000:\r
+ PAssert.That(() => ensei.Equals(result), "遠征終了2回目");\r
+ break;\r
+ case 6000:\r
+ PAssert.That(() => hakuchi.Equals(result), "泊地修理2回目");\r
+ return;\r
+ default:\r
+ PAssert.That(() => result == null, timer.Elapsed.ToString());\r
+ break;\r
+ }\r
+ result = null;\r
+ timer.ElapseTime(1000);\r
+ }\r
+ }\r
+\r
+ /// <summary>\r
+ /// リピートしている通知を止める\r
+ /// </summary>\r
+ [TestMethod]\r
+ public void RemoveRepeatableNotification()\r
+ {\r
+ var timer = new MockTimer();\r
+ Message result = null;\r
+ var manager =\r
+ new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, timer);\r
+ var ensei = new Message {Title = "遠征が終わりました", Body = "防空射撃演習", Name = "遠征終了"};\r
+ var hakuchi = new Message {Title = "入渠が終わりました", Body = "綾波改二", Name = "入渠終了"};\r
+ while (true)\r
+ {\r
+ switch (timer.Elapsed)\r
+ {\r
+ case 0:\r
+ manager.Enqueue("遠征終了", "防空射撃演習", 10);\r
+ PAssert.That(() => ensei.Equals(result));\r
+ break;\r
+ case 2000:\r
+ manager.Enqueue("入渠終了", "綾波改二", 5);\r
+ PAssert.That(() => hakuchi.Equals(result));\r
+ break;\r
+ case 3000:\r
+ manager.StopRepeat("入渠終了");\r
+ break;\r
+ case 7000:\r
+ PAssert.That(() => result == null, "入渠終了2回目はない");\r
+ break;\r
+ case 10000:\r
+ PAssert.That(() => ensei.Equals(result), "遠征終了2回目");\r
+ return;\r
+ default:\r
+ PAssert.That(() => result == null, timer.Elapsed.ToString());\r
+ break;\r
+ }\r
+ result = null;\r
+ timer.ElapseTime(1000);\r
+ }\r
+ }\r
}\r
}
\ No newline at end of file
using System;\r
using System.Collections.Generic;\r
using System.IO;\r
+using System.Linq;\r
using System.Windows.Forms;\r
\r
namespace KancolleSniffer\r
public string Key { get; set; }\r
public int Fleet { get; set; }\r
public string Subject { get; set; }\r
+ public int Repeat { get; set; }\r
+ public DateTime Schedule { get; set; }\r
}\r
\r
public NotificationManager(Action<string, string, string> ring, ITimer timer = null)\r
{\r
-\r
_notificationQueue = new NotificationQueue(ring, timer);\r
}\r
\r
- public void Enqueue(string key, int fleet, string subject)\r
+ public void Enqueue(string key, int fleet, string subject, int repeat = 0)\r
{\r
_notificationQueue.Enqueue(new Notification\r
{\r
Key = key,\r
Fleet = fleet,\r
- Subject = subject\r
+ Subject = subject,\r
+ Repeat = repeat\r
});\r
}\r
\r
- public void Enqueue(string key, string subject)\r
+ public void Enqueue(string key, string subject, int repeat = 0)\r
{\r
- Enqueue(key, 0, subject);\r
+ Enqueue(key, 0, subject, repeat);\r
+ }\r
+\r
+ public void StopRepeat(string key)\r
+ {\r
+ _notificationQueue.StopRepeat(key);\r
}\r
\r
private class NotificationConfig\r
event EventHandler Tick;\r
void Start();\r
void Stop();\r
+ DateTime Now { get; }\r
}\r
\r
public class TimerWrapper : ITimer\r
public void Start() => _timer.Start();\r
\r
public void Stop() => _timer.Stop();\r
+\r
+ public DateTime Now => DateTime.Now;\r
}\r
\r
private class NotificationQueue\r
{\r
private readonly Action<string, string, string> _ring;\r
- private readonly Queue<Notification> _queue = new Queue<Notification>();\r
+ private readonly List<Notification> _queue = new List<Notification>();\r
private readonly ITimer _timer;\r
private readonly NotificationConfig _notificationConfig = new NotificationConfig();\r
+ private DateTime _lastRing;\r
\r
- public NotificationQueue(Action<string, string, string> ring, ITimer timer)\r
+ public NotificationQueue(Action<string, string, string> ring, ITimer timer = null)\r
{\r
_ring = ring;\r
_timer = timer ?? new TimerWrapper();\r
- _timer.Interval = 2000;\r
+ _timer.Interval = 1000;\r
_timer.Tick += TimerOnTick;\r
}\r
\r
_timer.Stop();\r
return;\r
}\r
- var notification = _queue.Dequeue();\r
- Ring(notification);\r
+ Ring();\r
}\r
\r
public void Enqueue(Notification notification)\r
{\r
- if (_timer.Enabled)\r
+ _queue.Add(notification);\r
+ Ring();\r
+ if (_queue.Count > 0)\r
+ _timer.Start();\r
+ }\r
+\r
+ public void StopRepeat(string key)\r
+ {\r
+ _queue.RemoveAll(n => n.Key.Substring(0, 4) == key.Substring(0, 4) && n.Schedule != default);\r
+ }\r
+\r
+ private void Ring()\r
+ {\r
+ var now = _timer.Now;\r
+ if (now - _lastRing < TimeSpan.FromSeconds(2))\r
+ return;\r
+ var notification = _queue.FirstOrDefault(n => n.Schedule.CompareTo(now) <= 0);\r
+ if (notification == null)\r
+ return;\r
+ if (notification.Repeat == 0)\r
{\r
- _queue.Enqueue(notification);\r
+ _queue.Remove(notification);\r
}\r
else\r
{\r
- Ring(notification);\r
- _timer.Start();\r
+ notification.Schedule = _timer.Now + TimeSpan.FromSeconds(notification.Repeat);\r
}\r
- }\r
-\r
- private void Ring(Notification notification)\r
- {\r
var message =\r
_notificationConfig.GenerateMessage(notification);\r
_ring(message.Title, message.Body, message.Name);\r
+ _lastRing = now;\r
}\r
}\r
}\r