Got simple toast notifications going

This commit is contained in:
Daniel Schick 2024-12-19 12:59:54 +01:00
parent f218e5f96a
commit 880a8a2a8d
8 changed files with 415 additions and 47 deletions

View File

@ -1,8 +1,8 @@
//----------------------
// <auto-generated>
// Generated REST API Client Code Generator v1.16.0.0 on 10.12.2024 08:56:03
// Using the tool OpenAPI Generator v7.9.0
// Generated REST API Client Code Generator v1.17.0.0 on 19.12.2024 11:34:56
// Using the tool OpenAPI Generator v7.10.0
// </auto-generated>
//----------------------
@ -3829,7 +3829,7 @@ namespace BreCalClient.misc.Client
if (response.Headers != null)
{
var filePath = string.IsNullOrEmpty(_configuration.TempFolderPath)
? Path.GetTempPath()
? global::System.IO.Path.GetTempPath()
: _configuration.TempFolderPath;
var regex = new Regex(@"Content-Disposition=.*filename=['""]?([^'""\s]+)['""]?$");
foreach (var header in response.Headers)
@ -4069,7 +4069,7 @@ namespace BreCalClient.misc.Client
var bytes = ClientUtils.ReadAsBytes(file);
var fileStream = file as FileStream;
if (fileStream != null)
request.AddFile(fileParam.Key, bytes, Path.GetFileName(fileStream.Name));
request.AddFile(fileParam.Key, bytes, global::System.IO.Path.GetFileName(fileStream.Name));
else
request.AddFile(fileParam.Key, bytes, "no_file_name_provided");
}
@ -4139,7 +4139,7 @@ namespace BreCalClient.misc.Client
var clientOptions = new RestClientOptions(baseUrl)
{
ClientCertificates = configuration.ClientCertificates,
MaxTimeout = configuration.Timeout,
Timeout = configuration.Timeout,
Proxy = configuration.Proxy,
UserAgent = configuration.UserAgent,
UseDefaultCredentials = configuration.UseDefaultCredentials,
@ -4209,11 +4209,11 @@ namespace BreCalClient.misc.Client
return result;
}
}
private RestResponse<T> DeserializeRestResponseFromPolicy<T>(RestClient client, RestRequest request, PolicyResult<RestResponse> policyResult)
private async Task<RestResponse<T>> DeserializeRestResponseFromPolicyAsync<T>(RestClient client, RestRequest request, PolicyResult<RestResponse> policyResult, CancellationToken cancellationToken = default)
{
if (policyResult.Outcome == OutcomeType.Successful)
{
return client.Deserialize<T>(policyResult.Result);
return await client.Deserialize<T>(policyResult.Result, cancellationToken);
}
else
{
@ -4243,7 +4243,7 @@ namespace BreCalClient.misc.Client
{
var policy = RetryConfiguration.RetryPolicy;
var policyResult = policy.ExecuteAndCapture(() => client.Execute(request));
return Task.FromResult(DeserializeRestResponseFromPolicy<T>(client, request, policyResult));
return DeserializeRestResponseFromPolicyAsync<T>(client, request, policyResult);
}
else
{
@ -4264,7 +4264,7 @@ namespace BreCalClient.misc.Client
{
var policy = RetryConfiguration.AsyncRetryPolicy;
var policyResult = await policy.ExecuteAndCaptureAsync((ct) => client.ExecuteAsync(request, ct), cancellationToken).ConfigureAwait(false);
return DeserializeRestResponseFromPolicy<T>(client, request, policyResult);
return await DeserializeRestResponseFromPolicyAsync<T>(client, request, policyResult, cancellationToken);
}
else
{
@ -5000,7 +5000,7 @@ namespace BreCalClient.misc.Client
{
};
// Setting Timeout has side effects (forces ApiClient creation).
Timeout = 100000;
Timeout = TimeSpan.FromSeconds(100);
}
/// <summary>
/// Initializes a new instance of the <see cref="Configuration" /> class
@ -5072,9 +5072,9 @@ namespace BreCalClient.misc.Client
/// </summary>
public virtual IDictionary<string, string> DefaultHeaders { get; set; }
/// <summary>
/// Gets or sets the HTTP timeout (milliseconds) of ApiClient. Default to 100000 milliseconds.
/// Gets or sets the HTTP timeout of ApiClient. Defaults to 100 seconds.
/// </summary>
public virtual int Timeout { get; set; }
public virtual TimeSpan Timeout { get; set; }
/// <summary>
/// Gets or sets the proxy
/// </summary>
@ -5713,10 +5713,10 @@ namespace BreCalClient.misc.Client
/// <value>Temp folder path.</value>
string TempFolderPath { get; }
/// <summary>
/// Gets the HTTP connection timeout (in milliseconds)
/// Gets the HTTP connection timeout.
/// </summary>
/// <value>HTTP connection timeout.</value>
int Timeout { get; }
TimeSpan Timeout { get; }
/// <summary>
/// Gets the proxy.
/// </summary>
@ -7097,24 +7097,26 @@ namespace BreCalClient.misc.Model
public partial class Notification : IValidatableObject
{
/// <summary>
/// Gets or Sets NotificationType
/// Gets or Sets Type
/// </summary>
[DataMember(Name = "notification_type", EmitDefaultValue = true)]
public NotificationType? NotificationType { get; set; }
[DataMember(Name = "type", EmitDefaultValue = true)]
public NotificationType? Type { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="Notification" /> class.
/// </summary>
/// <param name="id">id.</param>
/// <param name="shipcallId">shipcallId.</param>
/// <param name="notificationType">notificationType.</param>
/// <param name="participantId">participantId.</param>
/// <param name="type">type.</param>
/// <param name="message">message.</param>
/// <param name="created">Readonly field set by the database when notification was created.</param>
/// <param name="modified">Readonly field set by the database when notification was last modified.</param>
public Notification(int id = default(int), int shipcallId = default(int), NotificationType? notificationType = default(NotificationType?), string message = default(string), DateTime created = default(DateTime), DateTime? modified = default(DateTime?))
public Notification(int id = default(int), int shipcallId = default(int), int? participantId = default(int?), NotificationType? type = default(NotificationType?), string message = default(string), DateTime created = default(DateTime), DateTime? modified = default(DateTime?))
{
this.Id = id;
this.ShipcallId = shipcallId;
this.NotificationType = notificationType;
this.ParticipantId = participantId;
this.Type = type;
this.Message = message;
this.Created = created;
this.Modified = modified;
@ -7136,6 +7138,14 @@ namespace BreCalClient.misc.Model
[DataMember(Name = "shipcall_id", EmitDefaultValue = true)]
public int ShipcallId { get; set; }
/// <summary>
/// Gets or Sets ParticipantId
/// </summary>
/*
<example>9</example>
*/
[DataMember(Name = "participant_id", EmitDefaultValue = true)]
public int? ParticipantId { get; set; }
/// <summary>
/// Gets or Sets Message
/// </summary>
/*
@ -7171,7 +7181,8 @@ namespace BreCalClient.misc.Model
sb.Append("class Notification {\n");
sb.Append(" Id: ").Append(Id).Append("\n");
sb.Append(" ShipcallId: ").Append(ShipcallId).Append("\n");
sb.Append(" NotificationType: ").Append(NotificationType).Append("\n");
sb.Append(" ParticipantId: ").Append(ParticipantId).Append("\n");
sb.Append(" Type: ").Append(Type).Append("\n");
sb.Append(" Message: ").Append(Message).Append("\n");
sb.Append(" Created: ").Append(Created).Append("\n");
sb.Append(" Modified: ").Append(Modified).Append("\n");

View File

@ -1550,7 +1550,11 @@ components:
type: integer
example: 5
nullable: false
notification_type:
participant_id:
type: integer
example: 9
nullable: true
type:
$ref: '#/components/schemas/NotificationType'
message:
type: string
@ -1569,7 +1573,8 @@ components:
example:
id: 42
shipcall_id: 5
notification_type: next24h
participant_id: 9
type: next24h
message: Shipcall may be relevant to you in the next 24 hours
created: '2023-08-21T08:23:35Z'
modified: '2023-08-21T08:23:35Z'
@ -1581,13 +1586,14 @@ components:
example:
- id: 42
shipcall_id: 5
notification_type: time_conflict
participant_id: 9
type: time_conflict
message: Entry XY violates rule Z
created: '2023-08-21T08:23:35Z'
modified: '2023-08-21T08:23:35Z'
- id: 43
shipcall_id: 7
notification_type: time_conflict
type: time_conflict
message: Entry AB violates rule C
created: '2023-08-21T08:23:35Z'
modified: '2023-08-21T08:23:35Z'

View File

@ -3,6 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BreCalClient"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:options="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
StartupUri="MainWindow.xaml" Exit="Application_Exit" Startup="Application_Startup" >
<Application.Resources>
@ -14,6 +15,95 @@
<sys:Double x:Key="{x:Static SystemParameters.VerticalScrollBarWidthKey}">10</sys:Double>
<sys:Double x:Key="{x:Static SystemParameters.HorizontalScrollBarHeightKey}">10</sys:Double>
<Color x:Key="InformationColor">#147ec9</Color>
<SolidColorBrush x:Key="InformationColorBrush" Color="{StaticResource InformationColor}" options:Freeze="True" />
<Color x:Key="SuccessColor">#11ad45</Color>
<SolidColorBrush x:Key="SuccessColorBrush" Color="{StaticResource SuccessColor}" options:Freeze="True" />
<Color x:Key="ErrorColor">#e60914</Color>
<SolidColorBrush x:Key="ErrorColorBrush" Color="{StaticResource ErrorColor}" options:Freeze="True" />
<Color x:Key="WarningColor">#f5a300</Color>
<SolidColorBrush x:Key="WarningColorBrush" Color="{StaticResource WarningColor}" options:Freeze="True" />
<Canvas x:Key="InformationIcon" Width="24" Height="24">
<Path Data="M11,9H13V7H11M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M11,17H13V11H11V17Z" Fill="White" />
</Canvas>
<Canvas x:Key="SuccessIcon" Width="24" Height="24">
<Path Data="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z" Fill="White" />
</Canvas>
<Canvas x:Key="ErrorIcon" Width="24" Height="24">
<Path Data="M11,15H13V17H11V15M11,7H13V13H11V7M12,2C6.47,2 2,6.5 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4A8,8 0 0,1 20,12A8,8 0 0,1 12,20Z" Fill="White" />
</Canvas>
<Canvas x:Key="WarningIcon" Width="24" Height="24">
<Path Data="M12,2L1,21H23M12,6L19.53,19H4.47M11,10V14H13V10M11,16V18H13V16" Fill="White" />
</Canvas>
<Canvas x:Key="CloseIcon" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
<Path Width="31.6666" Height="31.6667" Canvas.Left="22.1666" Canvas.Top="22.1667" Stretch="Fill" Fill="#FF000000" Data="F1 M 26.9166,22.1667L 37.9999,33.25L 49.0832,22.1668L 53.8332,26.9168L 42.7499,38L 53.8332,49.0834L 49.0833,53.8334L 37.9999,42.75L 26.9166,53.8334L 22.1666,49.0833L 33.25,38L 22.1667,26.9167L 26.9166,22.1667 Z "/>
</Canvas>
<Style TargetType="Border" x:Key="NotificationBorder">
<Setter Property="Padding" Value="5" />
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect Opacity="0.5" ShadowDepth="1" BlurRadius="2" />
</Setter.Value>
</Setter>
</Style>
<Style TargetType="Rectangle" x:Key="NotificationIcon">
<Setter Property="Width" Value="24"/>
<Setter Property="Height" Value="24"/>
<Setter Property="Margin" Value="0,5,5,5" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Fill" Value="White"/>
</Style>
<Style TargetType="TextBlock" x:Key="NotificationText">
<Setter Property="Foreground" Value="White" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="TextWrapping" Value="Wrap" />
<Setter Property="Margin" Value="5,0,0,0" />
</Style>
<Style TargetType="{x:Type Button}" x:Key="NotificationCloseButton">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="#FFF" />
<Setter Property="FontSize" Value="15" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#33000000" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#77000000" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="Rectangle" x:Key="CloseButtonIcon">
<Setter Property="Width" Value="10"/>
<Setter Property="Height" Value="10"/>
<Setter Property="Fill" Value="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}" />
</Style>
</ResourceDictionary>
</Application.Resources>

View File

@ -0,0 +1,121 @@
// Copyright (c) 2024- schick Informatik
// Description: Helper (static) class to handle polled API notifications
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ToastNotifications.Core;
namespace BreCalClient
{
internal class AppNotification
{
private static Dictionary<int, AppNotification> _notifications = new ();
private readonly int _id;
public AppNotification(int id)
{
_id = id;
}
public int Id { get { return _id; } }
#region internal statics
internal static void LoadFromSettings()
{
_notifications.Clear();
// preload notifications that have been processed
foreach (string? notification_id in Properties.Settings.Default.Notifications)
{
if(Int32.TryParse(notification_id, out int result))
_notifications.Add(result, new AppNotification(result));
}
}
internal static void Clear()
{
_notifications.Clear();
SaveNotifications();
}
internal static bool UpdateNotifications(List<BreCalClient.misc.Model.Notification> notifications, System.Collections.Concurrent.ConcurrentDictionary<int, ShipcallControlModel> currentShipcalls, ToastViewModel vm)
{
bool result = false;
foreach (BreCalClient.misc.Model.Notification notification in notifications)
{
if(!_notifications.ContainsKey(notification.Id))
{
_notifications.Add(notification.Id, new AppNotification(notification.Id));
// filter if the notification concerns us
if(notification.ParticipantId != null)
{
if(App.Participant.Id == notification.ParticipantId)
{
result = true;
}
}
else
{
// find out if this notification concerns us
if(currentShipcalls.ContainsKey(notification.ShipcallId))
{
result = true;
}
}
if(result)
{
System.Diagnostics.Trace.WriteLine($"Notification {notification.Id} Type {notification.Type}");
MessageOptions options = new MessageOptions();
options.FontSize = 14;
options.ShowCloseButton = true;
switch(notification.Type)
{
case misc.Model.NotificationType.TimeConflict:
break;
case misc.Model.NotificationType.TimeConflictResolved:
break;
case misc.Model.NotificationType.Assignment:
break;
case misc.Model.NotificationType.Next24h:
break;
case misc.Model.NotificationType.Unassigned:
break;
}
string toastText = $"{currentShipcalls[notification.ShipcallId]?.Ship?.Name} ({currentShipcalls[notification.ShipcallId]?.Shipcall?.Type}) - {currentShipcalls[notification.ShipcallId]?.GetETAETD(true)} - {currentShipcalls[notification.ShipcallId]?.GetBerthText(null)}";
App.Current.Dispatcher.Invoke(() =>
{
vm.ShowInformation(toastText, options);
});
}
}
}
return result;
}
internal static void SaveNotifications()
{
Properties.Settings.Default.Notifications.Clear();
foreach (int notification_id in _notifications.Keys)
{
Properties.Settings.Default.Notifications.Add(notification_id.ToString());
}
}
#endregion
}
}

View File

@ -36,8 +36,11 @@ namespace BreCalClient
public partial class MainWindow : Window
{
private readonly ILog _log = LogManager.GetLogger(typeof(MainWindow));
private readonly ToastViewModel _vm;
private const int SHIPCALL_UPDATE_INTERVAL_SECONDS = 30;
private const int SHIPS_UPDATE_INTERVAL_SECONDS = 120;
private const int CHECK_NOTIFICATIONS_INTERVAL_SECONDS = 5;
private const int PROGRESS_STEPS = 50;
#region Fields
@ -122,6 +125,13 @@ namespace BreCalClient
RetryConfiguration.AsyncRetryPolicy = retryPolicy;
this.generalProgressStatus.Maximum = PROGRESS_STEPS;
_vm = new ToastViewModel();
this.Unloaded += MainWindow_Unloaded;
}
private void MainWindow_Unloaded(object sender, RoutedEventArgs e)
{
_vm.OnUnloaded();
}
#endregion
@ -510,6 +520,7 @@ namespace BreCalClient
_ = Task.Run(() => RefreshShipcalls());
_ = Task.Run(() => RefreshShips());
_ = Task.Run(() => CheckNotifications());
}
@ -633,6 +644,16 @@ namespace BreCalClient
}
}
public async Task CheckNotifications()
{
while (true)
{
Thread.Sleep(CHECK_NOTIFICATIONS_INTERVAL_SECONDS * 1000);
List<Notification> notifications = await _staticApi.NotificationsGetAsync();
AppNotification.UpdateNotifications(notifications, _allShipcallsDict, _vm);
}
}
#endregion
#region basic operations

View File

@ -9,20 +9,20 @@
//------------------------------------------------------------------------------
namespace BreCalClient.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.10.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("#1D751F")]
@ -31,7 +31,7 @@ namespace BreCalClient.Properties {
return ((string)(this["BG_COLOR"]));
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("!!Bremen calling Testversion!!")]
@ -40,7 +40,7 @@ namespace BreCalClient.Properties {
return ((string)(this["APP_TITLE"]));
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("https://www.textbausteine.net/")]
@ -49,7 +49,7 @@ namespace BreCalClient.Properties {
return ((string)(this["LOGO_IMAGE_URL"]));
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
@ -61,7 +61,7 @@ namespace BreCalClient.Properties {
this["FilterCriteria"] = value;
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("https://brecaldevel.bsmd-emswe.eu")]
@ -70,7 +70,7 @@ namespace BreCalClient.Properties {
return ((string)(this["API_URL"]));
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("800")]
@ -82,7 +82,7 @@ namespace BreCalClient.Properties {
this["Width"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("450")]
@ -94,7 +94,7 @@ namespace BreCalClient.Properties {
this["Height"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
@ -106,7 +106,7 @@ namespace BreCalClient.Properties {
this["Left"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
@ -118,7 +118,7 @@ namespace BreCalClient.Properties {
this["Top"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
@ -130,7 +130,7 @@ namespace BreCalClient.Properties {
this["W1Left"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
@ -142,7 +142,7 @@ namespace BreCalClient.Properties {
this["W1Top"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
@ -154,7 +154,7 @@ namespace BreCalClient.Properties {
this["W2Left"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
@ -166,7 +166,7 @@ namespace BreCalClient.Properties {
this["W2Top"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
@ -178,7 +178,7 @@ namespace BreCalClient.Properties {
this["W3Left"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
@ -190,7 +190,7 @@ namespace BreCalClient.Properties {
this["W3Top"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
@ -202,7 +202,7 @@ namespace BreCalClient.Properties {
this["W4Left"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
@ -214,7 +214,7 @@ namespace BreCalClient.Properties {
this["W4Top"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
@ -226,5 +226,16 @@ namespace BreCalClient.Properties {
this["FilterCriteriaMap"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public global::System.Collections.Specialized.StringCollection Notifications {
get {
return ((global::System.Collections.Specialized.StringCollection)(this["Notifications"]));
}
set {
this["Notifications"] = value;
}
}
}
}

View File

@ -56,5 +56,8 @@
<Setting Name="FilterCriteriaMap" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="Notifications" Type="System.Collections.Specialized.StringCollection" Scope="User">
<Value Profile="(Default)" />
</Setting>
</Settings>
</SettingsFile>

View File

@ -0,0 +1,105 @@
// Copyright (c) 2024- schick Informatik
// Description:
//
using System;
using System.ComponentModel;
using System.Windows;
using ToastNotifications;
using ToastNotifications.Core;
using ToastNotifications.Lifetime;
using ToastNotifications.Lifetime.Clear;
using ToastNotifications.Messages;
using ToastNotifications.Position;
namespace BreCalClient
{
internal class ToastViewModel : INotifyPropertyChanged
{
private readonly Notifier _notifier;
public ToastViewModel()
{
_notifier = new Notifier(cfg =>
{
cfg.PositionProvider = new WindowPositionProvider(
parentWindow: Application.Current.MainWindow,
corner: Corner.BottomRight,
offsetX: 25,
offsetY: 100);
cfg.LifetimeSupervisor = new TimeAndCountBasedLifetimeSupervisor(
notificationLifetime: TimeSpan.FromSeconds(6),
maximumNotificationCount: MaximumNotificationCount.FromCount(6));
cfg.Dispatcher = Application.Current.Dispatcher;
cfg.DisplayOptions.TopMost = false;
cfg.DisplayOptions.Width = 250;
});
_notifier.ClearMessages(new ClearAll());
}
public void OnUnloaded()
{
_notifier.Dispose();
}
public void ShowInformation(string message)
{
_notifier.ShowInformation(message);
}
public void ShowInformation(string message, MessageOptions opts)
{
_notifier.ShowInformation(message, opts);
}
public void ShowSuccess(string message)
{
_notifier.ShowSuccess(message);
}
public void ShowSuccess(string message, MessageOptions opts)
{
_notifier.ShowSuccess(message, opts);
}
internal void ClearMessages(string msg)
{
_notifier.ClearMessages(new ClearByMessage(msg));
}
public void ShowWarning(string message, MessageOptions opts)
{
_notifier.ShowWarning(message, opts);
}
public void ShowError(string message)
{
_notifier.ShowError(message);
}
public void ShowError(string message, MessageOptions opts)
{
_notifier.ShowError(message, opts);
}
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged(string? propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
handler.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void ClearAll()
{
_notifier.ClearMessages(new ClearAll());
}
}
}