mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Merge pull request #1721 from DGP-Studio/feat/1715
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.WinUI.Behaviors;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Snap.Hutao.Control.Behavior;
|
||||
|
||||
[SuppressMessage("", "CA1001")]
|
||||
[DependencyProperty("MilliSecondsDelay", typeof(int))]
|
||||
internal sealed partial class InfoBarDelayCloseBehavior : BehaviorBase<InfoBar>
|
||||
{
|
||||
private readonly CancellationTokenSource closeTokenSource = new();
|
||||
|
||||
protected override void OnAssociatedObjectLoaded()
|
||||
{
|
||||
AssociatedObject.Closed += OnInfoBarClosed;
|
||||
if (MilliSecondsDelay > 0)
|
||||
{
|
||||
DelayCoreAsync().SafeForget();
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask DelayCoreAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(MilliSecondsDelay, closeTokenSource.Token).ConfigureAwait(true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (AssociatedObject is not null)
|
||||
{
|
||||
AssociatedObject.IsOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInfoBarClosed(InfoBar infoBar, InfoBarClosedEventArgs args)
|
||||
{
|
||||
if (args.Reason is InfoBarCloseReason.CloseButton)
|
||||
{
|
||||
closeTokenSource.Cancel();
|
||||
}
|
||||
|
||||
AssociatedObject.Closed -= OnInfoBarClosed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Service.Notification;
|
||||
|
||||
namespace Snap.Hutao.Control.Selector;
|
||||
|
||||
internal sealed class InfoBarTemplateSelector : DataTemplateSelector
|
||||
{
|
||||
public DataTemplate ActionButtonEnabled { get; set; } = default!;
|
||||
|
||||
public DataTemplate ActionButtonDisabled { get; set; } = default!;
|
||||
|
||||
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
|
||||
{
|
||||
if (item is InfoBarOptions { ActionButtonContent: { }, ActionButtonCommand: { } })
|
||||
{
|
||||
return ActionButtonEnabled;
|
||||
}
|
||||
|
||||
return ActionButtonDisabled;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Snap.Hutao.Service.Notification;
|
||||
@@ -9,7 +8,7 @@ namespace Snap.Hutao.Service.Notification;
|
||||
[HighQuality]
|
||||
internal interface IInfoBarService
|
||||
{
|
||||
ObservableCollection<InfoBar> Collection { get; }
|
||||
ObservableCollection<InfoBarOptions> Collection { get; }
|
||||
|
||||
void PrepareInfoBarAndShow(Action<IInfoBarOptionsBuilder> configure);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
|
||||
namespace Snap.Hutao.Service.Notification;
|
||||
|
||||
@@ -16,7 +15,9 @@ internal sealed class InfoBarOptions
|
||||
|
||||
public object? Content { get; set; }
|
||||
|
||||
public ButtonBase? ActionButton { get; set; }
|
||||
public string? ActionButtonContent { get; set; }
|
||||
|
||||
public ICommand? ActionButtonCommand { get; set; }
|
||||
|
||||
public int MilliSecondsDelay { get; set; }
|
||||
}
|
||||
@@ -2,8 +2,6 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Snap.Hutao.Control.Builder.ButtonBase;
|
||||
using Snap.Hutao.Core.Abstraction.Extension;
|
||||
|
||||
namespace Snap.Hutao.Service.Notification;
|
||||
@@ -38,20 +36,17 @@ internal static class InfoBarOptionsBuilderExtension
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IInfoBarOptionsBuilder SetActionButton<TBuilder, TButton>(this TBuilder builder, Action<ButtonBaseBuilder<TButton>> configureButton)
|
||||
public static IInfoBarOptionsBuilder SetActionButtonContent<TBuilder>(this TBuilder builder, string? buttonContent)
|
||||
where TBuilder : IInfoBarOptionsBuilder
|
||||
where TButton : ButtonBase, new()
|
||||
{
|
||||
ButtonBaseBuilder<TButton> buttonBaseBuilder = new ButtonBaseBuilder<TButton>().Configure(configureButton);
|
||||
builder.Configure(builder => builder.Options.ActionButton = buttonBaseBuilder.Button);
|
||||
builder.Configure(builder => builder.Options.ActionButtonContent = buttonContent);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IInfoBarOptionsBuilder SetActionButton<TBuilder>(this TBuilder builder, Action<ButtonBuilder> configureButton)
|
||||
public static IInfoBarOptionsBuilder SetActionButtonCommand<TBuilder>(this TBuilder builder, ICommand? buttonCommand)
|
||||
where TBuilder : IInfoBarOptionsBuilder
|
||||
{
|
||||
ButtonBuilder buttonBaseBuilder = new ButtonBuilder().Configure(configureButton);
|
||||
builder.Configure(builder => builder.Options.ActionButton = buttonBaseBuilder.Button);
|
||||
builder.Configure(builder => builder.Options.ActionButtonCommand = buttonCommand);
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
using Snap.Hutao.Core.Abstraction.Extension;
|
||||
using System.Collections.ObjectModel;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Snap.Hutao.Service.Notification;
|
||||
|
||||
@@ -17,20 +14,16 @@ internal sealed class InfoBarService : IInfoBarService
|
||||
private readonly ILogger<InfoBarService> logger;
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
private readonly TypedEventHandler<InfoBar, InfoBarClosedEventArgs> infobarClosedEventHandler;
|
||||
|
||||
private ObservableCollection<InfoBar>? collection;
|
||||
private ObservableCollection<InfoBarOptions>? collection;
|
||||
|
||||
public InfoBarService(IServiceProvider serviceProvider)
|
||||
{
|
||||
logger = serviceProvider.GetRequiredService<ILogger<InfoBarService>>();
|
||||
taskContext = serviceProvider.GetRequiredService<ITaskContext>();
|
||||
|
||||
infobarClosedEventHandler = OnInfoBarClosed;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ObservableCollection<InfoBar> Collection
|
||||
public ObservableCollection<InfoBarOptions> Collection
|
||||
{
|
||||
get => collection ??= [];
|
||||
}
|
||||
@@ -51,33 +44,7 @@ internal sealed class InfoBarService : IInfoBarService
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
|
||||
InfoBar infoBar = new()
|
||||
{
|
||||
Severity = builder.Options.Severity,
|
||||
Title = builder.Options.Title,
|
||||
Message = builder.Options.Message,
|
||||
Content = builder.Options.Content,
|
||||
IsOpen = true,
|
||||
ActionButton = builder.Options.ActionButton,
|
||||
Transitions = [new AddDeleteThemeTransition()],
|
||||
};
|
||||
|
||||
infoBar.Closed += infobarClosedEventHandler;
|
||||
ArgumentNullException.ThrowIfNull(collection);
|
||||
collection.Add(infoBar);
|
||||
|
||||
if (builder.Options.MilliSecondsDelay > 0)
|
||||
{
|
||||
await Delay.FromMilliSeconds(builder.Options.MilliSecondsDelay).ConfigureAwait(true);
|
||||
collection.Remove(infoBar);
|
||||
infoBar.IsOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInfoBarClosed(InfoBar sender, InfoBarClosedEventArgs args)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(collection);
|
||||
taskContext.BeginInvokeOnMainThread(() => collection.Remove(sender));
|
||||
sender.Closed -= infobarClosedEventHandler;
|
||||
collection.Add(builder.Options);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Control.Builder.ButtonBase;
|
||||
using Snap.Hutao.Core.Abstraction.Extension;
|
||||
|
||||
namespace Snap.Hutao.Service.Notification;
|
||||
@@ -21,7 +20,7 @@ internal static class InfoBarServiceExtension
|
||||
|
||||
public static void Information(this IInfoBarService infoBarService, string title, string message, string buttonContent, ICommand buttonCommand, int milliSeconds = 5000)
|
||||
{
|
||||
infoBarService.Information(builder => builder.SetTitle(title).SetMessage(message).SetActionButton(buttonBuilder => buttonBuilder.SetContent(buttonContent).SetCommand(buttonCommand)).SetDelay(milliSeconds));
|
||||
infoBarService.Information(builder => builder.SetTitle(title).SetMessage(message).SetActionButtonContent(buttonContent).SetActionButtonCommand(buttonCommand).SetDelay(milliSeconds));
|
||||
}
|
||||
|
||||
public static void Information(this IInfoBarService infoBarService, Action<IInfoBarOptionsBuilder> configure)
|
||||
@@ -56,7 +55,7 @@ internal static class InfoBarServiceExtension
|
||||
|
||||
public static void Warning(this IInfoBarService infoBarService, string title, string message, string buttonContent, ICommand buttonCommand, int milliSeconds = 30000)
|
||||
{
|
||||
infoBarService.Warning(builder => builder.SetTitle(title).SetMessage(message).SetActionButton(buttonBuilder => buttonBuilder.SetContent(buttonContent).SetCommand(buttonCommand)).SetDelay(milliSeconds));
|
||||
infoBarService.Warning(builder => builder.SetTitle(title).SetMessage(message).SetActionButtonContent(buttonContent).SetActionButtonCommand(buttonCommand).SetDelay(milliSeconds));
|
||||
}
|
||||
|
||||
public static void Warning(this IInfoBarService infoBarService, Action<IInfoBarOptionsBuilder> configure)
|
||||
@@ -76,7 +75,7 @@ internal static class InfoBarServiceExtension
|
||||
|
||||
public static void Error(this IInfoBarService infoBarService, string title, string message, string buttonContent, ICommand buttonCommand, int milliSeconds = 0)
|
||||
{
|
||||
infoBarService.Error(builder => builder.SetTitle(title).SetMessage(message).SetActionButton(buttonBuilder => buttonBuilder.SetContent(buttonContent).SetCommand(buttonCommand)).SetDelay(milliSeconds));
|
||||
infoBarService.Error(builder => builder.SetTitle(title).SetMessage(message).SetActionButtonContent(buttonContent).SetActionButtonCommand(buttonCommand).SetDelay(milliSeconds));
|
||||
}
|
||||
|
||||
public static void Error(this IInfoBarService infoBarService, Exception ex, int milliSeconds = 0)
|
||||
@@ -91,7 +90,7 @@ internal static class InfoBarServiceExtension
|
||||
|
||||
public static void Error(this IInfoBarService infoBarService, Exception ex, string subtitle, string buttonContent, ICommand buttonCommand, int milliSeconds = 0)
|
||||
{
|
||||
infoBarService.Error(builder => builder.SetTitle(ex.GetType().Name).SetMessage($"{subtitle}\n{ex.Message}").SetActionButton(buttonBuilder => buttonBuilder.SetContent(buttonContent).SetCommand(buttonCommand)).SetDelay(milliSeconds));
|
||||
infoBarService.Error(builder => builder.SetTitle(ex.GetType().Name).SetMessage($"{subtitle}\n{ex.Message}").SetActionButtonContent(buttonContent).SetActionButtonCommand(buttonCommand).SetDelay(milliSeconds));
|
||||
}
|
||||
|
||||
public static void Error(this IInfoBarService infoBarService, Action<IInfoBarOptionsBuilder> configure)
|
||||
|
||||
@@ -5,67 +5,112 @@
|
||||
xmlns:cw="using:CommunityToolkit.WinUI"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||
xmlns:shcs="using:Snap.Hutao.Control.Selector"
|
||||
xmlns:shsn="using:Snap.Hutao.Service.Notification"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarErrorSeverityBackgroundBrush"
|
||||
FallbackColor="#FDE7E9"
|
||||
TintColor="#FDE7E9"
|
||||
TintOpacity="0.6"/>
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarWarningSeverityBackgroundBrush"
|
||||
FallbackColor="#FFF4CE"
|
||||
TintColor="#FFF4CE"
|
||||
TintOpacity="0.6"/>
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarSuccessSeverityBackgroundBrush"
|
||||
FallbackColor="#DFF6DD"
|
||||
TintColor="#DFF6DD"
|
||||
TintOpacity="0.6"/>
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarInformationalSeverityBackgroundBrush"
|
||||
FallbackColor="#80F6F6F6"
|
||||
TintColor="#80F6F6F6"
|
||||
TintOpacity="0.6"/>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarErrorSeverityBackgroundBrush"
|
||||
FallbackColor="#442726"
|
||||
TintColor="#442726"
|
||||
TintOpacity="0.6"/>
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarWarningSeverityBackgroundBrush"
|
||||
FallbackColor="#433519"
|
||||
TintColor="#433519"
|
||||
TintOpacity="0.6"/>
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarSuccessSeverityBackgroundBrush"
|
||||
FallbackColor="#393D1B"
|
||||
TintColor="#393D1B"
|
||||
TintOpacity="0.6"/>
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarInformationalSeverityBackgroundBrush"
|
||||
FallbackColor="#34424d"
|
||||
TintColor="#34424d"
|
||||
TintOpacity="0.6"/>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<DataTemplate x:Key="InfoBarTemplate" x:DataType="shsn:InfoBarOptions">
|
||||
<InfoBar
|
||||
Title="{Binding Title}"
|
||||
Closed="OnInfoBarClosed"
|
||||
Content="{Binding Content}"
|
||||
IsOpen="True"
|
||||
Message="{Binding Message}"
|
||||
Severity="{Binding Severity}">
|
||||
<mxi:Interaction.Behaviors>
|
||||
<shcb:InfoBarDelayCloseBehavior MilliSecondsDelay="{Binding MilliSecondsDelay}"/>
|
||||
</mxi:Interaction.Behaviors>
|
||||
</InfoBar>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="InfoBarWithActionButtonTemplate" x:DataType="shsn:InfoBarOptions">
|
||||
<InfoBar
|
||||
Title="{Binding Title}"
|
||||
Closed="OnInfoBarClosed"
|
||||
Content="{Binding Content}"
|
||||
IsOpen="True"
|
||||
Message="{Binding Message}"
|
||||
Severity="{Binding Severity}">
|
||||
<InfoBar.ActionButton>
|
||||
<Button Command="{Binding ActionButtonCommand}" Content="{Binding ActionButtonContent}"/>
|
||||
</InfoBar.ActionButton>
|
||||
<mxi:Interaction.Behaviors>
|
||||
<shcb:InfoBarDelayCloseBehavior MilliSecondsDelay="{Binding MilliSecondsDelay}"/>
|
||||
</mxi:Interaction.Behaviors>
|
||||
</InfoBar>
|
||||
</DataTemplate>
|
||||
|
||||
<shcs:InfoBarTemplateSelector
|
||||
x:Key="InfoBarTemplateSelector"
|
||||
ActionButtonDisabled="{StaticResource InfoBarTemplate}"
|
||||
ActionButtonEnabled="{StaticResource InfoBarWithActionButtonTemplate}"/>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<ItemsControl
|
||||
MaxWidth="640"
|
||||
Margin="32,48,32,32"
|
||||
VerticalAlignment="Bottom"
|
||||
ItemContainerTransitions="{StaticResource RepositionThemeTransitions}"
|
||||
ItemTemplateSelector="{StaticResource InfoBarTemplateSelector}"
|
||||
ItemsSource="{x:Bind InfoBars}"
|
||||
Visibility="{x:Bind VisibilityButton.IsChecked, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}">
|
||||
<ItemsControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarErrorSeverityBackgroundBrush"
|
||||
FallbackColor="#FDE7E9"
|
||||
TintColor="#FDE7E9"
|
||||
TintOpacity="0.6"/>
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarWarningSeverityBackgroundBrush"
|
||||
FallbackColor="#FFF4CE"
|
||||
TintColor="#FFF4CE"
|
||||
TintOpacity="0.6"/>
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarSuccessSeverityBackgroundBrush"
|
||||
FallbackColor="#DFF6DD"
|
||||
TintColor="#DFF6DD"
|
||||
TintOpacity="0.6"/>
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarInformationalSeverityBackgroundBrush"
|
||||
FallbackColor="#80F6F6F6"
|
||||
TintColor="#80F6F6F6"
|
||||
TintOpacity="0.6"/>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarErrorSeverityBackgroundBrush"
|
||||
FallbackColor="#442726"
|
||||
TintColor="#442726"
|
||||
TintOpacity="0.6"/>
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarWarningSeverityBackgroundBrush"
|
||||
FallbackColor="#433519"
|
||||
TintColor="#433519"
|
||||
TintOpacity="0.6"/>
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarSuccessSeverityBackgroundBrush"
|
||||
FallbackColor="#393D1B"
|
||||
TintColor="#393D1B"
|
||||
TintOpacity="0.6"/>
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarInformationalSeverityBackgroundBrush"
|
||||
FallbackColor="#34424d"
|
||||
TintColor="#34424d"
|
||||
TintOpacity="0.6"/>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
</ItemsControl.Resources>
|
||||
<ItemsControl.Transitions>
|
||||
<AddDeleteThemeTransition/>
|
||||
</ItemsControl.Transitions>
|
||||
</ItemsControl>
|
||||
|
||||
<Border
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Snap.Hutao.View;
|
||||
/// <summary>
|
||||
/// 信息条视图
|
||||
/// </summary>
|
||||
[DependencyProperty("InfoBars", typeof(ObservableCollection<InfoBar>))]
|
||||
[DependencyProperty("InfoBars", typeof(ObservableCollection<InfoBarOptions>))]
|
||||
internal sealed partial class InfoBarView : UserControl
|
||||
{
|
||||
private readonly IInfoBarService infoBarService;
|
||||
@@ -35,4 +35,9 @@ internal sealed partial class InfoBarView : UserControl
|
||||
{
|
||||
LocalSetting.Set(SettingKeys.IsInfoBarToggleChecked, ((ToggleButton)sender).IsChecked ?? false);
|
||||
}
|
||||
|
||||
private void OnInfoBarClosed(InfoBar sender, InfoBarClosedEventArgs args)
|
||||
{
|
||||
InfoBars.Remove((InfoBarOptions)sender.DataContext);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user