Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
NotificationBuilder.cs
1using System;
3using Waher.Events;
6
8{
13 {
14 private readonly NotificationMessage message;
15 private readonly NotificationOptions options;
16 private Dictionary<string, object> data;
17 private readonly ClientType clientType;
18
24 {
25 this.clientType = ClientType;
26 this.options = new NotificationOptions();
27 this.message = ClientType switch
28 {
29 ClientType.Android => new NotificationMessageAndroid(),
30 ClientType.iOS => new NotificationMessageApple(),
31 ClientType.Web => new NotificationMessageWeb(),
32 _ => new NotificationMessage()
33 };
34 }
35
40 {
41 if (Payload is null)
42 return this;
43
44 bool SilentDelivery = Payload.Delivery?.Silent ?? false;
45
46 if (!(Payload.Visual is null))
47 {
48 if (!SilentDelivery && !string.IsNullOrEmpty(Payload.Visual.Title))
49 this.message.Title = Payload.Visual.Title;
50
51 if (!SilentDelivery && !string.IsNullOrEmpty(Payload.Visual.Body))
52 this.message.Body = Payload.Visual.Body;
53
54 if (!string.IsNullOrEmpty(Payload.Visual.Subtitle))
55 {
56 if (this.message is NotificationMessageApple Apple)
57 Apple.SubTitle = Payload.Visual.Subtitle;
58 }
59
60 if (!string.IsNullOrEmpty(Payload.Visual.Icon))
61 {
62 if (this.message is NotificationMessageAndroid Android)
63 Android.Icon = Payload.Visual.Icon;
64 else if (this.message is NotificationMessageWeb Web)
65 Web.Icon = Payload.Visual.Icon;
66 }
67
68 if (!string.IsNullOrEmpty(Payload.Visual.Badge) && this.message is NotificationMessageApple AppleBadge)
69 AppleBadge.Badge = Payload.Visual.Badge;
70 }
71
72 if (!(Payload.Action is null))
73 {
74 if (!SilentDelivery && !string.IsNullOrEmpty(Payload.Action.NavigationTarget))
75 {
76 this.message.ClickAction = Payload.Action.NavigationTarget;
77
78 if (this.message is NotificationMessageWeb Web)
79 Web.Link = Payload.Action.NavigationTarget;
80 }
81
82 this.AddData("actionType", Payload.Action.Type);
83 this.AddData("entityId", Payload.Action.EntityId);
84 this.AddData("correlationId", Payload.Action.CorrelationId);
85 this.AddData("navigationTarget", Payload.Action.NavigationTarget);
86 }
87
88 if (!(Payload.Channel is null))
89 {
90 if (!string.IsNullOrEmpty(Payload.Channel.ChannelId) && this.message is NotificationMessageAndroid Android)
91 Android.ChannelId = Payload.Channel.ChannelId;
92
93 this.AddData("channelId", Payload.Channel.ChannelId);
94 this.AddData("category", Payload.Channel.Category);
95 this.AddData("importance", Payload.Channel.Importance);
96 if (!(Payload.Channel.Tags is null))
97 this.AddData("tags", Payload.Channel.Tags);
98 }
99
100 if (!(Payload.Context is null))
101 {
102 foreach (KeyValuePair<string, object> P in Payload.Context)
103 this.AddData(P.Key, P.Value);
104 }
105
106 if (!(Payload.CustomData is null))
107 {
108 foreach (KeyValuePair<string, object> P in Payload.CustomData)
109 this.AddData(P.Key, P.Value);
110 }
111
112 if (!(Payload.Delivery is null))
113 {
114 if (!string.IsNullOrEmpty(Payload.Delivery.Priority) &&
115 Enum.TryParse(Payload.Delivery.Priority, true, out NotificationPriority Priority))
116 {
117 this.message.Priority = Priority;
118 }
119
120 if (Payload.Delivery.Ttl.HasValue)
121 this.message.TimeToLive = Payload.Delivery.Ttl.Value;
122
123 if (!string.IsNullOrEmpty(Payload.Delivery.CollapseKey))
124 this.options.CollapseKey = Payload.Delivery.CollapseKey;
125
126 if (Payload.Delivery.Silent)
127 {
128 this.message.SuppressNotification = true;
129 this.message.Priority = NotificationPriority.Normal;
130
131 switch (this.message)
132 {
133 case NotificationMessageApple Apple:
134 Apple.ContentAvailable = true;
135 break;
136 }
137 }
138 }
139
140 if (!(Payload.PlatformOverrides is null) &&
141 Payload.PlatformOverrides.TryGetValue(this.clientType, out Dictionary<string, object> Overrides))
142 {
143 foreach (KeyValuePair<string, object> P in Overrides)
144 this.ApplyOverrideProperty(P.Key, P.Value);
145 }
146
147 return this;
148 }
149
153 public (NotificationMessage message, NotificationOptions options, Dictionary<string, object> data) Build()
154 {
155 this.ValidateNotification();
156 return (this.message, this.options, this.data);
157 }
158
162 private void ValidateNotification()
163 {
164 switch (this.clientType)
165 {
166 case ClientType.Android:
167 this.ValidateAndroid();
168 break;
169
170 case ClientType.iOS:
171 this.ValidateApple();
172 break;
173
174 case ClientType.Web:
175 case ClientType.Other:
176 default:
177 break;
178 }
179 }
180
181 private void ValidateAndroid()
182 {
183 if (!(this.message is NotificationMessageAndroid Android))
184 return;
185
186 // Validate Android-specific requirements
187 if (string.IsNullOrEmpty(Android.ChannelId))
188 Android.ChannelId = "default"; // Ensure default channel
189 }
190
191 private void ValidateApple()
192 {
193 if (!(this.message is NotificationMessageApple Apple))
194 return;
195
196 // For iOS, either alert (title/body) or content-available must be set
197 if (string.IsNullOrEmpty(Apple.Title) &&
198 string.IsNullOrEmpty(Apple.Body) &&
199 !Apple.ContentAvailable)
200 {
201 Apple.ContentAvailable = true;
202 }
203 }
204
205 private void AddData(string Key, object Value)
206 {
207 if (string.IsNullOrEmpty(Key) || Value is null)
208 return;
209
210 this.data ??= new Dictionary<string, object>();
211 this.data[Key] = Value;
212 }
213
214 private void ApplyOverrideProperty(string Key, object Value)
215 {
216 // Try options first (transport-level settings)
217 bool Handled = this.options.TrySetProperty(Key, Value);
218
219 // Try message second (platform-specific settings)
220 Handled = this.message.TrySetProperty(Key, Value) || Handled;
221
222 // Add to data if not handled (custom data)
223 if (Key == "data" && Value is Dictionary<string, object> DataItems)
224 {
225 foreach (KeyValuePair<string, object> Item in DataItems)
226 this.AddData(Item.Key, Item.Value);
227 }
228 else if (!Handled)
229 this.AddData(Key, Value);
230 }
231 }
232}
Builds Firebase Cloud Messaging notifications with platform-specific validation
NotificationBuilder ApplyPayload(PushNotificationPayload Payload)
Apply a transport-agnostic push payload to the underlying message/options/data.
NotificationMessage message
Build the notification components for sending
NotificationBuilder(ClientType ClientType)
Constructor
string Type
Action type identifier (e.g. OpenChat, OpenContract).
string[] Tags
Tags to help clients route notifications locally.
Transport-agnostic push notification payload describing notification intent.
PushChannel Channel
Client-side channel/category information.
Dictionary< string, object > Context
Arbitrary context metadata.
Dictionary< string, object > CustomData
Additional custom data to include in the notification payload.
PushDelivery Delivery
Delivery characteristics (priority, TTL, collapse key, silent).
PushAction Action
Action to execute when the notification is acted on.
Dictionary< ClientType, Dictionary< string, object > > PlatformOverrides
Platform-specific override fragments keyed by client type.
Definition: ImplTypes.g.cs:58
NotificationPriority
Notification priority
ClientType
Type of client requesting notification.
Definition: ClientType.cs:7