Toasts – Blame information for rev 53

Subversion Repositories:
Rev:
Rev Author Line No. Line
41 office 1 using System;
2 using System.Collections.Concurrent;
44 office 3 using System.ComponentModel;
53 office 4 using System.Diagnostics;
41 office 5 using System.Drawing;
44 office 6 using System.Runtime.InteropServices;
41 office 7 using System.Threading;
8 using System.Threading.Tasks;
9 using System.Threading.Tasks.Dataflow;
10 using System.Windows.Forms;
11 using Markdig;
12 using Markdig.Renderers;
13  
14 namespace Toasts
15 {
44 office 16 public class ToastDisplay : IDisposable
17 {
18 private readonly CancellationToken _cancellationToken;
19 private readonly BufferBlock<ToastDisplayData> _toastFormBufferBlock;
20 private ConcurrentBag<IDisposable> tplDataflowLinks;
21 private readonly TransformBlock<ToastDisplayData, ToastDisplayData> _toastBodyTransformBlock;
22 private readonly ActionBlock<ToastDisplayData> _toastFormActionBlock;
23  
24 private ToastDisplay()
25 {
26 tplDataflowLinks = new ConcurrentBag<IDisposable>();
27 }
28  
29 public ToastDisplay(CancellationToken cancellationToken) : this()
30 {
31 _cancellationToken = cancellationToken;
32  
33 _toastFormBufferBlock = new BufferBlock<ToastDisplayData>(new DataflowBlockOptions { CancellationToken = _cancellationToken });
34 _toastBodyTransformBlock = new TransformBlock<ToastDisplayData, ToastDisplayData>(ToastBodyToHTML,
35 new ExecutionDataflowBlockOptions { CancellationToken = _cancellationToken });
36 _toastFormActionBlock = new ActionBlock<ToastDisplayData>(DisplayForm, new ExecutionDataflowBlockOptions { CancellationToken = _cancellationToken });
37  
38 tplDataflowLinks.Add(_toastFormBufferBlock.LinkTo(_toastBodyTransformBlock, new DataflowLinkOptions { PropagateCompletion = true }));
39 tplDataflowLinks.Add(_toastBodyTransformBlock.LinkTo(DataflowBlock.NullTarget<ToastDisplayData>(), new DataflowLinkOptions { PropagateCompletion = true }, result => result == null));
40 tplDataflowLinks.Add(_toastBodyTransformBlock.LinkTo(_toastFormActionBlock, new DataflowLinkOptions { PropagateCompletion = true }));
41 }
42  
43 private ToastDisplayData ToastBodyToHTML(ToastDisplayData toastDisplayData)
44 {
45 switch (toastDisplayData.Content)
46 {
47 case "text/markdown":
46 office 48 var pipeline = new MarkdownPipelineBuilder().UsePipeTables().Build();
49 var html = Markdown.ToHtml(toastDisplayData.Body, pipeline);
50 toastDisplayData.Body = html;
44 office 51 break;
52 }
53  
54 return toastDisplayData;
55 }
56  
57 public void Dispose()
58 {
59 while (tplDataflowLinks.TryTake(out var disposable))
60 {
61 disposable.Dispose();
62 }
63 }
64  
65 private static void DisplayForm(ToastDisplayData toastPayload)
66 {
67 var thread = new Thread(() =>
68 {
69 try
70 {
71 var toastForm = new ToastForm(toastPayload.Title, toastPayload.Body)
72 {
73 EnableChime = toastPayload.EnableChime,
74 Chime = toastPayload.Chime ?? toastPayload.Chime,
75 LingerTime = toastPayload.LingerTime,
76 Image = toastPayload.Image,
77 ContentType = toastPayload.Content,
78 EnablePin = toastPayload.EnablePin,
49 office 79 PinPoint = toastPayload.PinPoint,
80 UserAgent = toastPayload.UserAgent
44 office 81 };
82  
83 var formClosingEvent = new ManualResetEvent(false);
84 void OnFormClosing(object sender, EventArgs args)
85 {
86 toastForm.FormClosing -= OnFormClosing;
87 formClosingEvent.Set();
88 }
89 toastForm.FormClosing += OnFormClosing;
90  
91 Application.Run(toastForm);
92  
93 var timeout = toastPayload.EnablePin ? -1 : toastPayload.LingerTime;
94 formClosingEvent.WaitOne(timeout);
95 toastForm.FormClosing -= OnFormClosing;
96 toastForm.Close();
97 if (!toastForm.IsDisposed)
98 {
99 toastForm.Dispose();
100 }
101 toastForm = null;
102 formClosingEvent.Dispose();
103 formClosingEvent = null;
104 }
105 catch (Win32Exception)
106 {
107 // ignore window creation errors for now
108 }
109 catch (COMException)
110 {
111 // ignore window creation errors for now
112 }
51 office 113 catch(InvalidOperationException)
114 {
115 // animation clutter
116 }
53 office 117 catch (ArgumentException)
118 {
119 // animation clutter
120 }
121 catch(Exception exception)
122 {
123 Debug.WriteLine(exception);
124 }
44 office 125 })
126 {
127 IsBackground = true
128 };
129 thread.SetApartmentState(ApartmentState.STA);
130 thread.Start();
131 }
132  
133 public async Task Queue(ToastDisplayData toastPayload)
134 {
135 await _toastFormBufferBlock.SendAsync(toastPayload, _cancellationToken);
136 }
41 office 137 }
27 office 138 }