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 outputPath = "outputPath";
|
||||
|
||||
// Extension
|
||||
|
||||
static ProcessArgumentBuilder AppendIf(this ProcessArgumentBuilder builder, string text, bool condition)
|
||||
{
|
||||
return condition ? builder.Append(text) : builder;
|
||||
}
|
||||
|
||||
// Properties
|
||||
|
||||
string solution
|
||||
{
|
||||
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:AppxBundle=Never")
|
||||
.Append("/p:AppxPackageOutput=" + outputPath)
|
||||
.AppendIf("/p:AlphaConstants=IS_ALPHA_BUILD", !AppVeyor.IsRunningOnAppVeyor)
|
||||
};
|
||||
|
||||
DotNetBuild(project, settings);
|
||||
|
||||
@@ -85,7 +85,7 @@ public sealed partial class App : Application
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(ex);
|
||||
Debug.WriteLine(ex);
|
||||
Process.GetCurrentProcess().Kill();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,12 +63,12 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
|
||||
/// <inheritdoc/>
|
||||
protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
|
||||
{
|
||||
if (context.ItemCount == 0)
|
||||
if (context.ItemCount is 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);
|
||||
}
|
||||
|
||||
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 ICurrentXamlWindowReference currentWindowReference;
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
private readonly SemaphoreSlim activateSemaphore = new(1);
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -65,7 +66,14 @@ internal sealed partial class AppActivation : IAppActivation, IAppActivationActi
|
||||
serviceProvider.GetRequiredService<PrivateNamedPipeServer>().RunAsync().SafeForget();
|
||||
ToastNotificationManagerCompat.OnActivated += NotificationActivate;
|
||||
|
||||
using (activateSemaphore.Enter())
|
||||
{
|
||||
serviceProvider.GetRequiredService<HotKeyOptions>().RegisterAll();
|
||||
if (UnsafeLocalSetting.Get(SettingKeys.Major1Minor10Revision0GuideState, GuideState.Language) < GuideState.Completed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (serviceProvider.GetRequiredService<AppOptions>().IsNotifyIconEnabled)
|
||||
{
|
||||
XamlWindowLifetime.ApplicationLaunchedWithNotifyIcon = true;
|
||||
@@ -76,6 +84,7 @@ internal sealed partial class AppActivation : IAppActivation, IAppActivationActi
|
||||
serviceProvider.GetRequiredService<IScheduleTaskInterop>().UnregisterAllTasks();
|
||||
serviceProvider.GetRequiredService<IQuartzService>().StartAsync(default).SafeForget();
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
|
||||
@@ -15,7 +15,7 @@ internal static class SemaphoreSlimExtension
|
||||
}
|
||||
catch (ObjectDisposedException ex)
|
||||
{
|
||||
ThrowHelper.OperationCanceled(SH.CoreThreadingSemaphoreSlimDisposed, ex);
|
||||
HutaoException.OperationCanceled(SH.CoreThreadingSemaphoreSlimDisposed, ex);
|
||||
}
|
||||
|
||||
return new SemaphoreSlimToken(semaphoreSlim);
|
||||
@@ -29,7 +29,7 @@ internal static class SemaphoreSlimExtension
|
||||
}
|
||||
catch (ObjectDisposedException ex)
|
||||
{
|
||||
ThrowHelper.OperationCanceled(SH.CoreThreadingSemaphoreSlimDisposed, ex);
|
||||
HutaoException.OperationCanceled(SH.CoreThreadingSemaphoreSlimDisposed, ex);
|
||||
}
|
||||
|
||||
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">
|
||||
<value>不能添加名称无效的计划</value>
|
||||
</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">
|
||||
<value>实时便笺 Webhook Url 配置成功</value>
|
||||
</data>
|
||||
@@ -1988,6 +1994,9 @@
|
||||
<data name="ViewPageDailyNoteSettingRefreshHeader" xml:space="preserve">
|
||||
<value>刷新</value>
|
||||
</data>
|
||||
<data name="ViewPageDailyNoteSettingRefreshNotifyIconDisabledHint" xml:space="preserve">
|
||||
<value>未启用通知区域图标,自动刷新将不会执行</value>
|
||||
</data>
|
||||
<data name="ViewPageDailyNoteSlientModeDescription" xml:space="preserve">
|
||||
<value>在我游玩原神时不通知我</value>
|
||||
</data>
|
||||
@@ -3024,7 +3033,7 @@
|
||||
<value>武器资料</value>
|
||||
</data>
|
||||
<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 name="WebAnnouncementMatchPersistentActivityTime" xml:space="preserve">
|
||||
<value>〓活动时间〓.*?(\d\.\d)版本期间持续开放</value>
|
||||
@@ -3245,6 +3254,9 @@
|
||||
<data name="WebResponseRequestExceptionFormat" xml:space="preserve">
|
||||
<value>[{0}] 中的 [{1}] 网络请求异常,请稍后再试</value>
|
||||
</data>
|
||||
<data name="WebResponseSignInErrorHint" xml:space="preserve">
|
||||
<value>登录失败,请前往 HoYoLAB 初始化账号,原始消息:{0}</value>
|
||||
</data>
|
||||
<data name="WindowIdentifyMonitorHeader" xml:space="preserve">
|
||||
<value>显示器编号</value>
|
||||
</data>
|
||||
|
||||
@@ -152,6 +152,8 @@ internal sealed partial class AnnouncementService : IAnnouncementService
|
||||
announcement.StartTime = versionStartTime;
|
||||
continue;
|
||||
}
|
||||
|
||||
announcement.StartTime = UnsafeDateTimeOffset.ParseDateTime(permanent.Groups[2].ValueSpan, offset);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
Web.Response.Response<WebDailyNote> dailyNoteResponse;
|
||||
DailyNoteMetadataContext context;
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
IGameRecordClient gameRecordClient = scope.ServiceProvider
|
||||
@@ -63,6 +64,8 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient<U
|
||||
dailyNoteResponse = await gameRecordClient
|
||||
.GetDailyNoteAsync(userAndUid, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
context = await scope.GetRequiredService<IMetadataService>().GetContextAsync<DailyNoteMetadataContext>(token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (dailyNoteResponse.IsOk())
|
||||
@@ -71,6 +74,7 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient<U
|
||||
}
|
||||
|
||||
newEntry.UserGameRole = userService.GetUserGameRoleByUid(roleUid);
|
||||
newEntry.ArchonQuestView = DailyNoteArchonQuestView.Create(newEntry.DailyNote, context.Chapters);
|
||||
await dailyNoteDbService.AddDailyNoteEntryAsync(newEntry, token).ConfigureAwait(false);
|
||||
|
||||
newEntry.User = userAndUid.User;
|
||||
|
||||
@@ -15,7 +15,7 @@ internal static class SupportedCultures
|
||||
/*ToNameValue(CultureInfo.GetCultureInfo("de")),*/
|
||||
ToNameValue(CultureInfo.GetCultureInfo("en")),
|
||||
/*ToNameValue(CultureInfo.GetCultureInfo("es")),*/
|
||||
/*ToNameValue(CultureInfo.GetCultureInfo("fr")),*/
|
||||
ToNameValue(CultureInfo.GetCultureInfo("fr")),
|
||||
ToNameValue(CultureInfo.GetCultureInfo("id")),
|
||||
/*ToNameValue(CultureInfo.GetCultureInfo("it")),*/
|
||||
ToNameValue(CultureInfo.GetCultureInfo("ja")),
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<AppxBundle>Never</AppxBundle>
|
||||
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
|
||||
<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>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>embedded</DebugType>
|
||||
@@ -117,6 +117,7 @@
|
||||
<None Remove="Resource\BlurBackground.png" />
|
||||
<None Remove="Resource\Font\CascadiaMono.ttf" />
|
||||
<None Remove="Resource\Font\MiSans-Regular.ttf" />
|
||||
<None Remove="Resource\GuideStaticResourceQualityComparison.png" />
|
||||
<None Remove="Resource\HutaoIconSourceTransparentBackgroundGradient1.png" />
|
||||
<None Remove="Resource\Icon\UI_AchievementIcon_3_3.png" />
|
||||
<None Remove="Resource\Icon\UI_GachaShowPanel_Bg_Weapon.png" />
|
||||
@@ -216,6 +217,7 @@
|
||||
<AdditionalFiles Include="stylecop.json" />
|
||||
<AdditionalFiles Include="Resource\Localization\SH.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.ja.resx" />
|
||||
<AdditionalFiles Include="Resource\Localization\SH.ko.resx" />
|
||||
@@ -265,6 +267,7 @@
|
||||
<Content Include="Resource\BlurBackground.png" />
|
||||
<Content Include="Resource\Font\CascadiaMono.ttf" />
|
||||
<Content Include="Resource\Font\MiSans-Regular.ttf" />
|
||||
<Content Include="Resource\GuideStaticResourceQualityComparison.png" />
|
||||
<Content Include="Resource\HutaoIconSourceTransparentBackgroundGradient1.png" />
|
||||
<Content Include="Resource\Icon\UI_AchievementIcon_3_3.png" />
|
||||
<Content Include="Resource\Icon\UI_GachaShowPanel_Bg_Weapon.png" />
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
x:Class="Snap.Hutao.View.Guide.GuideView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:cw="using:CommunityToolkit.WinUI"
|
||||
xmlns:cwc="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
@@ -210,11 +211,58 @@
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel
|
||||
<Grid
|
||||
Grid.Row="0"
|
||||
Margin="16"
|
||||
Margin="72"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">
|
||||
ColumnSpacing="32">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<cwc:ConstrainedBox Grid.Column="0" AspectRatio="1:1">
|
||||
<Border cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
|
||||
<Grid
|
||||
BorderBrush="{x:Null}"
|
||||
BorderThickness="0"
|
||||
Style="{ThemeResource GridCardStyle}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0">
|
||||
<Image
|
||||
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"
|
||||
@@ -229,9 +277,9 @@
|
||||
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
|
||||
Grid.Row="1"
|
||||
|
||||
@@ -381,7 +381,7 @@
|
||||
ItemTemplate="{StaticResource InventoryItemTemplate}"
|
||||
ItemsSource="{Binding InventoryItems}">
|
||||
<ItemsRepeater.Layout>
|
||||
<cwcont:WrapLayout HorizontalSpacing="12" VerticalSpacing="12"/>
|
||||
<shcl:WrapLayout HorizontalSpacing="12" VerticalSpacing="12"/>
|
||||
</ItemsRepeater.Layout>
|
||||
</ItemsRepeater>
|
||||
</ScrollView>
|
||||
|
||||
@@ -507,6 +507,12 @@
|
||||
Text="{shcm:ResourceString Name=ViewPageDailyNoteSettingRefreshHeader}"/>
|
||||
</cwcont:HeaderedContentControl.Header>
|
||||
<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
|
||||
Description="{shcm:ResourceString Name=ViewPageDailyNoteSettingAutoRefreshDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageDailyNoteSettingAutoRefresh}"
|
||||
|
||||
@@ -104,8 +104,10 @@
|
||||
</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">
|
||||
<Border Margin="16,0,16,16" cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
|
||||
<Border Style="{ThemeResource AcrylicBorderCardStyle}">
|
||||
@@ -113,7 +115,7 @@
|
||||
DisplayMode="Inline"
|
||||
IsPaneOpen="True"
|
||||
OpenPaneLength="{StaticResource CompatSplitViewOpenPaneLength2}"
|
||||
PaneBackground="{StaticResource CardBackgroundFillColorSecondary}">
|
||||
PaneBackground="{ThemeResource CardBackgroundFillColorSecondaryBrush}">
|
||||
<SplitView.Pane>
|
||||
<ListView
|
||||
Grid.Row="1"
|
||||
|
||||
@@ -218,7 +218,7 @@
|
||||
DisplayMode="Inline"
|
||||
IsPaneOpen="True"
|
||||
OpenPaneLength="{StaticResource CompatSplitViewOpenPaneLength}"
|
||||
PaneBackground="{StaticResource CardBackgroundFillColorSecondary}">
|
||||
PaneBackground="{ThemeResource CardBackgroundFillColorSecondaryBrush}">
|
||||
<SplitView.Pane>
|
||||
<ListView
|
||||
Grid.Row="1"
|
||||
|
||||
@@ -372,8 +372,13 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
|
||||
private void UpdateAchievementsFinishPercent()
|
||||
{
|
||||
// 保存成就状态时,需要保持当前选择的成就分类
|
||||
AchievementGoalView? currentSelectedAchievementGoal = SelectedAchievementGoal;
|
||||
|
||||
// 仅 读取成就列表 与 保存成就状态 时需要刷新成就进度
|
||||
AchievementFinishPercent.Update(this);
|
||||
|
||||
SelectedAchievementGoal = currentSelectedAchievementGoal;
|
||||
}
|
||||
|
||||
[Command("SaveAchievementCommand")]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Factory.ContentDialog;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Service.Cultivation;
|
||||
@@ -110,11 +111,18 @@ internal sealed partial class CultivationViewModel : Abstraction.ViewModel
|
||||
return;
|
||||
}
|
||||
|
||||
ContentDialogResult result = await contentDialogFactory
|
||||
.CreateForConfirmCancelAsync(SH.ViewModelCultivationRemoveProjectTitle, SH.ViewModelCultivationRemoveProjectContent)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ using Snap.Hutao.Control.Extension;
|
||||
using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Factory.ContentDialog;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Service;
|
||||
using Snap.Hutao.Service.DailyNote;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using Snap.Hutao.Service.Notification;
|
||||
@@ -32,12 +33,15 @@ internal sealed partial class DailyNoteViewModel : Abstraction.ViewModel
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly IUserService userService;
|
||||
private readonly AppOptions appOptions;
|
||||
|
||||
private ObservableCollection<UserAndUid>? userAndUids;
|
||||
private ObservableCollection<DailyNoteEntry>? dailyNoteEntries;
|
||||
|
||||
public DailyNoteOptions DailyNoteOptions { get => dailyNoteOptions; }
|
||||
|
||||
public AppOptions AppOptions { get => appOptions; }
|
||||
|
||||
public IWebViewerSource VerifyUrlSource { get; } = new DailyNoteWebViewerSource();
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -66,7 +66,7 @@ internal sealed partial class TypedWishSummary : Wish
|
||||
/// </summary>
|
||||
public string TotalOrangeFormatted
|
||||
{
|
||||
get => $"{TotalOrangePull} [{TotalOrangePercent,6:p2}]";
|
||||
get => $"{TotalOrangePull} [{(TotalOrangePercent is double.NaN ? 0D : TotalOrangePercent),6:p2}]";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -74,7 +74,7 @@ internal sealed partial class TypedWishSummary : Wish
|
||||
/// </summary>
|
||||
public string TotalPurpleFormatted
|
||||
{
|
||||
get => $"{TotalPurplePull} [{TotalPurplePercent,6:p2}]";
|
||||
get => $"{TotalPurplePull} [{(TotalPurplePercent is double.NaN ? 0D : TotalPurplePercent),6:p2}]";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -82,7 +82,7 @@ internal sealed partial class TypedWishSummary : Wish
|
||||
/// </summary>
|
||||
public string TotalBlueFormatted
|
||||
{
|
||||
get => $"{TotalBluePull} [{TotalBluePercent,6:p2}]";
|
||||
get => $"{TotalBluePull} [{(TotalBluePercent is double.NaN ? 0D : TotalBluePercent),6:p2}]";
|
||||
}
|
||||
|
||||
public ColorSegmentCollection PullPercentSegmentSource
|
||||
|
||||
@@ -49,10 +49,21 @@ internal class Response : ICommonResponse<Response>
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -63,8 +74,7 @@ internal class Response : ICommonResponse<Response>
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (showInfoBar)
|
||||
{
|
||||
serviceProvider ??= Ioc.Default;
|
||||
@@ -73,7 +83,6 @@ internal class Response : ICommonResponse<Response>
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
@@ -102,20 +111,12 @@ internal class Response<TData> : Response, ICommonResponse<Response<TData>>, IJs
|
||||
[MemberNotNullWhen(true, nameof(Data))]
|
||||
public override bool IsOk(bool showInfoBar = true, IServiceProvider? serviceProvider = null)
|
||||
{
|
||||
if (ReturnCode == 0)
|
||||
bool result = base.IsOk(showInfoBar, serviceProvider);
|
||||
if (result)
|
||||
{
|
||||
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