303 lines
9.8 KiB
C#
303 lines
9.8 KiB
C#
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
/* TODO: Refactor as popup, detach from the window renderer */
|
|||
|
|
|
|||
|
|
using WPFluent.Input;
|
|||
|
|
|
|||
|
|
using System.Windows.Controls;
|
|||
|
|
|
|||
|
|
|
|||
|
|
// ReSharper disable once CheckNamespace
|
|||
|
|
namespace WPFluent.Controls;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Snackbar inform user of a process that an app has performed or will perform. It appears temporarily, towards the
|
|||
|
|
/// bottom of the window.
|
|||
|
|
/// </summary>
|
|||
|
|
public class Snackbar : ContentControl, IAppearanceControl, IIconControl
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// Identifies the <see cref="Appearance"/> dependency property.
|
|||
|
|
/// </summary>
|
|||
|
|
public static readonly DependencyProperty AppearanceProperty = DependencyProperty.Register(
|
|||
|
|
nameof(Appearance),
|
|||
|
|
typeof(ControlAppearance),
|
|||
|
|
typeof(Snackbar),
|
|||
|
|
new PropertyMetadata(ControlAppearance.Secondary));
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Identifies the <see cref="Closed"/> routed event.
|
|||
|
|
/// </summary>
|
|||
|
|
public static readonly RoutedEvent ClosedEvent = EventManager.RegisterRoutedEvent(
|
|||
|
|
nameof(Closed),
|
|||
|
|
RoutingStrategy.Bubble,
|
|||
|
|
typeof(TypedEventHandler<Snackbar, RoutedEventArgs>),
|
|||
|
|
typeof(Snackbar));
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Identifies the <see cref="ContentForeground"/> dependency property.
|
|||
|
|
/// </summary>
|
|||
|
|
public static readonly DependencyProperty ContentForegroundProperty = DependencyProperty.Register(
|
|||
|
|
nameof(ContentForeground),
|
|||
|
|
typeof(Brush),
|
|||
|
|
typeof(Snackbar),
|
|||
|
|
new FrameworkPropertyMetadata(SystemColors.ControlTextBrush, FrameworkPropertyMetadataOptions.Inherits));
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Identifies the <see cref="Icon"/> dependency property.
|
|||
|
|
/// </summary>
|
|||
|
|
public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
|
|||
|
|
nameof(Icon),
|
|||
|
|
typeof(IconElement),
|
|||
|
|
typeof(Snackbar),
|
|||
|
|
new PropertyMetadata(null, null, IconElement.Coerce));
|
|||
|
|
/// <summary>
|
|||
|
|
/// Identifies the <see cref="IsCloseButtonEnabled"/> dependency property.
|
|||
|
|
/// </summary>
|
|||
|
|
public static readonly DependencyProperty IsCloseButtonEnabledProperty = DependencyProperty.Register(
|
|||
|
|
nameof(IsCloseButtonEnabled),
|
|||
|
|
typeof(bool),
|
|||
|
|
typeof(Snackbar),
|
|||
|
|
new PropertyMetadata(true));
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Identifies the <see cref="IsShown"/> dependency property.
|
|||
|
|
/// </summary>
|
|||
|
|
public static readonly DependencyProperty IsShownProperty = DependencyProperty.Register(
|
|||
|
|
nameof(IsShown),
|
|||
|
|
typeof(bool),
|
|||
|
|
typeof(Snackbar),
|
|||
|
|
new PropertyMetadata(false, (d, e) => (d as Snackbar)?.OnIsShownChanged(e)));
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Identifies the <see cref="Opened"/> routed event.
|
|||
|
|
/// </summary>
|
|||
|
|
public static readonly RoutedEvent OpenedEvent = EventManager.RegisterRoutedEvent(
|
|||
|
|
nameof(Opened),
|
|||
|
|
RoutingStrategy.Bubble,
|
|||
|
|
typeof(TypedEventHandler<Snackbar, RoutedEventArgs>),
|
|||
|
|
typeof(Snackbar));
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Identifies the <see cref="SlideTransform"/> dependency property.
|
|||
|
|
/// </summary>
|
|||
|
|
public static readonly DependencyProperty SlideTransformProperty = DependencyProperty.Register(
|
|||
|
|
nameof(SlideTransform),
|
|||
|
|
typeof(TranslateTransform),
|
|||
|
|
typeof(Snackbar),
|
|||
|
|
new PropertyMetadata(null));
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Identifies the <see cref="TemplateButtonCommand"/> dependency property.
|
|||
|
|
/// </summary>
|
|||
|
|
public static readonly DependencyProperty TemplateButtonCommandProperty = DependencyProperty.Register(
|
|||
|
|
nameof(TemplateButtonCommand),
|
|||
|
|
typeof(IRelayCommand),
|
|||
|
|
typeof(Snackbar),
|
|||
|
|
new PropertyMetadata(null));
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Identifies the <see cref="Timeout"/> dependency property.
|
|||
|
|
/// </summary>
|
|||
|
|
public static readonly DependencyProperty TimeoutProperty = DependencyProperty.Register(
|
|||
|
|
nameof(Timeout),
|
|||
|
|
typeof(TimeSpan),
|
|||
|
|
typeof(Snackbar),
|
|||
|
|
new PropertyMetadata(TimeSpan.FromSeconds(2)));
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Identifies the <see cref="Title"/> dependency property.
|
|||
|
|
/// </summary>
|
|||
|
|
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
|
|||
|
|
nameof(Title),
|
|||
|
|
typeof(object),
|
|||
|
|
typeof(Snackbar),
|
|||
|
|
new PropertyMetadata(null));
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Identifies the <see cref="TitleTemplate"/> dependency property.
|
|||
|
|
/// </summary>
|
|||
|
|
public static readonly DependencyProperty TitleTemplateProperty = DependencyProperty.Register(
|
|||
|
|
nameof(TitleTemplate),
|
|||
|
|
typeof(DataTemplate),
|
|||
|
|
typeof(Snackbar),
|
|||
|
|
new PropertyMetadata(null));
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Initializes a new instance of the <see cref="Snackbar"/> class with a specified presenter.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="presenter">The <see cref="SnackbarPresenter"/> to manage the snackbar's display and interactions.</param>
|
|||
|
|
public Snackbar(SnackbarPresenter presenter)
|
|||
|
|
{
|
|||
|
|
Presenter = presenter;
|
|||
|
|
|
|||
|
|
SetValue(TemplateButtonCommandProperty, new RelayCommand<object>(_ => Hide()));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Occurs when the snackbar is about to close.
|
|||
|
|
/// </summary>
|
|||
|
|
public event TypedEventHandler<Snackbar, RoutedEventArgs> Closed
|
|||
|
|
{
|
|||
|
|
add => AddHandler(ClosedEvent, value);
|
|||
|
|
remove => RemoveHandler(ClosedEvent, value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Occurs when the snackbar is about to open.
|
|||
|
|
/// </summary>
|
|||
|
|
public event TypedEventHandler<Snackbar, RoutedEventArgs> Opened
|
|||
|
|
{
|
|||
|
|
add => AddHandler(OpenedEvent, value);
|
|||
|
|
remove => RemoveHandler(OpenedEvent, value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Hides the <see cref="Snackbar"/>
|
|||
|
|
/// </summary>
|
|||
|
|
protected virtual void Hide() { _ = Presenter.HideCurrent(); }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// This virtual method is called when <see cref="Snackbar"/> is closing and it raises the <see cref="Closed"/> <see
|
|||
|
|
/// langword="event"/>.
|
|||
|
|
/// </summary>
|
|||
|
|
protected virtual void OnClosed() { RaiseEvent(new RoutedEventArgs(ClosedEvent, this)); }
|
|||
|
|
|
|||
|
|
protected void OnIsShownChanged(DependencyPropertyChangedEventArgs e)
|
|||
|
|
{
|
|||
|
|
bool newValue = (bool)e.NewValue;
|
|||
|
|
|
|||
|
|
if(newValue)
|
|||
|
|
{
|
|||
|
|
OnOpened();
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
OnClosed();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// This virtual method is called when <see cref="Snackbar"/> is opening and it raises the <see cref="Opened"/> <see
|
|||
|
|
/// langword="event"/>.
|
|||
|
|
/// </summary>
|
|||
|
|
protected virtual void OnOpened() { RaiseEvent(new RoutedEventArgs(OpenedEvent, this)); }
|
|||
|
|
|
|||
|
|
protected SnackbarPresenter Presenter { get; }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Shows the <see cref="Snackbar"/>
|
|||
|
|
/// </summary>
|
|||
|
|
public virtual void Show() { Show(false); }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Shows the <see cref="Snackbar"/>
|
|||
|
|
/// </summary>
|
|||
|
|
public virtual void Show(bool immediately)
|
|||
|
|
{
|
|||
|
|
if(immediately)
|
|||
|
|
{
|
|||
|
|
_ = Presenter.ImmediatelyDisplay(this);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
Presenter.AddToQue(this);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Shows the <see cref="Snackbar"/>.
|
|||
|
|
/// </summary>
|
|||
|
|
public virtual Task ShowAsync() { return ShowAsync(false); }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Shows the <see cref="Snackbar"/>.
|
|||
|
|
/// </summary>
|
|||
|
|
public virtual async Task ShowAsync(bool immediately)
|
|||
|
|
{
|
|||
|
|
if(immediately)
|
|||
|
|
{
|
|||
|
|
await Presenter.ImmediatelyDisplay(this);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
Presenter.AddToQue(this);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <inheritdoc/>
|
|||
|
|
[Bindable(true)]
|
|||
|
|
[Category("Appearance")]
|
|||
|
|
public ControlAppearance Appearance
|
|||
|
|
{
|
|||
|
|
get => (ControlAppearance)GetValue(AppearanceProperty);
|
|||
|
|
set => SetValue(AppearanceProperty, value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the foreground of the <see cref="ContentControl.Content"/>.
|
|||
|
|
/// </summary>
|
|||
|
|
[Bindable(true)]
|
|||
|
|
[Category("Appearance")]
|
|||
|
|
public Brush ContentForeground
|
|||
|
|
{
|
|||
|
|
get => (Brush)GetValue(ContentForegroundProperty);
|
|||
|
|
set => SetValue(ContentForegroundProperty, value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the icon
|
|||
|
|
/// </summary>
|
|||
|
|
[Bindable(true)]
|
|||
|
|
[Category("Appearance")]
|
|||
|
|
public IconElement? Icon { get => (IconElement?)GetValue(IconProperty); set => SetValue(IconProperty, value); }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets a value indicating whether the <see cref="Snackbar"/> close button should be visible.
|
|||
|
|
/// </summary>
|
|||
|
|
public bool IsCloseButtonEnabled
|
|||
|
|
{
|
|||
|
|
get => (bool)GetValue(IsCloseButtonEnabledProperty);
|
|||
|
|
set => SetValue(IsCloseButtonEnabledProperty, value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets a value indicating whether the <see cref="Snackbar"/> is visible.
|
|||
|
|
/// </summary>
|
|||
|
|
public bool IsShown { get => (bool)GetValue(IsShownProperty); set => SetValue(IsShownProperty, value); }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the transform.
|
|||
|
|
/// </summary>
|
|||
|
|
public TranslateTransform? SlideTransform
|
|||
|
|
{
|
|||
|
|
get => (TranslateTransform?)GetValue(SlideTransformProperty);
|
|||
|
|
set => SetValue(SlideTransformProperty, value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets the command triggered after clicking the button in the template.
|
|||
|
|
/// </summary>
|
|||
|
|
public IRelayCommand TemplateButtonCommand => (IRelayCommand)GetValue(TemplateButtonCommandProperty);
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets a time for which the <see cref="Snackbar"/> should be visible.
|
|||
|
|
/// </summary>
|
|||
|
|
public TimeSpan Timeout { get => (TimeSpan)GetValue(TimeoutProperty); set => SetValue(TimeoutProperty, value); }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the title of the <see cref="Snackbar"/>.
|
|||
|
|
/// </summary>
|
|||
|
|
public object? Title { get => GetValue(TitleProperty); set => SetValue(TitleProperty, value); }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the title template of the <see cref="Snackbar"/>.
|
|||
|
|
/// </summary>
|
|||
|
|
public DataTemplate? TitleTemplate
|
|||
|
|
{
|
|||
|
|
get => (DataTemplate?)GetValue(TitleTemplateProperty);
|
|||
|
|
set => SetValue(TitleTemplateProperty, value);
|
|||
|
|
}
|
|||
|
|
}
|