mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Compare commits
23 Commits
feat/Shell
...
feat/daily
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df7f685a3c | ||
|
|
9d47082f47 | ||
|
|
cd4516d9a7 | ||
|
|
f7e94fe2f2 | ||
|
|
e93802d5a5 | ||
|
|
370f2fe1f7 | ||
|
|
c6f747a89b | ||
|
|
cf431719df | ||
|
|
c36c15f9be | ||
|
|
f80a63f557 | ||
|
|
36376f5af6 | ||
|
|
2c057458a3 | ||
|
|
f0f50e0e30 | ||
|
|
b834daef93 | ||
|
|
ff10543c21 | ||
|
|
a55b25ae53 | ||
|
|
c0fbb823d4 | ||
|
|
4306af94be | ||
|
|
dfc83d4a34 | ||
|
|
c6a47eb7be | ||
|
|
7413a81ff4 | ||
|
|
24d143ea9f | ||
|
|
9f6611cd20 |
10
build.cake
10
build.cake
@@ -11,6 +11,15 @@ var version = "version";
|
|||||||
var repoDir = "repoDir";
|
var repoDir = "repoDir";
|
||||||
var outputPath = "outputPath";
|
var outputPath = "outputPath";
|
||||||
|
|
||||||
|
// Extension
|
||||||
|
|
||||||
|
static ProcessArgumentBuilder AppendIf(this ProcessArgumentBuilder builder, string text, bool condition)
|
||||||
|
{
|
||||||
|
return condition ? builder.Append(text) : builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Properties
|
||||||
|
|
||||||
string solution
|
string solution
|
||||||
{
|
{
|
||||||
get => System.IO.Path.Combine(repoDir, "src", "Snap.Hutao", "Snap.Hutao.sln");
|
get => System.IO.Path.Combine(repoDir, "src", "Snap.Hutao", "Snap.Hutao.sln");
|
||||||
@@ -157,6 +166,7 @@ Task("Build binary package")
|
|||||||
.Append("/p:AppxPackageSigningEnabled=false")
|
.Append("/p:AppxPackageSigningEnabled=false")
|
||||||
.Append("/p:AppxBundle=Never")
|
.Append("/p:AppxBundle=Never")
|
||||||
.Append("/p:AppxPackageOutput=" + outputPath)
|
.Append("/p:AppxPackageOutput=" + outputPath)
|
||||||
|
.AppendIf("/p:AlphaConstants=IS_ALPHA_BUILD", !AppVeyor.IsRunningOnAppVeyor)
|
||||||
};
|
};
|
||||||
|
|
||||||
DotNetBuild(project, settings);
|
DotNetBuild(project, settings);
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ public sealed partial class App : Application
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
System.Diagnostics.Debug.WriteLine(ex);
|
Debug.WriteLine(ex);
|
||||||
Process.GetCurrentProcess().Kill();
|
Process.GetCurrentProcess().Kill();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,12 +63,12 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
|
protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
|
||||||
{
|
{
|
||||||
if (context.ItemCount == 0)
|
if (context.ItemCount is 0)
|
||||||
{
|
{
|
||||||
return new Size(availableSize.Width, 0);
|
return new Size(availableSize.Width, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((context.RealizationRect.Width == 0) && (context.RealizationRect.Height == 0))
|
if ((context.RealizationRect.Width is 0) && (context.RealizationRect.Height is 0))
|
||||||
{
|
{
|
||||||
return new Size(availableSize.Width, 0.0f);
|
return new Size(availableSize.Width, 0.0f);
|
||||||
}
|
}
|
||||||
|
|||||||
25
src/Snap.Hutao/Snap.Hutao/Control/Layout/WrapItem.cs
Normal file
25
src/Snap.Hutao/Snap.Hutao/Control/Layout/WrapItem.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// Licensed to the .NET Fou// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
using Windows.Foundation;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Control.Layout;
|
||||||
|
|
||||||
|
internal sealed class WrapItem
|
||||||
|
{
|
||||||
|
public static Point EmptyPosition { get; } = new(float.NegativeInfinity, float.NegativeInfinity);
|
||||||
|
|
||||||
|
public WrapItem(int index)
|
||||||
|
{
|
||||||
|
Index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Index { get; }
|
||||||
|
|
||||||
|
public Size Size { get; set; } = Size.Empty;
|
||||||
|
|
||||||
|
public Point Position { get; set; } = EmptyPosition;
|
||||||
|
|
||||||
|
public UIElement? Element { get; set; }
|
||||||
|
}
|
||||||
220
src/Snap.Hutao/Snap.Hutao/Control/Layout/WrapLayout.cs
Normal file
220
src/Snap.Hutao/Snap.Hutao/Control/Layout/WrapLayout.cs
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using Windows.Foundation;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Control.Layout;
|
||||||
|
|
||||||
|
[DependencyProperty("HorizontalSpacing", typeof(double), 0D, nameof(LayoutPropertyChanged))]
|
||||||
|
[DependencyProperty("VerticalSpacing", typeof(double), 0D, nameof(LayoutPropertyChanged))]
|
||||||
|
internal sealed partial class WrapLayout : VirtualizingLayout
|
||||||
|
{
|
||||||
|
protected override void InitializeForContextCore(VirtualizingLayoutContext context)
|
||||||
|
{
|
||||||
|
context.LayoutState = new WrapLayoutState(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UninitializeForContextCore(VirtualizingLayoutContext context)
|
||||||
|
{
|
||||||
|
context.LayoutState = default;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnItemsChangedCore(VirtualizingLayoutContext context, object source, NotifyCollectionChangedEventArgs args)
|
||||||
|
{
|
||||||
|
WrapLayoutState state = (WrapLayoutState)context.LayoutState;
|
||||||
|
|
||||||
|
switch (args.Action)
|
||||||
|
{
|
||||||
|
case NotifyCollectionChangedAction.Add:
|
||||||
|
state.RemoveFromIndex(args.NewStartingIndex);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NotifyCollectionChangedAction.Move:
|
||||||
|
int minIndex = Math.Min(args.NewStartingIndex, args.OldStartingIndex);
|
||||||
|
state.RemoveFromIndex(minIndex);
|
||||||
|
state.RecycleElementAt(args.OldStartingIndex);
|
||||||
|
state.RecycleElementAt(args.NewStartingIndex);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NotifyCollectionChangedAction.Remove:
|
||||||
|
state.RemoveFromIndex(args.OldStartingIndex);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NotifyCollectionChangedAction.Replace:
|
||||||
|
state.RemoveFromIndex(args.NewStartingIndex);
|
||||||
|
state.RecycleElementAt(args.NewStartingIndex);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NotifyCollectionChangedAction.Reset:
|
||||||
|
state.Clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnItemsChangedCore(context, source, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
|
||||||
|
{
|
||||||
|
if (context.ItemCount is 0)
|
||||||
|
{
|
||||||
|
return new Size(availableSize.Width, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((context.RealizationRect.Width is 0) && (context.RealizationRect.Height is 0))
|
||||||
|
{
|
||||||
|
return new Size(availableSize.Width, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
Size spacing = new(HorizontalSpacing, VerticalSpacing);
|
||||||
|
|
||||||
|
WrapLayoutState state = (WrapLayoutState)context.LayoutState;
|
||||||
|
|
||||||
|
if (spacing != state.Spacing || state.AvailableWidth != availableSize.Width)
|
||||||
|
{
|
||||||
|
state.ClearPositions();
|
||||||
|
state.Spacing = spacing;
|
||||||
|
state.AvailableWidth = availableSize.Width;
|
||||||
|
}
|
||||||
|
|
||||||
|
double currentHeight = 0;
|
||||||
|
Point itemPosition = default;
|
||||||
|
for (int i = 0; i < context.ItemCount; ++i)
|
||||||
|
{
|
||||||
|
bool itemMeasured = false;
|
||||||
|
WrapItem item = state.GetItemAt(i);
|
||||||
|
if (item.Size == Size.Empty)
|
||||||
|
{
|
||||||
|
item.Element = context.GetOrCreateElementAt(i);
|
||||||
|
item.Element.Measure(availableSize);
|
||||||
|
item.Size = item.Element.DesiredSize;
|
||||||
|
itemMeasured = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Size itemSize = item.Size;
|
||||||
|
|
||||||
|
if (item.Position == WrapItem.EmptyPosition)
|
||||||
|
{
|
||||||
|
if (availableSize.Width < itemPosition.X + itemSize.Width)
|
||||||
|
{
|
||||||
|
// New Row
|
||||||
|
itemPosition.X = 0;
|
||||||
|
itemPosition.Y += currentHeight + spacing.Height;
|
||||||
|
currentHeight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.Position = itemPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
itemPosition = item.Position;
|
||||||
|
|
||||||
|
double bottom = itemPosition.Y + itemSize.Height;
|
||||||
|
if (bottom < context.RealizationRect.Top)
|
||||||
|
{
|
||||||
|
// Item is "above" the bounds
|
||||||
|
if (item.Element is not null)
|
||||||
|
{
|
||||||
|
context.RecycleElement(item.Element);
|
||||||
|
item.Element = default;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (itemPosition.Y > context.RealizationRect.Bottom)
|
||||||
|
{
|
||||||
|
// Item is "below" the bounds.
|
||||||
|
if (item.Element is not null)
|
||||||
|
{
|
||||||
|
context.RecycleElement(item.Element);
|
||||||
|
item.Element = default;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't need to measure anything below the bounds
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (!itemMeasured)
|
||||||
|
{
|
||||||
|
// Always measure elements that are within the bounds
|
||||||
|
item.Element = context.GetOrCreateElementAt(i);
|
||||||
|
item.Element.Measure(availableSize);
|
||||||
|
|
||||||
|
itemSize = item.Element.DesiredSize;
|
||||||
|
if (itemSize != item.Size)
|
||||||
|
{
|
||||||
|
// this item changed size; we need to recalculate layout for everything after this
|
||||||
|
state.RemoveFromIndex(i + 1);
|
||||||
|
item.Size = itemSize;
|
||||||
|
|
||||||
|
// did the change make it go into the new row?
|
||||||
|
if (availableSize.Width < itemPosition.X + itemSize.Width)
|
||||||
|
{
|
||||||
|
// New Row
|
||||||
|
itemPosition.X = 0;
|
||||||
|
itemPosition.Y += currentHeight + spacing.Height;
|
||||||
|
currentHeight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.Position = itemPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
itemPosition.X += itemSize.Width + spacing.Width;
|
||||||
|
currentHeight = Math.Max(itemSize.Height, currentHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Size(double.IsInfinity(availableSize.Width) ? 0 : Math.Ceiling(availableSize.Width), state.GetHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize)
|
||||||
|
{
|
||||||
|
if (context.ItemCount > 0)
|
||||||
|
{
|
||||||
|
WrapLayoutState state = (WrapLayoutState)context.LayoutState;
|
||||||
|
|
||||||
|
for (int i = 0; i < context.ItemCount; ++i)
|
||||||
|
{
|
||||||
|
if (!ArrangeItem(context, state.GetItemAt(i)))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalSize;
|
||||||
|
|
||||||
|
static bool ArrangeItem(VirtualizingLayoutContext context, WrapItem item)
|
||||||
|
{
|
||||||
|
if (item.Size == Size.Empty || item.Position == WrapItem.EmptyPosition)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Size size = item.Size;
|
||||||
|
Point position = item.Position;
|
||||||
|
|
||||||
|
if (context.RealizationRect.Top <= position.Y + size.Height && position.Y <= context.RealizationRect.Bottom)
|
||||||
|
{
|
||||||
|
// place the item
|
||||||
|
UIElement child = context.GetOrCreateElementAt(item.Index);
|
||||||
|
child.Arrange(new Rect(position, size));
|
||||||
|
}
|
||||||
|
else if (position.Y > context.RealizationRect.Bottom)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LayoutPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (d is WrapLayout layout)
|
||||||
|
{
|
||||||
|
layout.InvalidateMeasure();
|
||||||
|
layout.InvalidateArrange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
112
src/Snap.Hutao/Snap.Hutao/Control/Layout/WrapLayoutState.cs
Normal file
112
src/Snap.Hutao/Snap.Hutao/Control/Layout/WrapLayoutState.cs
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Windows.Foundation;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Control.Layout;
|
||||||
|
|
||||||
|
internal sealed class WrapLayoutState
|
||||||
|
{
|
||||||
|
private readonly List<WrapItem> items = [];
|
||||||
|
private readonly VirtualizingLayoutContext context;
|
||||||
|
|
||||||
|
public WrapLayoutState(VirtualizingLayoutContext context)
|
||||||
|
{
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Orientation Orientation { get; private set; }
|
||||||
|
|
||||||
|
public Size Spacing { get; set; }
|
||||||
|
|
||||||
|
public double AvailableWidth { get; set; }
|
||||||
|
|
||||||
|
public WrapItem GetItemAt(int index)
|
||||||
|
{
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
throw new IndexOutOfRangeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index <= (items.Count - 1))
|
||||||
|
{
|
||||||
|
return items[index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WrapItem item = new(index);
|
||||||
|
items.Add(item);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < items.Count; i++)
|
||||||
|
{
|
||||||
|
RecycleElementAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
items.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveFromIndex(int index)
|
||||||
|
{
|
||||||
|
if (index >= items.Count)
|
||||||
|
{
|
||||||
|
// Item was added/removed but we haven't realized that far yet
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int numToRemove = items.Count - index;
|
||||||
|
items.RemoveRange(index, numToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearPositions()
|
||||||
|
{
|
||||||
|
foreach (ref readonly WrapItem item in CollectionsMarshal.AsSpan(items))
|
||||||
|
{
|
||||||
|
item.Position = WrapItem.EmptyPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double GetHeight()
|
||||||
|
{
|
||||||
|
if (items.Count is 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Point? lastPosition = default;
|
||||||
|
double maxHeight = 0;
|
||||||
|
|
||||||
|
Span<WrapItem> itemSpan = CollectionsMarshal.AsSpan(items);
|
||||||
|
for (int i = items.Count - 1; i >= 0; --i)
|
||||||
|
{
|
||||||
|
ref readonly WrapItem item = ref itemSpan[i];
|
||||||
|
|
||||||
|
if (item.Position == WrapItem.EmptyPosition || item.Size == Size.Empty)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastPosition is not null && lastPosition.Value.Y > item.Position.Y)
|
||||||
|
{
|
||||||
|
// This is a row above the last item.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastPosition = item.Position;
|
||||||
|
maxHeight = Math.Max(maxHeight, item.Size.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastPosition?.Y + maxHeight ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RecycleElementAt(int index)
|
||||||
|
{
|
||||||
|
context.RecycleElement(context.GetOrCreateElementAt(index));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,6 +44,7 @@ internal sealed partial class AppActivation : IAppActivation, IAppActivationActi
|
|||||||
private readonly IServiceProvider serviceProvider;
|
private readonly IServiceProvider serviceProvider;
|
||||||
private readonly ICurrentXamlWindowReference currentWindowReference;
|
private readonly ICurrentXamlWindowReference currentWindowReference;
|
||||||
private readonly ITaskContext taskContext;
|
private readonly ITaskContext taskContext;
|
||||||
|
|
||||||
private readonly SemaphoreSlim activateSemaphore = new(1);
|
private readonly SemaphoreSlim activateSemaphore = new(1);
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -65,16 +66,24 @@ internal sealed partial class AppActivation : IAppActivation, IAppActivationActi
|
|||||||
serviceProvider.GetRequiredService<PrivateNamedPipeServer>().RunAsync().SafeForget();
|
serviceProvider.GetRequiredService<PrivateNamedPipeServer>().RunAsync().SafeForget();
|
||||||
ToastNotificationManagerCompat.OnActivated += NotificationActivate;
|
ToastNotificationManagerCompat.OnActivated += NotificationActivate;
|
||||||
|
|
||||||
serviceProvider.GetRequiredService<HotKeyOptions>().RegisterAll();
|
using (activateSemaphore.Enter())
|
||||||
if (serviceProvider.GetRequiredService<AppOptions>().IsNotifyIconEnabled)
|
|
||||||
{
|
{
|
||||||
XamlWindowLifetime.ApplicationLaunchedWithNotifyIcon = true;
|
serviceProvider.GetRequiredService<HotKeyOptions>().RegisterAll();
|
||||||
serviceProvider.GetRequiredService<App>().DispatcherShutdownMode = DispatcherShutdownMode.OnExplicitShutdown;
|
if (UnsafeLocalSetting.Get(SettingKeys.Major1Minor10Revision0GuideState, GuideState.Language) < GuideState.Completed)
|
||||||
_ = serviceProvider.GetRequiredService<NotifyIconController>();
|
{
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
serviceProvider.GetRequiredService<IScheduleTaskInterop>().UnregisterAllTasks();
|
if (serviceProvider.GetRequiredService<AppOptions>().IsNotifyIconEnabled)
|
||||||
serviceProvider.GetRequiredService<IQuartzService>().StartAsync(default).SafeForget();
|
{
|
||||||
|
XamlWindowLifetime.ApplicationLaunchedWithNotifyIcon = true;
|
||||||
|
serviceProvider.GetRequiredService<App>().DispatcherShutdownMode = DispatcherShutdownMode.OnExplicitShutdown;
|
||||||
|
_ = serviceProvider.GetRequiredService<NotifyIconController>();
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceProvider.GetRequiredService<IScheduleTaskInterop>().UnregisterAllTasks();
|
||||||
|
serviceProvider.GetRequiredService<IQuartzService>().StartAsync(default).SafeForget();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
@@ -172,7 +181,6 @@ internal sealed partial class AppActivation : IAppActivation, IAppActivationActi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's the first time launch, show the guide window anyway.
|
|
||||||
if (UnsafeLocalSetting.Get(SettingKeys.Major1Minor10Revision0GuideState, GuideState.Language) < GuideState.Completed)
|
if (UnsafeLocalSetting.Get(SettingKeys.Major1Minor10Revision0GuideState, GuideState.Language) < GuideState.Completed)
|
||||||
{
|
{
|
||||||
await taskContext.SwitchToMainThreadAsync();
|
await taskContext.SwitchToMainThreadAsync();
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ internal static class SemaphoreSlimExtension
|
|||||||
}
|
}
|
||||||
catch (ObjectDisposedException ex)
|
catch (ObjectDisposedException ex)
|
||||||
{
|
{
|
||||||
ThrowHelper.OperationCanceled(SH.CoreThreadingSemaphoreSlimDisposed, ex);
|
HutaoException.OperationCanceled(SH.CoreThreadingSemaphoreSlimDisposed, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SemaphoreSlimToken(semaphoreSlim);
|
return new SemaphoreSlimToken(semaphoreSlim);
|
||||||
@@ -29,7 +29,7 @@ internal static class SemaphoreSlimExtension
|
|||||||
}
|
}
|
||||||
catch (ObjectDisposedException ex)
|
catch (ObjectDisposedException ex)
|
||||||
{
|
{
|
||||||
ThrowHelper.OperationCanceled(SH.CoreThreadingSemaphoreSlimDisposed, ex);
|
HutaoException.OperationCanceled(SH.CoreThreadingSemaphoreSlimDisposed, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SemaphoreSlimToken(semaphoreSlim);
|
return new SemaphoreSlimToken(semaphoreSlim);
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
@@ -1568,6 +1568,12 @@
|
|||||||
<data name="ViewModelCultivationProjectInvalidName" xml:space="preserve">
|
<data name="ViewModelCultivationProjectInvalidName" xml:space="preserve">
|
||||||
<value>不能添加名称无效的计划</value>
|
<value>不能添加名称无效的计划</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ViewModelCultivationRemoveProjectContent" xml:space="preserve">
|
||||||
|
<value>此操作不可逆,此计划的养成物品与背包材料将会丢失</value>
|
||||||
|
</data>
|
||||||
|
<data name="ViewModelCultivationRemoveProjectTitle" xml:space="preserve">
|
||||||
|
<value>确认要删除当前计划吗?</value>
|
||||||
|
</data>
|
||||||
<data name="ViewModelDailyNoteConfigWebhookUrlComplete" xml:space="preserve">
|
<data name="ViewModelDailyNoteConfigWebhookUrlComplete" xml:space="preserve">
|
||||||
<value>实时便笺 Webhook Url 配置成功</value>
|
<value>实时便笺 Webhook Url 配置成功</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1988,6 +1994,9 @@
|
|||||||
<data name="ViewPageDailyNoteSettingRefreshHeader" xml:space="preserve">
|
<data name="ViewPageDailyNoteSettingRefreshHeader" xml:space="preserve">
|
||||||
<value>刷新</value>
|
<value>刷新</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ViewPageDailyNoteSettingRefreshNotifyIconDisabledHint" xml:space="preserve">
|
||||||
|
<value>未启用通知区域图标,自动刷新将不会执行</value>
|
||||||
|
</data>
|
||||||
<data name="ViewPageDailyNoteSlientModeDescription" xml:space="preserve">
|
<data name="ViewPageDailyNoteSlientModeDescription" xml:space="preserve">
|
||||||
<value>在我游玩原神时不通知我</value>
|
<value>在我游玩原神时不通知我</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -3024,7 +3033,7 @@
|
|||||||
<value>武器资料</value>
|
<value>武器资料</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WebAnnouncementMatchPermanentActivityTime" xml:space="preserve">
|
<data name="WebAnnouncementMatchPermanentActivityTime" xml:space="preserve">
|
||||||
<value>(?:〓活动时间〓|〓任务开放时间〓).*?(\d\.\d)版本更新(?:完成|)后永久开放</value>
|
<value>(?:(?:〓活动时间〓|〓任务开放时间〓).*?(\d\.\d)版本更新(?:完成|)|&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;)后永久开放</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WebAnnouncementMatchPersistentActivityTime" xml:space="preserve">
|
<data name="WebAnnouncementMatchPersistentActivityTime" xml:space="preserve">
|
||||||
<value>〓活动时间〓.*?(\d\.\d)版本期间持续开放</value>
|
<value>〓活动时间〓.*?(\d\.\d)版本期间持续开放</value>
|
||||||
@@ -3245,6 +3254,9 @@
|
|||||||
<data name="WebResponseRequestExceptionFormat" xml:space="preserve">
|
<data name="WebResponseRequestExceptionFormat" xml:space="preserve">
|
||||||
<value>[{0}] 中的 [{1}] 网络请求异常,请稍后再试</value>
|
<value>[{0}] 中的 [{1}] 网络请求异常,请稍后再试</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="WebResponseSignInErrorHint" xml:space="preserve">
|
||||||
|
<value>登录失败,请前往 HoYoLAB 初始化账号,原始消息:{0}</value>
|
||||||
|
</data>
|
||||||
<data name="WindowIdentifyMonitorHeader" xml:space="preserve">
|
<data name="WindowIdentifyMonitorHeader" xml:space="preserve">
|
||||||
<value>显示器编号</value>
|
<value>显示器编号</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -152,6 +152,8 @@ internal sealed partial class AnnouncementService : IAnnouncementService
|
|||||||
announcement.StartTime = versionStartTime;
|
announcement.StartTime = versionStartTime;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
announcement.StartTime = UnsafeDateTimeOffset.ParseDateTime(permanent.Groups[2].ValueSpan, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AnnouncementRegex.PersistentActivityAfterUpdateTimeRegex.Match(announcement.Content) is { Success: true } persistent)
|
if (AnnouncementRegex.PersistentActivityAfterUpdateTimeRegex.Match(announcement.Content) is { Success: true } persistent)
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient<U
|
|||||||
DailyNoteEntry newEntry = DailyNoteEntry.From(userAndUid);
|
DailyNoteEntry newEntry = DailyNoteEntry.From(userAndUid);
|
||||||
|
|
||||||
Web.Response.Response<WebDailyNote> dailyNoteResponse;
|
Web.Response.Response<WebDailyNote> dailyNoteResponse;
|
||||||
|
DailyNoteMetadataContext context;
|
||||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||||
{
|
{
|
||||||
IGameRecordClient gameRecordClient = scope.ServiceProvider
|
IGameRecordClient gameRecordClient = scope.ServiceProvider
|
||||||
@@ -63,6 +64,8 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient<U
|
|||||||
dailyNoteResponse = await gameRecordClient
|
dailyNoteResponse = await gameRecordClient
|
||||||
.GetDailyNoteAsync(userAndUid, token)
|
.GetDailyNoteAsync(userAndUid, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
context = await scope.GetRequiredService<IMetadataService>().GetContextAsync<DailyNoteMetadataContext>(token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dailyNoteResponse.IsOk())
|
if (dailyNoteResponse.IsOk())
|
||||||
@@ -71,6 +74,7 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient<U
|
|||||||
}
|
}
|
||||||
|
|
||||||
newEntry.UserGameRole = userService.GetUserGameRoleByUid(roleUid);
|
newEntry.UserGameRole = userService.GetUserGameRoleByUid(roleUid);
|
||||||
|
newEntry.ArchonQuestView = DailyNoteArchonQuestView.Create(newEntry.DailyNote, context.Chapters);
|
||||||
await dailyNoteDbService.AddDailyNoteEntryAsync(newEntry, token).ConfigureAwait(false);
|
await dailyNoteDbService.AddDailyNoteEntryAsync(newEntry, token).ConfigureAwait(false);
|
||||||
|
|
||||||
newEntry.User = userAndUid.User;
|
newEntry.User = userAndUid.User;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ internal static class SupportedCultures
|
|||||||
/*ToNameValue(CultureInfo.GetCultureInfo("de")),*/
|
/*ToNameValue(CultureInfo.GetCultureInfo("de")),*/
|
||||||
ToNameValue(CultureInfo.GetCultureInfo("en")),
|
ToNameValue(CultureInfo.GetCultureInfo("en")),
|
||||||
/*ToNameValue(CultureInfo.GetCultureInfo("es")),*/
|
/*ToNameValue(CultureInfo.GetCultureInfo("es")),*/
|
||||||
/*ToNameValue(CultureInfo.GetCultureInfo("fr")),*/
|
ToNameValue(CultureInfo.GetCultureInfo("fr")),
|
||||||
ToNameValue(CultureInfo.GetCultureInfo("id")),
|
ToNameValue(CultureInfo.GetCultureInfo("id")),
|
||||||
/*ToNameValue(CultureInfo.GetCultureInfo("it")),*/
|
/*ToNameValue(CultureInfo.GetCultureInfo("it")),*/
|
||||||
ToNameValue(CultureInfo.GetCultureInfo("ja")),
|
ToNameValue(CultureInfo.GetCultureInfo("ja")),
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
<AppxBundle>Never</AppxBundle>
|
<AppxBundle>Never</AppxBundle>
|
||||||
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
|
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
|
||||||
<StartupObject>Snap.Hutao.Program</StartupObject>
|
<StartupObject>Snap.Hutao.Program</StartupObject>
|
||||||
<DefineConstants>$(DefineConstants);DISABLE_XAML_GENERATED_MAIN;DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION;DISABLE_XAML_GENERATED_BINDING_DEBUG_OUTPUT</DefineConstants>
|
<DefineConstants>$(DefineConstants);DISABLE_XAML_GENERATED_MAIN;DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION;DISABLE_XAML_GENERATED_BINDING_DEBUG_OUTPUT;$(AlphaConstants)</DefineConstants>
|
||||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
@@ -117,6 +117,7 @@
|
|||||||
<None Remove="Resource\BlurBackground.png" />
|
<None Remove="Resource\BlurBackground.png" />
|
||||||
<None Remove="Resource\Font\CascadiaMono.ttf" />
|
<None Remove="Resource\Font\CascadiaMono.ttf" />
|
||||||
<None Remove="Resource\Font\MiSans-Regular.ttf" />
|
<None Remove="Resource\Font\MiSans-Regular.ttf" />
|
||||||
|
<None Remove="Resource\GuideStaticResourceQualityComparison.png" />
|
||||||
<None Remove="Resource\HutaoIconSourceTransparentBackgroundGradient1.png" />
|
<None Remove="Resource\HutaoIconSourceTransparentBackgroundGradient1.png" />
|
||||||
<None Remove="Resource\Icon\UI_AchievementIcon_3_3.png" />
|
<None Remove="Resource\Icon\UI_AchievementIcon_3_3.png" />
|
||||||
<None Remove="Resource\Icon\UI_GachaShowPanel_Bg_Weapon.png" />
|
<None Remove="Resource\Icon\UI_GachaShowPanel_Bg_Weapon.png" />
|
||||||
@@ -216,6 +217,7 @@
|
|||||||
<AdditionalFiles Include="stylecop.json" />
|
<AdditionalFiles Include="stylecop.json" />
|
||||||
<AdditionalFiles Include="Resource\Localization\SH.resx" />
|
<AdditionalFiles Include="Resource\Localization\SH.resx" />
|
||||||
<AdditionalFiles Include="Resource\Localization\SH.en.resx" />
|
<AdditionalFiles Include="Resource\Localization\SH.en.resx" />
|
||||||
|
<AdditionalFiles Include="Resource\Localization\SH.fr.resx" />
|
||||||
<AdditionalFiles Include="Resource\Localization\SH.id.resx" />
|
<AdditionalFiles Include="Resource\Localization\SH.id.resx" />
|
||||||
<AdditionalFiles Include="Resource\Localization\SH.ja.resx" />
|
<AdditionalFiles Include="Resource\Localization\SH.ja.resx" />
|
||||||
<AdditionalFiles Include="Resource\Localization\SH.ko.resx" />
|
<AdditionalFiles Include="Resource\Localization\SH.ko.resx" />
|
||||||
@@ -265,6 +267,7 @@
|
|||||||
<Content Include="Resource\BlurBackground.png" />
|
<Content Include="Resource\BlurBackground.png" />
|
||||||
<Content Include="Resource\Font\CascadiaMono.ttf" />
|
<Content Include="Resource\Font\CascadiaMono.ttf" />
|
||||||
<Content Include="Resource\Font\MiSans-Regular.ttf" />
|
<Content Include="Resource\Font\MiSans-Regular.ttf" />
|
||||||
|
<Content Include="Resource\GuideStaticResourceQualityComparison.png" />
|
||||||
<Content Include="Resource\HutaoIconSourceTransparentBackgroundGradient1.png" />
|
<Content Include="Resource\HutaoIconSourceTransparentBackgroundGradient1.png" />
|
||||||
<Content Include="Resource\Icon\UI_AchievementIcon_3_3.png" />
|
<Content Include="Resource\Icon\UI_AchievementIcon_3_3.png" />
|
||||||
<Content Include="Resource\Icon\UI_GachaShowPanel_Bg_Weapon.png" />
|
<Content Include="Resource\Icon\UI_GachaShowPanel_Bg_Weapon.png" />
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
x:Class="Snap.Hutao.View.Guide.GuideView"
|
x:Class="Snap.Hutao.View.Guide.GuideView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:cw="using:CommunityToolkit.WinUI"
|
||||||
xmlns:cwc="using:CommunityToolkit.WinUI.Controls"
|
xmlns:cwc="using:CommunityToolkit.WinUI.Controls"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
@@ -210,28 +211,75 @@
|
|||||||
<RowDefinition Height="auto"/>
|
<RowDefinition Height="auto"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<StackPanel
|
<Grid
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Margin="16"
|
Margin="72"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center">
|
ColumnSpacing="32">
|
||||||
<TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Text="{shcm:ResourceString Name=ViewGuideStepStaticResourceSettingQualityHeader}"/>
|
<Grid.ColumnDefinitions>
|
||||||
<ListView
|
<ColumnDefinition/>
|
||||||
MinWidth="320"
|
<ColumnDefinition/>
|
||||||
Margin="0,8,0,32"
|
</Grid.ColumnDefinitions>
|
||||||
DisplayMemberPath="Name"
|
<cwc:ConstrainedBox Grid.Column="0" AspectRatio="1:1">
|
||||||
ItemsSource="{Binding StaticResourceOptions.ImageQualities}"
|
<Border cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
|
||||||
SelectedItem="{Binding StaticResourceOptions.ImageQuality, Mode=TwoWay}"/>
|
<Grid
|
||||||
<TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Text="{shcm:ResourceString Name=ViewGuideStepStaticResourceSettingMinimumHeader}"/>
|
BorderBrush="{x:Null}"
|
||||||
<ListView
|
BorderThickness="0"
|
||||||
MinWidth="320"
|
Style="{ThemeResource GridCardStyle}">
|
||||||
Margin="0,8,0,32"
|
<Grid.RowDefinitions>
|
||||||
DisplayMemberPath="Name"
|
<RowDefinition/>
|
||||||
ItemsSource="{Binding StaticResourceOptions.ImageArchives}"
|
<RowDefinition Height="auto"/>
|
||||||
SelectedItem="{Binding StaticResourceOptions.ImageArchive, Mode=TwoWay}"/>
|
</Grid.RowDefinitions>
|
||||||
|
<Grid Grid.Row="0">
|
||||||
<TextBlock Margin="0,16,0,0" Text="{Binding StaticResourceOptions.SizeInformationText, Mode=OneWay}"/>
|
<Image
|
||||||
</StackPanel>
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Source="ms-appx:///Resource/GuideStaticResourceQualityComparison.png"/>
|
||||||
|
<Rectangle
|
||||||
|
Width="2"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
Fill="White"/>
|
||||||
|
</Grid>
|
||||||
|
<Grid
|
||||||
|
Grid.Row="1"
|
||||||
|
Padding="16"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
Background="{ThemeResource ContentDialogBackground}"
|
||||||
|
BorderThickness="0,1,0,0"
|
||||||
|
CornerRadius="{ThemeResource ControlCornerRadiusBottom}"
|
||||||
|
Style="{ThemeResource GridCardStyle}">
|
||||||
|
<StackPanel HorizontalAlignment="Left" Orientation="Vertical">
|
||||||
|
<TextBlock Text="{shcm:ResourceString Name=ViewModelGuideStaticResourceQualityHigh}" TextAlignment="Left"/>
|
||||||
|
<TextBlock Text="233 KB" TextAlignment="Left"/>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel HorizontalAlignment="Right" Orientation="Vertical">
|
||||||
|
<TextBlock Text="{shcm:ResourceString Name=ViewModelGuideStaticResourceQualityRaw}" TextAlignment="Right"/>
|
||||||
|
<TextBlock Text="1030 KB" TextAlignment="Right"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</cwc:ConstrainedBox>
|
||||||
|
<StackPanel Grid.Column="1" VerticalAlignment="Top">
|
||||||
|
<TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Text="{shcm:ResourceString Name=ViewGuideStepStaticResourceSettingQualityHeader}"/>
|
||||||
|
<ListView
|
||||||
|
MinWidth="320"
|
||||||
|
Margin="0,8,0,32"
|
||||||
|
DisplayMemberPath="Name"
|
||||||
|
ItemsSource="{Binding StaticResourceOptions.ImageQualities}"
|
||||||
|
SelectedItem="{Binding StaticResourceOptions.ImageQuality, Mode=TwoWay}"/>
|
||||||
|
<TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Text="{shcm:ResourceString Name=ViewGuideStepStaticResourceSettingMinimumHeader}"/>
|
||||||
|
<ListView
|
||||||
|
MinWidth="320"
|
||||||
|
Margin="0,8,0,32"
|
||||||
|
DisplayMemberPath="Name"
|
||||||
|
ItemsSource="{Binding StaticResourceOptions.ImageArchives}"
|
||||||
|
SelectedItem="{Binding StaticResourceOptions.ImageArchive, Mode=TwoWay}"/>
|
||||||
|
<TextBlock Margin="0,16,0,0" Text="{Binding StaticResourceOptions.SizeInformationText, Mode=OneWay}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
|||||||
@@ -381,7 +381,7 @@
|
|||||||
ItemTemplate="{StaticResource InventoryItemTemplate}"
|
ItemTemplate="{StaticResource InventoryItemTemplate}"
|
||||||
ItemsSource="{Binding InventoryItems}">
|
ItemsSource="{Binding InventoryItems}">
|
||||||
<ItemsRepeater.Layout>
|
<ItemsRepeater.Layout>
|
||||||
<cwcont:WrapLayout HorizontalSpacing="12" VerticalSpacing="12"/>
|
<shcl:WrapLayout HorizontalSpacing="12" VerticalSpacing="12"/>
|
||||||
</ItemsRepeater.Layout>
|
</ItemsRepeater.Layout>
|
||||||
</ItemsRepeater>
|
</ItemsRepeater>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|||||||
@@ -507,6 +507,12 @@
|
|||||||
Text="{shcm:ResourceString Name=ViewPageDailyNoteSettingRefreshHeader}"/>
|
Text="{shcm:ResourceString Name=ViewPageDailyNoteSettingRefreshHeader}"/>
|
||||||
</cwcont:HeaderedContentControl.Header>
|
</cwcont:HeaderedContentControl.Header>
|
||||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||||
|
<InfoBar
|
||||||
|
Title="{shcm:ResourceString Name=ViewPageDailyNoteSettingRefreshNotifyIconDisabledHint}"
|
||||||
|
IsClosable="False"
|
||||||
|
IsOpen="True"
|
||||||
|
Severity="Warning"
|
||||||
|
Visibility="{Binding AppOptions.IsNotifyIconEnabled, Converter={StaticResource BoolToVisibilityRevertConverter}}"/>
|
||||||
<cwcont:SettingsCard
|
<cwcont:SettingsCard
|
||||||
Description="{shcm:ResourceString Name=ViewPageDailyNoteSettingAutoRefreshDescription}"
|
Description="{shcm:ResourceString Name=ViewPageDailyNoteSettingAutoRefreshDescription}"
|
||||||
Header="{shcm:ResourceString Name=ViewPageDailyNoteSettingAutoRefresh}"
|
Header="{shcm:ResourceString Name=ViewPageDailyNoteSettingAutoRefresh}"
|
||||||
|
|||||||
@@ -104,8 +104,10 @@
|
|||||||
</Border>
|
</Border>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<cwc:SwitchPresenter Grid.Row="1" Value="{Binding ElementName=ItemsPanelSelector, Path=Current}">
|
<cwc:SwitchPresenter
|
||||||
|
Grid.Row="1"
|
||||||
|
ContentTransitions="{ThemeResource EntranceThemeTransitions}"
|
||||||
|
Value="{Binding ElementName=ItemsPanelSelector, Path=Current}">
|
||||||
<cwc:Case Value="List">
|
<cwc:Case Value="List">
|
||||||
<Border Margin="16,0,16,16" cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
|
<Border Margin="16,0,16,16" cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
|
||||||
<Border Style="{ThemeResource AcrylicBorderCardStyle}">
|
<Border Style="{ThemeResource AcrylicBorderCardStyle}">
|
||||||
@@ -113,7 +115,7 @@
|
|||||||
DisplayMode="Inline"
|
DisplayMode="Inline"
|
||||||
IsPaneOpen="True"
|
IsPaneOpen="True"
|
||||||
OpenPaneLength="{StaticResource CompatSplitViewOpenPaneLength2}"
|
OpenPaneLength="{StaticResource CompatSplitViewOpenPaneLength2}"
|
||||||
PaneBackground="{StaticResource CardBackgroundFillColorSecondary}">
|
PaneBackground="{ThemeResource CardBackgroundFillColorSecondaryBrush}">
|
||||||
<SplitView.Pane>
|
<SplitView.Pane>
|
||||||
<ListView
|
<ListView
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
|||||||
@@ -218,7 +218,7 @@
|
|||||||
DisplayMode="Inline"
|
DisplayMode="Inline"
|
||||||
IsPaneOpen="True"
|
IsPaneOpen="True"
|
||||||
OpenPaneLength="{StaticResource CompatSplitViewOpenPaneLength}"
|
OpenPaneLength="{StaticResource CompatSplitViewOpenPaneLength}"
|
||||||
PaneBackground="{StaticResource CardBackgroundFillColorSecondary}">
|
PaneBackground="{ThemeResource CardBackgroundFillColorSecondaryBrush}">
|
||||||
<SplitView.Pane>
|
<SplitView.Pane>
|
||||||
<ListView
|
<ListView
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
|||||||
@@ -372,8 +372,13 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
|||||||
|
|
||||||
private void UpdateAchievementsFinishPercent()
|
private void UpdateAchievementsFinishPercent()
|
||||||
{
|
{
|
||||||
|
// 保存成就状态时,需要保持当前选择的成就分类
|
||||||
|
AchievementGoalView? currentSelectedAchievementGoal = SelectedAchievementGoal;
|
||||||
|
|
||||||
// 仅 读取成就列表 与 保存成就状态 时需要刷新成就进度
|
// 仅 读取成就列表 与 保存成就状态 时需要刷新成就进度
|
||||||
AchievementFinishPercent.Update(this);
|
AchievementFinishPercent.Update(this);
|
||||||
|
|
||||||
|
SelectedAchievementGoal = currentSelectedAchievementGoal;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("SaveAchievementCommand")]
|
[Command("SaveAchievementCommand")]
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Snap.Hutao.Factory.ContentDialog;
|
using Snap.Hutao.Factory.ContentDialog;
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
using Snap.Hutao.Service.Cultivation;
|
using Snap.Hutao.Service.Cultivation;
|
||||||
@@ -110,10 +111,17 @@ internal sealed partial class CultivationViewModel : Abstraction.ViewModel
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await cultivationService.RemoveProjectAsync(project).ConfigureAwait(false);
|
ContentDialogResult result = await contentDialogFactory
|
||||||
await taskContext.SwitchToMainThreadAsync();
|
.CreateForConfirmCancelAsync(SH.ViewModelCultivationRemoveProjectTitle, SH.ViewModelCultivationRemoveProjectContent)
|
||||||
ArgumentNullException.ThrowIfNull(Projects);
|
.ConfigureAwait(false);
|
||||||
SelectedProject = Projects.FirstOrDefault();
|
|
||||||
|
if (result is ContentDialogResult.Primary)
|
||||||
|
{
|
||||||
|
await cultivationService.RemoveProjectAsync(project).ConfigureAwait(false);
|
||||||
|
await taskContext.SwitchToMainThreadAsync();
|
||||||
|
ArgumentNullException.ThrowIfNull(Projects);
|
||||||
|
SelectedProject = Projects.FirstOrDefault();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async ValueTask UpdateEntryCollectionAsync(CultivateProject? project)
|
private async ValueTask UpdateEntryCollectionAsync(CultivateProject? project)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Snap.Hutao.Control.Extension;
|
|||||||
using Snap.Hutao.Core;
|
using Snap.Hutao.Core;
|
||||||
using Snap.Hutao.Factory.ContentDialog;
|
using Snap.Hutao.Factory.ContentDialog;
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
|
using Snap.Hutao.Service;
|
||||||
using Snap.Hutao.Service.DailyNote;
|
using Snap.Hutao.Service.DailyNote;
|
||||||
using Snap.Hutao.Service.Metadata;
|
using Snap.Hutao.Service.Metadata;
|
||||||
using Snap.Hutao.Service.Notification;
|
using Snap.Hutao.Service.Notification;
|
||||||
@@ -32,12 +33,15 @@ internal sealed partial class DailyNoteViewModel : Abstraction.ViewModel
|
|||||||
private readonly IInfoBarService infoBarService;
|
private readonly IInfoBarService infoBarService;
|
||||||
private readonly ITaskContext taskContext;
|
private readonly ITaskContext taskContext;
|
||||||
private readonly IUserService userService;
|
private readonly IUserService userService;
|
||||||
|
private readonly AppOptions appOptions;
|
||||||
|
|
||||||
private ObservableCollection<UserAndUid>? userAndUids;
|
private ObservableCollection<UserAndUid>? userAndUids;
|
||||||
private ObservableCollection<DailyNoteEntry>? dailyNoteEntries;
|
private ObservableCollection<DailyNoteEntry>? dailyNoteEntries;
|
||||||
|
|
||||||
public DailyNoteOptions DailyNoteOptions { get => dailyNoteOptions; }
|
public DailyNoteOptions DailyNoteOptions { get => dailyNoteOptions; }
|
||||||
|
|
||||||
|
public AppOptions AppOptions { get => appOptions; }
|
||||||
|
|
||||||
public IWebViewerSource VerifyUrlSource { get; } = new DailyNoteWebViewerSource();
|
public IWebViewerSource VerifyUrlSource { get; } = new DailyNoteWebViewerSource();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ internal sealed partial class TypedWishSummary : Wish
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string TotalOrangeFormatted
|
public string TotalOrangeFormatted
|
||||||
{
|
{
|
||||||
get => $"{TotalOrangePull} [{TotalOrangePercent,6:p2}]";
|
get => $"{TotalOrangePull} [{(TotalOrangePercent is double.NaN ? 0D : TotalOrangePercent),6:p2}]";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -74,7 +74,7 @@ internal sealed partial class TypedWishSummary : Wish
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string TotalPurpleFormatted
|
public string TotalPurpleFormatted
|
||||||
{
|
{
|
||||||
get => $"{TotalPurplePull} [{TotalPurplePercent,6:p2}]";
|
get => $"{TotalPurplePull} [{(TotalPurplePercent is double.NaN ? 0D : TotalPurplePercent),6:p2}]";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -82,7 +82,7 @@ internal sealed partial class TypedWishSummary : Wish
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string TotalBlueFormatted
|
public string TotalBlueFormatted
|
||||||
{
|
{
|
||||||
get => $"{TotalBluePull} [{TotalBluePercent,6:p2}]";
|
get => $"{TotalBluePull} [{(TotalBluePercent is double.NaN ? 0D : TotalBluePercent),6:p2}]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public ColorSegmentCollection PullPercentSegmentSource
|
public ColorSegmentCollection PullPercentSegmentSource
|
||||||
|
|||||||
@@ -49,10 +49,21 @@ internal class Response : ICommonResponse<Response>
|
|||||||
response.Message = SH.FormatWebResponseRefreshCookieHintFormat(response.Message);
|
response.Message = SH.FormatWebResponseRefreshCookieHintFormat(response.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch ((KnownReturnCode)response.ReturnCode)
|
||||||
|
{
|
||||||
|
case KnownReturnCode.PleaseLogin:
|
||||||
|
case KnownReturnCode.RET_TOKEN_INVALID:
|
||||||
|
response.Message = SH.FormatWebResponseRefreshCookieHintFormat(response.Message);
|
||||||
|
break;
|
||||||
|
case KnownReturnCode.SignInError:
|
||||||
|
response.Message = SH.FormatWebResponseSignInErrorHint(response.Message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Response<TData> CloneReturnCodeAndMessage<TData, TOther>(Response<TOther> response, [CallerMemberName] string callerName = default!)
|
public static Response<TData> CloneReturnCodeAndMessage<TData, TOther>(Response<TOther> response)
|
||||||
{
|
{
|
||||||
return new(response.ReturnCode, response.Message, default);
|
return new(response.ReturnCode, response.Message, default);
|
||||||
}
|
}
|
||||||
@@ -63,16 +74,14 @@ internal class Response : ICommonResponse<Response>
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
if (showInfoBar)
|
|
||||||
{
|
|
||||||
serviceProvider ??= Ioc.Default;
|
|
||||||
serviceProvider.GetRequiredService<IInfoBarService>().Error(ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
if (showInfoBar)
|
||||||
|
{
|
||||||
|
serviceProvider ??= Ioc.Default;
|
||||||
|
serviceProvider.GetRequiredService<IInfoBarService>().Error(ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
@@ -102,20 +111,12 @@ internal class Response<TData> : Response, ICommonResponse<Response<TData>>, IJs
|
|||||||
[MemberNotNullWhen(true, nameof(Data))]
|
[MemberNotNullWhen(true, nameof(Data))]
|
||||||
public override bool IsOk(bool showInfoBar = true, IServiceProvider? serviceProvider = null)
|
public override bool IsOk(bool showInfoBar = true, IServiceProvider? serviceProvider = null)
|
||||||
{
|
{
|
||||||
if (ReturnCode == 0)
|
bool result = base.IsOk(showInfoBar, serviceProvider);
|
||||||
|
if (result)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(Data);
|
ArgumentNullException.ThrowIfNull(Data);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
if (showInfoBar)
|
|
||||||
{
|
|
||||||
serviceProvider ??= Ioc.Default;
|
|
||||||
serviceProvider.GetRequiredService<IInfoBarService>().Error(ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return result;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user