Skip to content

Commit

Permalink
Merge pull request #194 from AuroraZiling/main
Browse files Browse the repository at this point in the history
[Refactor/Clean] MessageBox & Toast & WaveProgress
  • Loading branch information
AuroraZiling authored May 22, 2024
2 parents 18ee97e + 3472e64 commit d995252
Show file tree
Hide file tree
Showing 18 changed files with 322 additions and 309 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<controls:GroupBox Header="Toasts">
<StackPanel Classes="HeaderContent">
<TextBlock>
SukiUI contains an API for creating and dismissing toasts, with the ability to set limits on the number of toasts.
SukiUI contains an API for creating and dismissing 4 kinds of toasts, with the ability to set limits on the number of toasts.
</TextBlock>
<TextBlock>
It is also possible to set the toasts to appear in the bottom right (default) or in the bottom left.
Expand Down
10 changes: 5 additions & 5 deletions SukiUI.Demo/Features/ControlsLibrary/Toasts/ToastsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,19 @@ private static Task ShowSingleStandardToast() =>

[RelayCommand]
private static Task ShowInfoToast() =>
SukiHost.ShowToast("A Simple Toast", "This is the content of an info toast.", SukiToastType.Info);
SukiHost.ShowToast("A Simple Toast", "This is the content of an info toast.", ToastType.Info);

[RelayCommand]
private static Task ShowSuccessToast() =>
SukiHost.ShowToast("A Simple Toast", "This is the content of a success toast.", SukiToastType.Success);
SukiHost.ShowToast("A Simple Toast", "This is the content of a success toast.", ToastType.Success);

[RelayCommand]
private static Task ShowWarningToast() =>
SukiHost.ShowToast("A Simple Toast", "This is the content of a warning toast.", SukiToastType.Warning);
SukiHost.ShowToast("A Simple Toast", "This is the content of a warning toast.", ToastType.Warning);

[RelayCommand]
private static Task ShowErrorToast() =>
SukiHost.ShowToast("A Simple Toast", "This is the content of an error toast.", SukiToastType.Error);
SukiHost.ShowToast("A Simple Toast", "This is the content of an error toast.", ToastType.Error);

[RelayCommand]
private static async Task ShowThreeInfoToasts()
Expand All @@ -46,7 +46,7 @@ private static async Task ShowThreeInfoToasts()
[RelayCommand]
private static Task ShowToastWithCallback()
{
return SukiHost.ShowToast("Click This Toast", "Click this toast to open a dialog.", SukiToastType.Info, TimeSpan.FromSeconds(15),
return SukiHost.ShowToast("Click This Toast", "Click this toast to open a dialog.", ToastType.Info, TimeSpan.FromSeconds(15),
() => SukiHost.ShowDialog(
new TextBlock { Text = "You clicked the toast! - Click anywhere outside of this dialog to close." },
allowBackgroundClose: true));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,100 +1,99 @@
<Window x:Class="SukiUI.MessageBox.MessageBox"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:content="clr-namespace:SukiUI.Content"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:suki="clr-namespace:SukiUI.Controls;assembly=SukiUI"
Width="500"
Height="150"
MaxWidth="500"
MaxHeight="150"
d:DesignHeight="200"
d:DesignWidth="500"
Background="{DynamicResource SukiBackground}"
Classes="NakedWindow"
ExtendClientAreaToDecorationsHint="True"
mc:Ignorable="d">
<Panel>
<Panel.Styles>
<Style Selector="Grid.AnimatedGrid">
<Style.Animations>
<Animation Duration="0:0:4">
<KeyFrame Cue="0%">
<Setter Property="ScaleTransform.ScaleX" Value="1" />
<Setter Property="ScaleTransform.ScaleY" Value="1" />
</KeyFrame>
<KeyFrame Cue="80%">
<Setter Property="ScaleTransform.ScaleX" Value="1" />
<Setter Property="ScaleTransform.ScaleY" Value="1" />
</KeyFrame>
<KeyFrame Cue="84%">
<Setter Property="ScaleTransform.ScaleX" Value="0.99" />
<Setter Property="ScaleTransform.ScaleY" Value="0.99" />
</KeyFrame>
<KeyFrame Cue="88%">
<Setter Property="ScaleTransform.ScaleX" Value="1" />
<Setter Property="ScaleTransform.ScaleY" Value="1" />
</KeyFrame>
<KeyFrame Cue="94%">
<Setter Property="ScaleTransform.ScaleX" Value="0.99" />
<Setter Property="ScaleTransform.ScaleY" Value="0.99" />
</KeyFrame>
<KeyFrame Cue="100%">
<Setter Property="ScaleTransform.ScaleX" Value="1" />
<Setter Property="ScaleTransform.ScaleY" Value="1" />
</KeyFrame>
</Animation>
</Style.Animations>
</Style>
</Panel.Styles>
<Panel Background="{DynamicResource SukiBackground}" IsHitTestVisible="False" />
<Button Width="23"
Height="23"
Margin="12"
Padding="0"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="Transparent"
BorderThickness="0"
Classes="ZoomOnHover"
Click="Close">
<PathIcon Data="{x:Static content:Icons.CircleOutlineClose}" Foreground="DarkRed" />
</Button>

<Grid Classes="AnimatedGrid">
<PathIcon Name="InfoIcon"
Width="50"
Height="50"
Margin="25,35,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Data="{x:Static content:Icons.CircleInformation}"
DockPanel.Dock="Left"
Foreground="{DynamicResource SukiPrimaryColor}" />
</Grid>

<TextBlock Name="Title"
Margin="100,45,0,-45"
HorizontalAlignment="Left"
Classes="h3"
DockPanel.Dock="Top" />
<ScrollViewer Margin="102,45,14,10"
HorizontalAlignment="Left"
VerticalAlignment="Center">
<TextBlock Name="Message"
FontWeight="Light"
TextWrapping="Wrap" />
</ScrollViewer>

<Button Width="80"
Margin="0,0,0,7"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Classes="Basic"
Click="Close"
DockPanel.Dock="Bottom">
<TextBlock />
</Button>
</Panel>
<Window x:Class="SukiUI.Controls.MessageBox"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:content="clr-namespace:SukiUI.Content"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Width="500"
Height="150"
MaxWidth="500"
MaxHeight="150"
d:DesignHeight="200"
d:DesignWidth="500"
Background="{DynamicResource SukiBackground}"
Classes="NakedWindow"
ExtendClientAreaToDecorationsHint="True"
mc:Ignorable="d">
<Panel>
<Panel.Styles>
<Style Selector="Grid.AnimatedGrid">
<Style.Animations>
<Animation Duration="0:0:4">
<KeyFrame Cue="0%">
<Setter Property="ScaleTransform.ScaleX" Value="1" />
<Setter Property="ScaleTransform.ScaleY" Value="1" />
</KeyFrame>
<KeyFrame Cue="80%">
<Setter Property="ScaleTransform.ScaleX" Value="1" />
<Setter Property="ScaleTransform.ScaleY" Value="1" />
</KeyFrame>
<KeyFrame Cue="84%">
<Setter Property="ScaleTransform.ScaleX" Value="0.99" />
<Setter Property="ScaleTransform.ScaleY" Value="0.99" />
</KeyFrame>
<KeyFrame Cue="88%">
<Setter Property="ScaleTransform.ScaleX" Value="1" />
<Setter Property="ScaleTransform.ScaleY" Value="1" />
</KeyFrame>
<KeyFrame Cue="94%">
<Setter Property="ScaleTransform.ScaleX" Value="0.99" />
<Setter Property="ScaleTransform.ScaleY" Value="0.99" />
</KeyFrame>
<KeyFrame Cue="100%">
<Setter Property="ScaleTransform.ScaleX" Value="1" />
<Setter Property="ScaleTransform.ScaleY" Value="1" />
</KeyFrame>
</Animation>
</Style.Animations>
</Style>
</Panel.Styles>
<Panel Background="{DynamicResource SukiBackground}" IsHitTestVisible="False" />
<Button Width="23"
Height="23"
Margin="12"
Padding="0"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="Transparent"
BorderThickness="0"
Classes="ZoomOnHover"
Click="Close">
<PathIcon Data="{x:Static content:Icons.CircleOutlineClose}" Foreground="DarkRed" />
</Button>

<Grid Classes="AnimatedGrid">
<PathIcon Name="InfoIcon"
Width="50"
Height="50"
Margin="25,35,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Data="{x:Static content:Icons.CircleInformation}"
DockPanel.Dock="Left"
Foreground="{DynamicResource SukiPrimaryColor}" />
</Grid>

<TextBlock Name="Title"
Margin="100,45,0,-45"
HorizontalAlignment="Left"
Classes="h3"
DockPanel.Dock="Top" />
<ScrollViewer Margin="102,45,14,10"
HorizontalAlignment="Left"
VerticalAlignment="Center">
<TextBlock Name="Message"
FontWeight="Light"
TextWrapping="Wrap" />
</ScrollViewer>

<Button Width="80"
Margin="0,0,0,7"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Classes="Basic"
Click="Close"
DockPanel.Dock="Bottom">
<TextBlock />
</Button>
</Panel>
</Window>
66 changes: 66 additions & 0 deletions SukiUI/Controls/MessageBox.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using SukiUI.Content;
using SukiUI.Extensions;

namespace SukiUI.Controls;

public partial class MessageBox : Window
{
private static readonly SolidColorBrush InfoBrush = new(Color.FromRgb(47, 84, 235));

public MessageBox()
{
InitializeComponent();
}

public MessageBox(string title, string message)
{
InitializeComponent();
this.FindRequiredControl<TextBlock>("Title").Text = title;
this.FindRequiredControl<TextBlock>("Message").Text = message;
}

private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
CanResize = false;
}

public static void Info(Window owner, string title, string message, WindowStartupLocation startupLocation = WindowStartupLocation.CenterScreen)
{
var mbox = new MessageBox(title, message);
if (mbox.FindControl<PathIcon>("InfoIcon") is not { } icon) return;
icon.Data = Icons.CircleInformation;
icon.Foreground = InfoBrush;
mbox.WindowStartupLocation = startupLocation;
mbox.ShowDialog(owner);
}

public static void Success(Window owner, string title, string message, WindowStartupLocation startupLocation = WindowStartupLocation.CenterScreen)
{
var mbox = new MessageBox(title, message);
if (mbox.FindControl<PathIcon>("InfoIcon") is not { } icon) return;
icon.Data = Icons.CircleCheck;
icon.Foreground = Brushes.DarkGreen;
mbox.WindowStartupLocation = startupLocation;
mbox.ShowDialog(owner);
}

public static void Error(Window owner, string title, string message, WindowStartupLocation startupLocation = WindowStartupLocation.CenterScreen)
{
var mbox = new MessageBox(title, message);
if (mbox.FindControl<PathIcon>("InfoIcon") is not { } icon) return;
icon.Data = Icons.CircleClose;
icon.Foreground = Brushes.DarkRed;
mbox.WindowStartupLocation = startupLocation;
mbox.ShowDialog(owner);
}

private void Close(object sender, RoutedEventArgs e)
{
Close();
}
}
22 changes: 11 additions & 11 deletions SukiUI/Controls/SukiHost.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,14 @@ private static void BackgroundRequestClose(SukiHost host)
/// <param name="window">The window who's SukiHost should be used to display the toast.</param>
/// <param name="model">A pre-constructed <see cref="SukiToastModel"/>.</param>
/// <exception cref="InvalidOperationException">Thrown if there is no SukiHost associated with the specified window.</exception>
public static async Task ShowToast(Window window, SukiToastModel model)
public static async Task ShowToast(Window window, ToastModel model)
{
try
{
if (!Instances.TryGetValue(window, out var host))
throw new InvalidOperationException("No SukiHost present in this window");

var toast = SukiToastPool.Get();
var toast = ToastPool.Get();
toast.Initialize(model, host);
if (host.ToastsCollection.Count >= host._maxToasts)
await ClearToast(host.ToastsCollection.First());
Expand All @@ -202,7 +202,7 @@ public static async Task ShowToast(Window window, SukiToastModel model)
/// This method will show the toast in the earliest opened window.
/// </summary>
/// <param name="model">A pre-constructed <see cref="SukiToastModel"/>.</param>
public static Task ShowToast(SukiToastModel model) =>
public static Task ShowToast(ToastModel model) =>
ShowToast(_mainWindow, model);

/// <summary>
Expand All @@ -214,11 +214,11 @@ public static Task ShowToast(SukiToastModel model) =>
/// <param name="type">The type of the toast, including Info, Success, Warning and Error</param>
/// <param name="duration">Duration for this toast to be active. Default is 2 seconds.</param>
/// <param name="onClicked">A callback that will be fired if the Toast is cleared by clicking.</param>
public static Task ShowToast(string title, object content, SukiToastType? type = SukiToastType.Info, TimeSpan? duration = null, Action? onClicked = null) =>
ShowToast(new SukiToastModel(
public static Task ShowToast(string title, object content, ToastType? type = ToastType.Info, TimeSpan? duration = null, Action? onClicked = null) =>
ShowToast(new ToastModel(
title,
content as Control ?? ViewLocator.TryBuild(content),
type ?? SukiToastType.Info,
type ?? ToastType.Info,
duration ?? TimeSpan.FromSeconds(4),
onClicked));

Expand All @@ -232,12 +232,12 @@ public static Task ShowToast(string title, object content, SukiToastType? type =
/// <param name="type">The type of the toast, including Info, Success, Warning and Error</param>
/// <param name="duration">Duration for this toast to be active. Default is 2 seconds.</param>
/// <param name="onClicked">A callback that will be fired if the Toast is cleared by clicking.</param>
public static Task ShowToast(Window window, string title, object content, SukiToastType? type = SukiToastType.Info, TimeSpan? duration = null,
public static Task ShowToast(Window window, string title, object content, ToastType? type = ToastType.Info, TimeSpan? duration = null,
Action? onClicked = null) =>
ShowToast(window, new SukiToastModel(
ShowToast(window, new ToastModel(
title,
content as Control ?? ViewLocator.TryBuild(content),
type ?? SukiToastType.Info,
type ?? ToastType.Info,
duration ?? TimeSpan.FromSeconds(4),
onClicked));

Expand All @@ -260,7 +260,7 @@ public static async Task ClearToast(SukiToast toast)
});

if (!wasRemoved) return;
SukiToastPool.Return(toast);
ToastPool.Return(toast);
}

/// <summary>
Expand All @@ -270,7 +270,7 @@ public static void ClearAllToasts(Window window)
{
if (!Instances.TryGetValue(window, out var host))
throw new InvalidOperationException("No SukiHost present in this window");
SukiToastPool.Return(host.ToastsCollection);
ToastPool.Return(host.ToastsCollection);
Dispatcher.UIThread.Invoke(() => host.ToastsCollection.Clear());
}

Expand Down
Loading

0 comments on commit d995252

Please sign in to comment.