Compare commits

..

17 Commits

Author SHA1 Message Date
qhy040404
13108b6694 show finished icon if we have enough items 2024-03-27 16:23:30 +08:00
DismissedLight
ab1b3c02c8 Merge pull request #1500 from DGP-Studio/feat/suggestbox_not_found 2024-03-25 22:43:47 +08:00
DismissedLight
8ef5dc9302 code style 2024-03-25 22:41:58 +08:00
qhy040404
a387e0dbf5 fix achievement search reset 2024-03-23 12:59:38 +08:00
qhy040404
8111c1e662 Disable unknown token 2024-03-23 12:58:49 +08:00
qhy040404
9cd9193425 show not found in view 2024-03-23 12:58:49 +08:00
qhy040404
d531c81fa2 show not found in search box 2024-03-23 12:58:49 +08:00
DismissedLight
1d0a72493e achievement city typedef 2024-03-21 22:27:16 +08:00
Lightczx
f2b361819b fix userview 2024-03-20 10:42:14 +08:00
qhy040404
41f7245a1a fix #1503 2024-03-19 22:46:58 +08:00
DismissedLight
889e914f7f colorized log message 2024-03-19 22:23:47 +08:00
Lightczx
9f90ec221c colorized 2024-03-19 17:30:23 +08:00
DismissedLight
8fc874fd09 Merge pull request #1498 from DGP-Studio/dependabot/nuget/src/Snap.Hutao/develop/packages-f9ad2d8712 2024-03-19 15:13:47 +08:00
Lightczx
f42ec1ea12 change banner color 2024-03-18 17:25:45 +08:00
Lightczx
5cc3cf264c refactor 2024-03-18 17:15:42 +08:00
Lightczx
e38517a2ad optimize uniformpanel 2024-03-18 16:54:17 +08:00
dependabot[bot]
cdc0fb8a82 Bump the packages group in /src/Snap.Hutao with 1 update
Bumps the packages group in /src/Snap.Hutao with 1 update: [coverlet.collector](https://github.com/coverlet-coverage/coverlet).


Updates `coverlet.collector` from 6.0.1 to 6.0.2
- [Release notes](https://github.com/coverlet-coverage/coverlet/releases)
- [Commits](https://github.com/coverlet-coverage/coverlet/compare/v6.0.1...v6.0.2)

---
updated-dependencies:
- dependency-name: coverlet.collector
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: packages
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-18 07:31:21 +00:00
41 changed files with 1219 additions and 770 deletions

View File

@@ -15,7 +15,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.2.2" />
<PackageReference Include="MSTest.TestFramework" Version="3.2.2" />
<PackageReference Include="coverlet.collector" Version="6.0.1">
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -7,8 +7,11 @@ using Snap.Hutao.Core;
using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.Core.LifeCycle;
using Snap.Hutao.Core.LifeCycle.InterProcess;
using Snap.Hutao.Core.Logging;
using Snap.Hutao.Core.Shell;
using System.Diagnostics;
using System.Text;
using static Snap.Hutao.Core.Logging.ConsoleVirtualTerminalSequences;
namespace Snap.Hutao;
@@ -21,17 +24,17 @@ namespace Snap.Hutao;
[SuppressMessage("", "SH001")]
public sealed partial class App : Application
{
private const string ConsoleBanner = """
private const string ConsoleBanner = $"""
----------------------------------------------------------------
_____ _ _ _
/ ____| | | | | | |
| (___ _ __ __ _ _ __ | |__| | _ _ | |_ __ _ ___
\___ \ | '_ \ / _` || '_ \ | __ || | | || __|/ _` | / _ \
_____ _ _ _
/ ____| | | | | | |
| (___ _ __ __ _ _ __ | |__| | _ _ | |_ __ _ ___
\___ \ | '_ \ / _` || '_ \ | __ || | | || __|/ _` | / _ \
____) || | | || (_| || |_) |_ | | | || |_| || |_| (_| || (_) |
|_____/ |_| |_| \__,_|| .__/(_)|_| |_| \__,_| \__|\__,_| \___/
| |
|_|
|_____/ |_| |_| \__,_|| .__/(_)|_| |_| \__,_| \__|\__,_| \___/
| |
|_|
Snap.Hutao is a open source software developed by DGP Studio.
Copyright (C) 2022 - 2024 DGP Studio, All Rights Reserved.
----------------------------------------------------------------
@@ -69,7 +72,7 @@ public sealed partial class App : Application
return;
}
logger.LogInformation(ConsoleBanner);
logger.LogColorizedInformation((ConsoleBanner, ConsoleColor.DarkYellow));
LogDiagnosticInformation();
// manually invoke
@@ -89,8 +92,8 @@ public sealed partial class App : Application
{
RuntimeOptions runtimeOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
logger.LogInformation("FamilyName: {name}", runtimeOptions.FamilyName);
logger.LogInformation("Version: {version}", runtimeOptions.Version);
logger.LogInformation("LocalCache: {folder}", runtimeOptions.LocalCache);
logger.LogColorizedInformation(("FamilyName: {Name}", ConsoleColor.Blue), (runtimeOptions.FamilyName, ConsoleColor.Cyan));
logger.LogColorizedInformation(("Version: {Version}", ConsoleColor.Blue), (runtimeOptions.Version, ConsoleColor.Cyan));
logger.LogColorizedInformation(("LocalCache: {Path}", ConsoleColor.Blue), (runtimeOptions.LocalCache, ConsoleColor.Cyan));
}
}

View File

@@ -7,6 +7,7 @@ using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Snap.Hutao.Control.Extension;
using System.Collections;
namespace Snap.Hutao.Control.AutoSuggestBox;
@@ -21,8 +22,8 @@ internal sealed partial class AutoSuggestTokenBox : TokenizingTextBox
TextChanged += OnFilterSuggestionRequested;
QuerySubmitted += OnQuerySubmitted;
TokenItemAdding += OnTokenItemAdding;
TokenItemAdded += OnTokenItemModified;
TokenItemRemoved += OnTokenItemModified;
TokenItemAdded += OnTokenItemCollectionChanged;
TokenItemRemoved += OnTokenItemCollectionChanged;
Loaded += OnLoaded;
}
@@ -30,34 +31,15 @@ internal sealed partial class AutoSuggestTokenBox : TokenizingTextBox
{
if (this.FindDescendant("SuggestionsPopup") is Popup { Child: Border { Child: ListView listView } border })
{
IAppResourceProvider appResourceProvider = Ioc.Default.GetRequiredService<IAppResourceProvider>();
IAppResourceProvider appResourceProvider = this.ServiceProvider().GetRequiredService<IAppResourceProvider>();
listView.Background = null;
listView.Margin = appResourceProvider.GetResource<Thickness>("AutoSuggestListPadding");
border.Background = appResourceProvider.GetResource<Microsoft.UI.Xaml.Media.Brush>("AutoSuggestBoxSuggestionsListBackground");
border.CornerRadius = new(0, 0, 8, 8);
}
if (this.FindDescendant("PART_AutoSuggestBox") is Microsoft.UI.Xaml.Controls.AutoSuggestBox autoSuggestBox)
{
autoSuggestBox.GotFocus += OnSuggestBoxFocusGot;
autoSuggestBox.LosingFocus += OnSuggestBoxFocusLosing;
}
}
private void OnSuggestBoxFocusGot(object sender, RoutedEventArgs e)
{
if (sender is Microsoft.UI.Xaml.Controls.AutoSuggestBox autoSuggestBox)
{
autoSuggestBox.ItemsSource = AvailableTokens.Values;
}
}
private void OnSuggestBoxFocusLosing(object sender, RoutedEventArgs e)
{
if (sender is Microsoft.UI.Xaml.Controls.AutoSuggestBox autoSuggestBox)
{
autoSuggestBox.ItemsSource = null;
CornerRadius overlayCornerRadius = appResourceProvider.GetResource<CornerRadius>("OverlayCornerRadius");
CornerRadiusFilterConverter cornerRadiusFilterConverter = new() { Filter = CornerRadiusFilterKind.Bottom };
border.CornerRadius = (CornerRadius)cornerRadiusFilterConverter.Convert(overlayCornerRadius, typeof(CornerRadius), default, default);
}
}
@@ -65,12 +47,19 @@ internal sealed partial class AutoSuggestTokenBox : TokenizingTextBox
{
if (string.IsNullOrWhiteSpace(Text))
{
return;
sender.ItemsSource = AvailableTokens
.OrderBy(kvp => kvp.Value.Kind)
.Select(kvp => kvp.Value);
}
if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
{
sender.ItemsSource = AvailableTokens.Values.Where(q => q.Value.Contains(Text, StringComparison.OrdinalIgnoreCase));
sender.ItemsSource = AvailableTokens
.Where(kvp => kvp.Value.Value.Contains(Text, StringComparison.OrdinalIgnoreCase))
.OrderBy(kvp => kvp.Value.Kind)
.ThenBy(kvp => kvp.Value.Order)
.Select(kvp => kvp.Value)
.DefaultIfEmpty(SearchToken.NotFound);
}
}
@@ -91,11 +80,23 @@ internal sealed partial class AutoSuggestTokenBox : TokenizingTextBox
return;
}
args.Item = AvailableTokens.GetValueOrDefault(args.TokenText) ?? new SearchToken(SearchTokenKind.None, args.TokenText);
if (AvailableTokens.GetValueOrDefault(args.TokenText) is { } token)
{
args.Item = token;
}
else
{
args.Cancel = true;
}
}
private void OnTokenItemModified(TokenizingTextBox sender, object args)
private void OnTokenItemCollectionChanged(TokenizingTextBox sender, object args)
{
CommandInvocation.TryExecute(FilterCommand, FilterCommandParameter);
if (args is SearchToken { Kind: SearchTokenKind.None } token)
{
((IList)sender.ItemsSource).Remove(token);
}
FilterCommand.TryExecute(FilterCommandParameter);
}
}

View File

@@ -7,13 +7,16 @@ namespace Snap.Hutao.Control.AutoSuggestBox;
internal sealed class SearchToken
{
public SearchToken(SearchTokenKind kind, string value, Uri? iconUri = null, Uri? sideIconUri = null, Color? quality = null)
public static readonly SearchToken NotFound = new(SearchTokenKind.None, SH.ControlAutoSuggestBoxNotFoundValue, 0);
public SearchToken(SearchTokenKind kind, string value, int order, Uri? iconUri = null, Uri? sideIconUri = null, Color? quality = null)
{
Value = value;
Kind = kind;
IconUri = iconUri;
SideIconUri = sideIconUri;
Quality = quality;
Order = order;
}
public SearchTokenKind Kind { get; }
@@ -26,6 +29,8 @@ internal sealed class SearchToken
public Color? Quality { get; }
public int Order { get; }
public override string ToString()
{
return Value;

View File

@@ -6,12 +6,12 @@ namespace Snap.Hutao.Control.AutoSuggestBox;
internal enum SearchTokenKind
{
None,
AssociationType,
Avatar,
BodyType,
ElementName,
FightProperty,
ItemQuality,
Weapon,
WeaponType,
FightProperty,
ElementName,
AssociationType,
BodyType,
Avatar,
Weapon,
}

View File

@@ -33,6 +33,7 @@ internal sealed partial class PeriodicInvokeCommandOrOnActualThemeChangedBehavio
protected override bool Uninitialize()
{
periodicTimerCancellationTokenSource.Cancel();
AssociatedObject.ActualThemeChanged -= OnActualThemeChanged;
return true;
}

View File

@@ -13,6 +13,4 @@ namespace Snap.Hutao.Control;
/// </summary>
[HighQuality]
[DependencyProperty("DataContext", typeof(object))]
internal sealed partial class BindingProxy : DependencyObject
{
}
internal sealed partial class BindingProxy : DependencyObject;

View File

@@ -30,7 +30,7 @@ internal sealed class AdvancedCollectionView<T> : IAdvancedCollectionView<T>, IN
private WeakEventListener<AdvancedCollectionView<T>, object?, NotifyCollectionChangedEventArgs>? sourceWeakEventListener;
public AdvancedCollectionView()
: this(new List<T>(0))
: this([])
{
}

View File

@@ -6,6 +6,7 @@ using Windows.Foundation.Collections;
namespace Snap.Hutao.Control.Collection.Alternating;
[Obsolete("Use SettingsCard instead")]
[DependencyProperty("ItemAlternateBackground", typeof(Microsoft.UI.Xaml.Media.Brush))]
internal sealed partial class AlternatingItemsControl : ItemsControl
{

View File

@@ -3,6 +3,7 @@
namespace Snap.Hutao.Control.Collection.Alternating;
[Obsolete("Use SettingsCard instead")]
internal interface IAlternatingItem
{
public Microsoft.UI.Xaml.Media.Brush? Background { get; set; }

View File

@@ -21,6 +21,9 @@ internal sealed class CachedImage : Implementation.ImageEx
/// </summary>
public CachedImage()
{
DefaultStyleKey = typeof(CachedImage);
DefaultStyleResourceUri = "ms-appx:///Control/Image/CachedImage.xaml".ToUri();
IsCacheEnabled = true;
EnableLazyLoading = false;
}

View File

@@ -17,7 +17,7 @@ internal class Loading : Microsoft.UI.Xaml.Controls.ContentControl
public Loading()
{
DefaultStyleKey = typeof(Loading);
DefaultStyleResourceUri = new("ms-appx:///Control/Loading.xaml");
DefaultStyleResourceUri = "ms-appx:///Control/Loading.xaml".ToUri();
}
public bool IsLoading

View File

@@ -1,21 +1,55 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Controls;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Windows.Foundation;
namespace Snap.Hutao.Control.Panel;
[DependencyProperty("MinItemWidth", typeof(double))]
internal sealed partial class UniformPanel : UniformGrid
[DependencyProperty("ColumnSpacing", typeof(double))]
[DependencyProperty("RowSpacing", typeof(double))]
internal sealed partial class UniformPanel : Microsoft.UI.Xaml.Controls.Panel
{
public UniformPanel()
private int columns;
protected override Size MeasureOverride(Size availableSize)
{
Columns = 1;
SizeChanged += OnSizeChanged;
columns = (int)((availableSize.Width + ColumnSpacing) / (MinItemWidth + ColumnSpacing));
double availableItemWidth = ((availableSize.Width + ColumnSpacing) / columns) - ColumnSpacing;
double maxDesiredHeight = 0;
foreach (UIElement child in Children)
{
child.Measure(new Size(availableItemWidth, availableSize.Height));
maxDesiredHeight = Math.Max(maxDesiredHeight, child.DesiredSize.Height);
}
int desiredRows = (int)Math.Ceiling(Children.Count / (double)columns);
double desiredHeight = ((maxDesiredHeight + RowSpacing) * desiredRows) - RowSpacing;
return new Size(availableSize.Width, desiredHeight);
}
private void OnSizeChanged(object sender, Microsoft.UI.Xaml.SizeChangedEventArgs e)
protected override Size ArrangeOverride(Size finalSize)
{
Columns = (int)((e.NewSize.Width + ColumnSpacing) / (MinItemWidth + ColumnSpacing));
double itemWidth = ((finalSize.Width + ColumnSpacing) / columns) - ColumnSpacing;
for (int index = 0; index < Children.Count; index++)
{
UIElement child = Children[index];
int row = index / columns;
int column = index % columns;
double x = column * (itemWidth + ColumnSpacing);
double y = row * (child.DesiredSize.Height + RowSpacing);
child.Arrange(new Rect(x, y, itemWidth, child.DesiredSize.Height));
}
return finalSize;
}
}

View File

@@ -45,15 +45,7 @@ internal sealed partial class DescriptionTextBlock : ContentControl
private static void OnDescriptionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextBlock textBlock = (TextBlock)((DescriptionTextBlock)d).Content;
try
{
UpdateDescription(textBlock, MiHoYoSyntaxTree.Parse(SpecialNameHandler.Handle((string)e.NewValue)));
}
catch (Exception ex)
{
_ = ex;
}
UpdateDescription(textBlock, MiHoYoSyntaxTree.Parse(SpecialNameHandler.Handle((string)e.NewValue)));
}
private static void OnTextStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

View File

@@ -14,6 +14,7 @@ using Windows.UI;
namespace Snap.Hutao.Control.Text;
// TODO: change the parsing to syntax tree
[DependencyProperty("Description", typeof(string), "", nameof(OnDescriptionChanged))]
[DependencyProperty("TextStyle", typeof(Style), default(Style), nameof(OnTextStyleChanged))]
internal sealed partial class HtmlDescriptionTextBlock : ContentControl

View File

@@ -30,6 +30,7 @@
<x:String x:Key="UI_EmotionIcon25">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon25.png</x:String>
<x:String x:Key="UI_EmotionIcon52">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon52.png</x:String>
<x:String x:Key="UI_EmotionIcon71">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon71.png</x:String>
<x:String x:Key="UI_EmotionIcon89">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon89.png</x:String>
<x:String x:Key="UI_EmotionIcon250">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon250.png</x:String>
<x:String x:Key="UI_EmotionIcon271">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon271.png</x:String>
<x:String x:Key="UI_EmotionIcon272">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon272.png</x:String>

View File

@@ -1,18 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.Abstraction;
/// <summary>
/// 可克隆
/// </summary>
/// <typeparam name="TSelf">自身类型</typeparam>
[HighQuality]
internal interface ICloneable<out TSelf>
{
/// <summary>
/// 克隆
/// </summary>
/// <returns>新的克隆</returns>
TSelf Clone();
}

View File

@@ -0,0 +1,114 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.Logging;
internal static class ConsoleVirtualTerminalSequences
{
public const string Default = "\u001b[0m";
public const string Bold = "\u001b[1m";
public const string Underline = "\u001b[4m";
public const string Negative = "\u001b[7m";
public const string NoBold = "\u001b[22m";
public const string NoUnderline = "\u001b[24m";
public const string Positive = "\u001b[27m";
public const string ForegroundBlack = "\u001b[30m";
public const string ForegroundRed = "\u001b[31m";
public const string ForegroundGreen = "\u001b[32m";
public const string ForegroundYellow = "\u001b[33m";
public const string ForegroundBlue = "\u001b[34m";
public const string ForegroundMagenta = "\u001b[35m";
public const string ForegroundCyan = "\u001b[36m";
public const string ForegroundWhite = "\u001b[37m";
public const string ForegroundExtended = "\u001b[38m";
public const string ForegroundDefault = "\u001b[39m";
public const string BackgroundBlack = "\u001b[40m";
public const string BackgroundRed = "\u001b[41m";
public const string BackgroundGreen = "\u001b[42m";
public const string BackgroundYellow = "\u001b[43m";
public const string BackgroundBlue = "\u001b[44m";
public const string BackgroundMagenta = "\u001b[45m";
public const string BackgroundCyan = "\u001b[46m";
public const string BackgroundWhite = "\u001b[47m";
public const string BackgroundExtended = "\u001b[48m";
public const string BackgroundDefault = "\u001b[49m";
public const string BrightForegroundBlack = "\u001b[1m\u001b[30m";
public const string BrightForegroundRed = "\u001b[1m\u001b[31m";
public const string BrightForegroundGreen = "\u001b[1m\u001b[32m";
public const string BrightForegroundYellow = "\u001b[1m\u001b[33m";
public const string BrightForegroundBlue = "\u001b[1m\u001b[34m";
public const string BrightForegroundMagenta = "\u001b[1m\u001b[35m";
public const string BrightForegroundCyan = "\u001b[1m\u001b[36m";
public const string BrightForegroundWhite = "\u001b[1m\u001b[37m";
public const string BrightBackgroundBlack = "\u001b[1m\u001b[40m";
public const string BrightBackgroundRed = "\u001b[1m\u001b[41m";
public const string BrightBackgroundGreen = "\u001b[1m\u001b[42m";
public const string BrightBackgroundYellow = "\u001b[1m\u001b[43m";
public const string BrightBackgroundBlue = "\u001b[1m\u001b[44m";
public const string BrightBackgroundMagenta = "\u001b[1m\u001b[45m";
public const string BrightBackgroundCyan = "\u001b[1m\u001b[46m";
public const string BrightBackgroundWhite = "\u001b[1m\u001b[47m";
public const string Dim = "\u001b[2m";
public const string Italic = "\u001b[3m";
public const string Blink = "\u001b[5m";
public const string Hidden = "\u001b[8m";
public const string StrikeThrough = "\u001b[9m";
public const string DoubleUnderline = "\u001b[21m";
public const string NoItalic = "\u001b[23m";
public const string NoBlink = "\u001b[25m";
public const string NoHidden = "\u001b[28m";
public const string NoStrikeThrough = "\u001b[29m";
public static string FromConsoleColor(ConsoleColor color, bool foreground)
{
return (foreground, color) switch
{
(true, ConsoleColor.Black) => ForegroundBlack,
(true, ConsoleColor.DarkBlue) => ForegroundBlue,
(true, ConsoleColor.DarkGreen) => ForegroundGreen,
(true, ConsoleColor.DarkCyan) => ForegroundCyan,
(true, ConsoleColor.DarkRed) => ForegroundRed,
(true, ConsoleColor.DarkMagenta) => ForegroundMagenta,
(true, ConsoleColor.DarkYellow) => ForegroundYellow,
(true, ConsoleColor.DarkGray) => BrightForegroundBlack,
(true, ConsoleColor.Gray) => ForegroundWhite,
(true, ConsoleColor.Blue) => BrightForegroundBlue,
(true, ConsoleColor.Green) => BrightForegroundGreen,
(true, ConsoleColor.Cyan) => BrightForegroundCyan,
(true, ConsoleColor.Red) => BrightForegroundRed,
(true, ConsoleColor.Magenta) => BrightForegroundMagenta,
(true, ConsoleColor.Yellow) => BrightForegroundYellow,
(true, ConsoleColor.White) => BrightForegroundWhite,
(false, ConsoleColor.Black) => BackgroundBlack,
(false, ConsoleColor.DarkBlue) => BackgroundBlue,
(false, ConsoleColor.DarkGreen) => BackgroundGreen,
(false, ConsoleColor.DarkCyan) => BackgroundCyan,
(false, ConsoleColor.DarkRed) => BackgroundRed,
(false, ConsoleColor.DarkMagenta) => BackgroundMagenta,
(false, ConsoleColor.DarkYellow) => BackgroundYellow,
(false, ConsoleColor.DarkGray) => BrightBackgroundBlack,
(false, ConsoleColor.Gray) => BackgroundWhite,
(false, ConsoleColor.Blue) => BrightBackgroundBlue,
(false, ConsoleColor.Green) => BrightBackgroundGreen,
(false, ConsoleColor.Cyan) => BrightBackgroundCyan,
(false, ConsoleColor.Red) => BrightBackgroundRed,
(false, ConsoleColor.Magenta) => BrightBackgroundMagenta,
(false, ConsoleColor.Yellow) => BrightBackgroundYellow,
(false, ConsoleColor.White) => BrightBackgroundWhite,
_ => string.Empty,
};
}
}

View File

@@ -22,7 +22,7 @@ internal sealed class ConsoleWindowLifeTime : IDisposable
HANDLE inputHandle = GetStdHandle(STD_HANDLE.STD_INPUT_HANDLE);
if (GetConsoleMode(inputHandle, out CONSOLE_MODE mode))
{
mode &= ~CONSOLE_MODE.ENABLE_QUICK_EDIT_MODE;
mode &= ~CONSOLE_MODE.ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(inputHandle, mode);
}
@@ -38,4 +38,4 @@ internal sealed class ConsoleWindowLifeTime : IDisposable
FreeConsole();
}
}
}
}

View File

@@ -0,0 +1,28 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.Logging;
internal readonly struct LogArgument
{
public readonly object? Argument;
public readonly ConsoleColor? ForegroundColor;
public readonly ConsoleColor? BackgroundColor;
public LogArgument(object? argument, ConsoleColor? foreground = default, ConsoleColor? background = default)
{
Argument = argument;
ForegroundColor = foreground;
BackgroundColor = background;
}
public static implicit operator LogArgument(string argument)
{
return new(argument);
}
public static implicit operator LogArgument((object? Argument, ConsoleColor Foreground) tuple)
{
return new(tuple.Argument, tuple.Foreground);
}
}

View File

@@ -0,0 +1,28 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.Logging;
internal readonly struct LogMessage
{
public readonly string Message;
public readonly ConsoleColor? ForegroundColor;
public readonly ConsoleColor? BackgroundColor;
public LogMessage(string message, ConsoleColor? foreground = default, ConsoleColor? background = default)
{
Message = message;
ForegroundColor = foreground;
BackgroundColor = background;
}
public static implicit operator LogMessage(string value)
{
return new(value);
}
public static implicit operator LogMessage((string Value, ConsoleColor? Foreground) tuple)
{
return new(tuple.Value, tuple.Foreground);
}
}

View File

@@ -0,0 +1,172 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Text;
namespace Snap.Hutao.Core.Logging;
[SuppressMessage("", "SH002")]
internal static class LoggerExtension
{
public static void LogColorizedDebug(this ILogger logger, Exception? exception, LogMessage message, params LogArgument[] args)
{
logger.LogColorized(LogLevel.Debug, exception, message, args);
}
public static void LogColorizedDebug(this ILogger logger, LogMessage message, params LogArgument[] args)
{
logger.LogColorized(LogLevel.Debug, message, args);
}
public static void LogColorizedTrace(this ILogger logger, Exception? exception, LogMessage message, params LogArgument[] args)
{
logger.LogColorized(LogLevel.Trace, exception, message, args);
}
public static void LogColorizedTrace(this ILogger logger, LogMessage message, params LogArgument[] args)
{
logger.LogColorized(LogLevel.Trace, message, args);
}
public static void LogColorizedInformation(this ILogger logger, Exception? exception, LogMessage message, params LogArgument[] args)
{
logger.LogColorized(LogLevel.Information, exception, message, args);
}
public static void LogColorizedInformation(this ILogger logger, LogMessage message, params LogArgument[] args)
{
logger.LogColorized(LogLevel.Information, message, args);
}
public static void LogColorizedWarning(this ILogger logger, Exception? exception, LogMessage message, params LogArgument[] args)
{
logger.LogColorized(LogLevel.Warning, exception, message, args);
}
public static void LogColorizedWarning(this ILogger logger, LogMessage message, params LogArgument[] args)
{
logger.LogColorized(LogLevel.Warning, message, args);
}
public static void LogColorizedError(this ILogger logger, Exception? exception, LogMessage message, params LogArgument[] args)
{
logger.LogColorized(LogLevel.Error, exception, message, args);
}
public static void LogColorizedError(this ILogger logger, LogMessage message, params LogArgument[] args)
{
logger.LogColorized(LogLevel.Error, message, args);
}
public static void LogColorizedCritical(this ILogger logger, Exception? exception, LogMessage message, params LogArgument[] args)
{
logger.LogColorized(LogLevel.Critical, exception, message, args);
}
public static void LogColorizedCritical(this ILogger logger, LogMessage message, params LogArgument[] args)
{
logger.LogColorized(LogLevel.Critical, message, args);
}
public static void LogColorized(this ILogger logger, LogLevel logLevel, LogMessage message, params LogArgument[] args)
{
logger.LogColorized(logLevel, 0, null, message, args);
}
public static void LogColorized(this ILogger logger, LogLevel logLevel, EventId eventId, LogMessage message, params LogArgument[] args)
{
logger.LogColorized(logLevel, eventId, null, message, args);
}
public static void LogColorized(this ILogger logger, LogLevel logLevel, Exception? exception, LogMessage message, params LogArgument[] args)
{
logger.LogColorized(logLevel, 0, exception, message, args);
}
public static void LogColorized(this ILogger logger, LogLevel logLevel, EventId eventId, Exception? exception, LogMessage message, params LogArgument[] args)
{
string colorizedMessage = Colorize(message, args, out object?[] outArgs)!;
logger.Log(logLevel, eventId, exception, colorizedMessage, outArgs);
}
private static string? Colorize(LogMessage message, LogArgument[] args, out object?[] outArgs)
{
StringBuilder resultMessageBuilder = new(message.Message.Length);
ReadOnlySpan<char> messageSpan = message.Message.AsSpan();
// Message base colors
ConsoleColor? messageForeground = message.ForegroundColor;
ConsoleColor? messageBackground = message.BackgroundColor;
if (messageForeground.HasValue)
{
resultMessageBuilder.Append(ConsoleVirtualTerminalSequences.FromConsoleColor(messageForeground.Value, true));
}
if (messageBackground.HasValue)
{
resultMessageBuilder.Append(ConsoleVirtualTerminalSequences.FromConsoleColor(messageBackground.Value, false));
}
ReadOnlySpan<LogArgument> argSpan = args.AsSpan();
outArgs = new object?[args.Length];
int argIndex = 0;
for (int index = 0; index < messageSpan.Length; index++)
{
if (messageSpan[index] == '{')
{
ref readonly LogArgument arg = ref argSpan[argIndex];
outArgs[argIndex] = arg.Argument;
argIndex++;
if (arg.ForegroundColor.HasValue)
{
resultMessageBuilder.Append(ConsoleVirtualTerminalSequences.FromConsoleColor(arg.ForegroundColor.Value, true));
}
if (arg.BackgroundColor.HasValue)
{
resultMessageBuilder.Append(ConsoleVirtualTerminalSequences.FromConsoleColor(arg.BackgroundColor.Value, false));
}
int closingIndex = messageSpan[index..].IndexOf('}');
resultMessageBuilder.Append(messageSpan.Slice(index, closingIndex + 1));
index += closingIndex;
if (arg.ForegroundColor.HasValue || arg.BackgroundColor.HasValue)
{
// Restore message colors
if (messageForeground.HasValue || messageBackground.HasValue)
{
if (messageForeground.HasValue)
{
resultMessageBuilder.Append(ConsoleVirtualTerminalSequences.FromConsoleColor(messageForeground.Value, true));
}
if (messageBackground.HasValue)
{
resultMessageBuilder.Append(ConsoleVirtualTerminalSequences.FromConsoleColor(messageBackground.Value, false));
}
}
else
{
resultMessageBuilder.Append(ConsoleVirtualTerminalSequences.Default);
}
}
}
else
{
resultMessageBuilder.Append(messageSpan[index]);
}
}
// Restore default colors
if (message.ForegroundColor.HasValue || message.BackgroundColor.HasValue)
{
resultMessageBuilder.Append(ConsoleVirtualTerminalSequences.Default);
}
return resultMessageBuilder.ToString();
}
}

View File

@@ -3,7 +3,7 @@
namespace Snap.Hutao.Core.Logging;
internal static class LoggerFactoryExtensions
internal static class LoggerFactoryExtension
{
public static ILoggingBuilder AddConsoleWindow(this ILoggingBuilder builder)
{

View File

@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using Microsoft.EntityFrameworkCore;
using Snap.Hutao.Core.Logging;
using Snap.Hutao.Model.Entity.Configuration;
using System.Diagnostics;
@@ -34,7 +35,7 @@ internal sealed class AppDbContext : DbContext
: this(options)
{
this.logger = logger;
logger.LogInformation("{Name}[{Id}] created", nameof(AppDbContext), ContextId);
logger.LogColorizedInformation("{Name}[{Id}] {Action}", nameof(AppDbContext), (ContextId, ConsoleColor.DarkCyan), ("created", ConsoleColor.Green));
}
public DbSet<SettingEntry> Settings { get; set; } = default!;
@@ -87,7 +88,7 @@ internal sealed class AppDbContext : DbContext
public override void Dispose()
{
base.Dispose();
logger?.LogInformation("{Name}[{Id}] disposed", nameof(AppDbContext), ContextId);
logger?.LogColorizedInformation("{Name}[{Id}] {Action}", nameof(AppDbContext), (ContextId, ConsoleColor.DarkCyan), ("disposed", ConsoleColor.Red));
}
/// <inheritdoc/>

View File

@@ -11,34 +11,26 @@ namespace Snap.Hutao.Model.Intrinsic.Frozen;
[HighQuality]
internal static class IntrinsicFrozen
{
/// <summary>
/// 所属地区
/// </summary>
public static FrozenSet<string> AssociationTypes { get; } = Enum.GetValues<AssociationType>().Select(e => e.GetLocalizedDescriptionOrDefault()).OfType<string>().ToFrozenSet();
/// <summary>
/// 武器类型
/// </summary>
public static FrozenSet<NameValue<AssociationType>> AssociationTypeNameValues { get; } = Enum.GetValues<AssociationType>().Select(e => new NameValue<AssociationType>(e.GetLocalizedDescriptionOrDefault()!, e)).Where(nv => !string.IsNullOrEmpty(nv.Name)).ToFrozenSet();
public static FrozenSet<string> WeaponTypes { get; } = Enum.GetValues<WeaponType>().Select(e => e.GetLocalizedDescriptionOrDefault()).OfType<string>().ToFrozenSet();
/// <summary>
/// 物品类型
/// </summary>
public static FrozenSet<NameValue<WeaponType>> WeaponTypeNameValues { get; } = Enum.GetValues<WeaponType>().Select(e => new NameValue<WeaponType>(e.GetLocalizedDescriptionOrDefault()!, e)).Where(nv => !string.IsNullOrEmpty(nv.Name)).ToFrozenSet();
public static FrozenSet<string> ItemQualities { get; } = Enum.GetValues<QualityType>().Select(e => e.GetLocalizedDescriptionOrDefault()).OfType<string>().ToFrozenSet();
/// <summary>
/// 身材类型
/// </summary>
public static FrozenSet<NameValue<QualityType>> ItemQualityNameValues { get; } = Enum.GetValues<QualityType>().Select(e => new NameValue<QualityType>(e.GetLocalizedDescriptionOrDefault()!, e)).Where(nv => !string.IsNullOrEmpty(nv.Name)).ToFrozenSet();
public static FrozenSet<string> BodyTypes { get; } = Enum.GetValues<BodyType>().Select(e => e.GetLocalizedDescriptionOrDefault()).OfType<string>().ToFrozenSet();
/// <summary>
/// 战斗属性
/// </summary>
public static FrozenSet<NameValue<BodyType>> BodyTypeNameValues { get; } = Enum.GetValues<BodyType>().Select(e => new NameValue<BodyType>(e.GetLocalizedDescriptionOrDefault()!, e)).Where(nv => !string.IsNullOrEmpty(nv.Name)).ToFrozenSet();
public static FrozenSet<string> FightProperties { get; } = Enum.GetValues<FightProperty>().Select(e => e.GetLocalizedDescriptionOrDefault()).OfType<string>().ToFrozenSet();
/// <summary>
/// 元素名称
/// </summary>
public static FrozenSet<NameValue<FightProperty>> FightPropertyNameValues { get; } = Enum.GetValues<FightProperty>().Select(e => new NameValue<FightProperty>(e.GetLocalizedDescriptionOrDefault()!, e)).Where(nv => !string.IsNullOrEmpty(nv.Name)).ToFrozenSet();
public static FrozenSet<string> ElementNames { get; } = FrozenSet.ToFrozenSet(
[
SH.ModelIntrinsicElementNameFire,
@@ -50,6 +42,17 @@ internal static class IntrinsicFrozen
SH.ModelIntrinsicElementNameRock,
]);
public static FrozenSet<NameValue<int>> ElementNameValues { get; } = FrozenSet.ToFrozenSet(
[
new NameValue<int>(SH.ModelIntrinsicElementNameFire, 1),
new NameValue<int>(SH.ModelIntrinsicElementNameWater, 2),
new NameValue<int>(SH.ModelIntrinsicElementNameGrass, 3),
new NameValue<int>(SH.ModelIntrinsicElementNameElec, 4),
new NameValue<int>(SH.ModelIntrinsicElementNameWind, 5),
new NameValue<int>(SH.ModelIntrinsicElementNameIce, 6),
new NameValue<int>(SH.ModelIntrinsicElementNameRock, 7),
]);
public static FrozenSet<string> MaterialTypeDescriptions { get; } = FrozenSet.ToFrozenSet(
[
SH.ModelMetadataMaterialCharacterAndWeaponEnhancementMaterial,

View File

@@ -0,0 +1,16 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Model.Metadata;
// CityTaskOpenExcelConfig
internal enum City : uint
{
Mondstadt = 1,
Liyue = 2,
Inazuma = 3,
Sumeru = 4,
Fontaine = 5,
Natlan,
Snezhnaya,
}

View File

@@ -9,24 +9,6 @@ namespace Snap.Hutao.Model.Metadata.Converter;
internal sealed class AssociationTypeIconConverter : ValueConverter<AssociationType, Uri?>
{
private static readonly FrozenDictionary<string, AssociationType> LocalizedNameToAssociationType = FrozenDictionary.ToFrozenDictionary(
[
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeMondstadt, AssociationType.ASSOC_TYPE_MONDSTADT),
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeLiyue, AssociationType.ASSOC_TYPE_LIYUE),
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeFatui, AssociationType.ASSOC_TYPE_FATUI),
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeInazuma, AssociationType.ASSOC_TYPE_INAZUMA),
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeRanger, AssociationType.ASSOC_TYPE_RANGER),
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeSumeru, AssociationType.ASSOC_TYPE_SUMERU),
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeFontaine, AssociationType.ASSOC_TYPE_FONTAINE),
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeNatlan, AssociationType.ASSOC_TYPE_NATLAN),
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeSnezhnaya, AssociationType.ASSOC_TYPE_SNEZHNAYA),
]);
public static Uri? AssociationTypeNameToIconUri(string associationTypeName)
{
return AssociationTypeToIconUri(LocalizedNameToAssociationType.GetValueOrDefault(associationTypeName));
}
public static Uri? AssociationTypeToIconUri(AssociationType type)
{
string? association = type switch

View File

@@ -144,6 +144,9 @@
<data name="ContentDialogSavePrimaryButtonText" xml:space="preserve">
<value>Save</value>
</data>
<data name="ControlAutoSuggestBoxNotFoundValue" xml:space="preserve">
<value>No results found</value>
</data>
<data name="ControlImageCachedImageInvalidResourceUri" xml:space="preserve">
<value>Invalid Uri</value>
</data>

View File

@@ -144,6 +144,9 @@
<data name="ContentDialogSavePrimaryButtonText" xml:space="preserve">
<value>保存</value>
</data>
<data name="ControlAutoSuggestBoxNotFoundValue" xml:space="preserve">
<value>未找到结果</value>
</data>
<data name="ControlImageCachedImageInvalidResourceUri" xml:space="preserve">
<value>无效的 Uri</value>
</data>

View File

@@ -3,6 +3,7 @@
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Control;
using Snap.Hutao.Core.Logging;
using Snap.Hutao.Core.Setting;
using Snap.Hutao.Service.Notification;
using Snap.Hutao.View.Helper;
@@ -81,7 +82,7 @@ internal sealed class NavigationService : INavigationService, INavigationInitial
if (currentType == pageType)
{
logger.LogInformation("Navigate to {pageType} : succeed, already in", pageType);
logger.LogColorizedInformation("Navigate to {Page} : {Result}, already in", (pageType, ConsoleColor.DarkGreen), ("succeed", ConsoleColor.Green));
return NavigationResult.AlreadyNavigatedTo;
}
@@ -91,7 +92,7 @@ internal sealed class NavigationService : INavigationService, INavigationInitial
try
{
navigated = frame?.Navigate(pageType, data) ?? false;
logger.LogInformation("Navigate to {pageType} : {result}", pageType, navigated ? "succeed" : "failed");
logger.LogColorizedInformation("Navigate to {Page} : {Result}", (pageType, ConsoleColor.Magenta), navigated ? ("succeed", ConsoleColor.Green) : ("succeed", ConsoleColor.Red));
}
catch (Exception ex)
{

View File

@@ -174,12 +174,20 @@
</ItemContainer.Resources>
<shvcp:HorizontalCard>
<shvcp:HorizontalCard.Left>
<shvco:ItemIcon
Grid.Column="0"
Width="40"
Height="40"
Icon="{Binding Inner.Icon, Converter={StaticResource ItemIconConverter}}"
Quality="{Binding Inner.RankLevel}"/>
<Grid Grid.Column="0">
<shvco:ItemIcon
Width="40"
Height="40"
Icon="{Binding Inner.Icon, Converter={StaticResource ItemIconConverter}}"
Opacity="{Binding IsFinished, Converter={StaticResource BoolToOpacityConverter}}"
Quality="{Binding Inner.RankLevel}"/>
<FontIcon
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="24"
Glyph="&#xE73E;"
Visibility="{Binding IsFinished, Converter={StaticResource BoolToVisibilityConverter}}"/>
</Grid>
</shvcp:HorizontalCard.Left>
<shvcp:HorizontalCard.Right>
<Grid Margin="16,0">

View File

@@ -104,7 +104,7 @@
IsClickEnabled="True"/>
<cwcont:SettingsCard
Command="{Binding NavigateToUriCommand}"
CommandParameter="https://status.hut.ao"
CommandParameter="https://status.snapgenshin.cn/status"
Description="{shcm:ResourceString Name=ViewPageFeedbackServerStatusDescription}"
Header="{shcm:ResourceString Name=ViewPageFeedbackServerStatusHeader}"
IsClickEnabled="True"/>

View File

@@ -725,7 +725,7 @@
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<shcp:UniformPanel
Padding="0,0,16,0"
Margin="0,0,16,0"
ColumnSpacing="6"
MinItemWidth="240"
RowSpacing="2"/>
@@ -752,7 +752,7 @@
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<shcp:UniformPanel
Padding="0,0,16,0"
Margin="0,0,16,0"
ColumnSpacing="6"
MinItemWidth="240"
RowSpacing="2"/>

View File

@@ -317,6 +317,7 @@
QueryIcon="{cw:FontIconSource Glyph=&#xE721;}"
Style="{StaticResource DefaultTokenizingTextBoxStyle}"
SuggestedItemTemplate="{StaticResource TokenTemplate}"
SuggestedItemsSource="{Binding AvailableTokens.Values}"
Text="{Binding FilterToken, Mode=TwoWay}"
TokenItemTemplate="{StaticResource TokenTemplate}">
<shca:AutoSuggestTokenBox.ItemsPanel>
@@ -364,367 +365,378 @@
</SplitView.Pane>
<SplitView.Content>
<ScrollViewer>
<StackPanel
Padding="16,16,16,16"
HorizontalAlignment="Left"
Spacing="16">
<!-- 简介 -->
<Grid Style="{ThemeResource GridCardStyle}">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Margin="16">
<Grid Margin="0,0,0,12" ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<shci:MonoChrome
Grid.Column="0"
Width="32"
Height="32"
HorizontalAlignment="Left"
Source="{Binding Selected.FetterInfo.VisionBefore, Converter={StaticResource ElementNameIconConverter}}"/>
<shci:MonoChrome
Grid.Column="1"
Width="32"
Height="32"
Source="{Binding Selected.Weapon, Converter={StaticResource WeaponTypeIconConverter}}"/>
</Grid>
<shvcont:ItemIcon
Width="128"
Height="128"
Icon="{Binding Selected.Icon, Converter={StaticResource AvatarIconConverter}, Mode=OneWay}"
Quality="{Binding Selected.Quality, Mode=OneWay}"/>
</StackPanel>
<StackPanel Grid.Column="1" Margin="16">
<StackPanel Margin="0,0,0,2" Orientation="Horizontal">
<TextBlock
VerticalAlignment="Center"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{Binding Selected.Name}"/>
<TextBlock
Margin="24,0,0,0"
VerticalAlignment="Center"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{Binding Selected.FetterInfo.Title}"/>
</StackPanel>
<TextBlock
Opacity="0.7"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Selected.FetterInfo.Detail}"
TextWrapping="NoWrap"/>
<cwc:UniformGrid
Margin="0,16,0,0"
ColumnSpacing="6"
Columns="4">
<StackPanel>
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageWiKiAvatarOccupationNameTitle}"/>
<TextBlock
Margin="0,6,0,0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Selected.FetterInfo.Native}"
TextWrapping="NoWrap"/>
</StackPanel>
<StackPanel>
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageWiKiAvatarConstellationNameTitle}"/>
<TextBlock
Margin="0,6,0,0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Selected.FetterInfo.ConstellationBefore}"
TextWrapping="NoWrap"/>
</StackPanel>
<StackPanel>
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageWiKiAvatarDateofBirthTitle}"/>
<TextBlock
Margin="0,6,0,0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Selected.FetterInfo.BirthFormatted}"
TextWrapping="NoWrap"/>
</StackPanel>
</cwc:UniformGrid>
<cwc:UniformGrid
Margin="0,12,0,0"
ColumnSpacing="6"
Columns="4">
<StackPanel>
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageWiKiAvatarChineseCVNameTitle}"/>
<TextBlock
Margin="0,6,0,0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Selected.FetterInfo.CvChinese}"
TextWrapping="NoWrap"/>
</StackPanel>
<StackPanel>
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageWiKiAvatarJapaneseCVNameTitle}"/>
<TextBlock
Margin="0,6,0,0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Selected.FetterInfo.CvJapanese}"
TextWrapping="NoWrap"/>
</StackPanel>
<StackPanel>
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageWiKiAvatarEnglishCVNameTitle}"/>
<TextBlock
Margin="0,6,0,0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Selected.FetterInfo.CvEnglish}"
TextWrapping="NoWrap"/>
</StackPanel>
<StackPanel>
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageWiKiAvatarKoreanCVNameTitle}"/>
<TextBlock
Margin="0,6,0,0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Selected.FetterInfo.CvKorean}"
TextWrapping="NoWrap"/>
</StackPanel>
</cwc:UniformGrid>
</StackPanel>
<StackPanel Grid.Row="1" Grid.ColumnSpan="2">
<ItemsControl
Margin="16,0,16,16"
ItemTemplate="{StaticResource CultivationItemTemplate}"
ItemsSource="{Binding Selected.CultivationItemsView}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<cwc:UniformGrid
ColumnSpacing="8"
Columns="3"
RowSpacing="8"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</Grid>
<!-- 属性 -->
<Border Style="{ThemeResource BorderCardStyle}">
<Border.Resources>
<SolidColorBrush x:Key="ToggleButtonBackground" Color="Transparent"/>
<SolidColorBrush x:Key="ExpanderContentBackground" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackground" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackgroundDisabled" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackgroundPointerOver" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackgroundPressed" Color="Transparent"/>
</Border.Resources>
<shvcont:BaseValueSlider
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
BaseValueInfo="{Binding BaseValueInfo, Mode=OneWay}"/>
</Border>
<!-- 天赋 -->
<Border Padding="16" Style="{ThemeResource BorderCardStyle}">
<shvcont:SkillPivot ItemTemplate="{StaticResource SkillDataTemplate}" Skills="{Binding Selected.SkillDepot.CompositeSkills}"/>
</Border>
<!-- 命座 -->
<Border Padding="16" Style="{ThemeResource BorderCardStyle}">
<shvcont:SkillPivot ItemTemplate="{StaticResource TalentDataTemplate}" Skills="{Binding Selected.SkillDepot.Talents}"/>
</Border>
<!-- 搭配 -->
<Border Padding="16" Style="{ThemeResource BorderCardStyle}">
<Grid ColumnSpacing="8" RowSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid Padding="16">
<StackPanel VerticalAlignment="Center" Visibility="{Binding Avatars.Count, Converter={StaticResource Int32ToVisibilityRevertConverter}}">
<shci:CachedImage
Height="120"
MinWidth="{ThemeResource SettingsCardContentControlMinWidth}"
EnableLazyLoading="False"
Source="{StaticResource UI_EmotionIcon89}"/>
<TextBlock
Margin="0,5,0,21"
HorizontalAlignment="Center"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{shcm:ResourceString Name=ControlAutoSuggestBoxNotFoundValue}"/>
</StackPanel>
<ScrollViewer Visibility="{Binding Avatars.Count, Converter={StaticResource Int32ToVisibilityConverter}}">
<StackPanel HorizontalAlignment="Left" Spacing="16">
<!-- 简介 -->
<Grid Style="{ThemeResource GridCardStyle}">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
Grid.Column="0"
Style="{StaticResource BaseTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewPageWiKiAvatarTeamCombinationHeader}"/>
<ItemsControl
Grid.Row="1"
Grid.Column="0"
ItemTemplate="{StaticResource CollocationTemplate}"
ItemsPanel="{StaticResource StackPanelSpacing4Template}"
ItemsSource="{Binding Selected.Collocation.Avatars}"/>
<TextBlock
Grid.Row="0"
Grid.Column="1"
Style="{StaticResource BaseTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewPageWiKiAvatarWeaponCombinationHeader}"/>
<ItemsControl
Grid.Row="1"
Grid.Column="1"
ItemTemplate="{StaticResource CollocationTemplate}"
ItemsPanel="{StaticResource StackPanelSpacing4Template}"
ItemsSource="{Binding Selected.Collocation.Weapons}"/>
<TextBlock
Grid.Row="0"
Grid.Column="2"
Style="{StaticResource BaseTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewPageWiKiAvatarArtifactSetCombinationHeader}"/>
<ItemsControl
Grid.Row="1"
Grid.Column="2"
ItemTemplate="{StaticResource CollocationReliquaryTemplate}"
ItemsPanel="{StaticResource StackPanelSpacing4Template}"
ItemsSource="{Binding Selected.Collocation.ReliquarySets}"/>
</Grid>
</Border>
<!-- 立绘 -->
<cwc:ConstrainedBox AspectRatio="2048:1024">
<Grid Style="{ThemeResource GridCardStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<!-- 使其有较低的ZOrder -->
<shci:CachedImage Grid.ColumnSpan="2" Source="{Binding Selected.Icon, Converter={StaticResource GachaAvatarImgConverter}}"/>
<StackPanel Grid.Column="0" Margin="16">
<Grid Margin="0,0,0,12" ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<shci:MonoChrome
Grid.Column="0"
Width="32"
Height="32"
HorizontalAlignment="Left"
Source="{Binding Selected.FetterInfo.VisionBefore, Converter={StaticResource ElementNameIconConverter}}"/>
<shci:MonoChrome
Grid.Column="1"
Width="32"
Height="32"
Source="{Binding Selected.Weapon, Converter={StaticResource WeaponTypeIconConverter}}"/>
</Grid>
<shvcont:ItemIcon
Width="128"
Height="128"
Icon="{Binding Selected.Icon, Converter={StaticResource AvatarIconConverter}, Mode=OneWay}"
Quality="{Binding Selected.Quality, Mode=OneWay}"/>
</StackPanel>
<Border
Grid.Column="0"
Margin="16"
Style="{StaticResource BorderCardStyle}">
<cwc:ConstrainedBox AspectRatio="320:1024">
<shci:CachedImage CornerRadius="{ThemeResource ControlCornerRadius}" Source="{Binding Selected.Icon, Converter={StaticResource GachaAvatarIconConverter}}"/>
</cwc:ConstrainedBox>
</Border>
<StackPanel Grid.Column="1" Margin="16">
<StackPanel Margin="0,0,0,2" Orientation="Horizontal">
<TextBlock
VerticalAlignment="Center"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{Binding Selected.Name}"/>
<TextBlock
Margin="24,0,0,0"
VerticalAlignment="Center"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{Binding Selected.FetterInfo.Title}"/>
</StackPanel>
<TextBlock
Opacity="0.7"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Selected.FetterInfo.Detail}"
TextWrapping="NoWrap"/>
<cwc:UniformGrid
Margin="0,16,0,0"
ColumnSpacing="6"
Columns="4">
<StackPanel>
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageWiKiAvatarOccupationNameTitle}"/>
<TextBlock
Margin="0,6,0,0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Selected.FetterInfo.Native}"
TextWrapping="NoWrap"/>
</StackPanel>
<StackPanel>
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageWiKiAvatarConstellationNameTitle}"/>
<TextBlock
Margin="0,6,0,0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Selected.FetterInfo.ConstellationBefore}"
TextWrapping="NoWrap"/>
</StackPanel>
<StackPanel>
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageWiKiAvatarDateofBirthTitle}"/>
<TextBlock
Margin="0,6,0,0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Selected.FetterInfo.BirthFormatted}"
TextWrapping="NoWrap"/>
</StackPanel>
</cwc:UniformGrid>
<cwc:UniformGrid
Margin="0,12,0,0"
ColumnSpacing="6"
Columns="4">
<StackPanel>
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageWiKiAvatarChineseCVNameTitle}"/>
<TextBlock
Margin="0,6,0,0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Selected.FetterInfo.CvChinese}"
TextWrapping="NoWrap"/>
</StackPanel>
<StackPanel>
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageWiKiAvatarJapaneseCVNameTitle}"/>
<TextBlock
Margin="0,6,0,0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Selected.FetterInfo.CvJapanese}"
TextWrapping="NoWrap"/>
</StackPanel>
<StackPanel>
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageWiKiAvatarEnglishCVNameTitle}"/>
<TextBlock
Margin="0,6,0,0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Selected.FetterInfo.CvEnglish}"
TextWrapping="NoWrap"/>
</StackPanel>
<StackPanel>
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageWiKiAvatarKoreanCVNameTitle}"/>
<TextBlock
Margin="0,6,0,0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Selected.FetterInfo.CvKorean}"
TextWrapping="NoWrap"/>
</StackPanel>
</cwc:UniformGrid>
</StackPanel>
<StackPanel Grid.Row="1" Grid.ColumnSpan="2">
<ItemsControl
Margin="16,0,16,16"
ItemTemplate="{StaticResource CultivationItemTemplate}"
ItemsSource="{Binding Selected.CultivationItemsView}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<cwc:UniformGrid
ColumnSpacing="8"
Columns="3"
RowSpacing="8"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</Grid>
</cwc:ConstrainedBox>
<!-- 料理 -->
<Border Style="{ThemeResource BorderCardStyle}">
<Border.Resources>
<SolidColorBrush x:Key="ExpanderContentBackground" Color="Transparent"/>
<SolidColorBrush x:Key="ExpanderHeaderBackground" Color="Transparent"/>
</Border.Resources>
<Expander
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Header="{shcm:ResourceString Name=ViewPageWiKiAvatarFoodHeader}"
IsExpanded="True">
<Grid DataContext="{Binding Selected.CookBonusView}">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<!-- 属性 -->
<Border Style="{ThemeResource BorderCardStyle}">
<Border.Resources>
<SolidColorBrush x:Key="ToggleButtonBackground" Color="Transparent"/>
<SolidColorBrush x:Key="ExpanderContentBackground" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackground" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackgroundDisabled" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackgroundPointerOver" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackgroundPressed" Color="Transparent"/>
</Border.Resources>
<shvcont:BaseValueSlider
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
BaseValueInfo="{Binding BaseValueInfo, Mode=OneWay}"/>
</Border>
<!-- 天赋 -->
<Border Padding="16" Style="{ThemeResource BorderCardStyle}">
<shvcont:SkillPivot ItemTemplate="{StaticResource SkillDataTemplate}" Skills="{Binding Selected.SkillDepot.CompositeSkills}"/>
</Border>
<!-- 命座 -->
<Border Padding="16" Style="{ThemeResource BorderCardStyle}">
<shvcont:SkillPivot ItemTemplate="{StaticResource TalentDataTemplate}" Skills="{Binding Selected.SkillDepot.Talents}"/>
</Border>
<!-- 搭配 -->
<Border Padding="16" Style="{ThemeResource BorderCardStyle}">
<Grid ColumnSpacing="8" RowSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
Grid.Column="0"
Style="{StaticResource BaseTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewPageWiKiAvatarTeamCombinationHeader}"/>
<ItemsControl
Grid.Row="1"
Grid.Column="0"
ItemTemplate="{StaticResource CollocationTemplate}"
ItemsPanel="{StaticResource StackPanelSpacing4Template}"
ItemsSource="{Binding Selected.Collocation.Avatars}"/>
<TextBlock
Grid.Row="0"
Grid.Column="1"
Style="{StaticResource BaseTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewPageWiKiAvatarWeaponCombinationHeader}"/>
<ItemsControl
Grid.Row="1"
Grid.Column="1"
ItemTemplate="{StaticResource CollocationTemplate}"
ItemsPanel="{StaticResource StackPanelSpacing4Template}"
ItemsSource="{Binding Selected.Collocation.Weapons}"/>
<TextBlock
Grid.Row="0"
Grid.Column="2"
Style="{StaticResource BaseTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewPageWiKiAvatarArtifactSetCombinationHeader}"/>
<ItemsControl
Grid.Row="1"
Grid.Column="2"
ItemTemplate="{StaticResource CollocationReliquaryTemplate}"
ItemsPanel="{StaticResource StackPanelSpacing4Template}"
ItemsSource="{Binding Selected.Collocation.ReliquarySets}"/>
</Grid>
</Border>
<!-- 立绘 -->
<cwc:ConstrainedBox AspectRatio="2048:1024">
<Grid Style="{ThemeResource GridCardStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock
<!-- 使其有较低的ZOrder -->
<shci:CachedImage Grid.ColumnSpan="2" Source="{Binding Selected.Icon, Converter={StaticResource GachaAvatarImgConverter}}"/>
<Border
Grid.Column="0"
Style="{StaticResource BaseTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewPageWiKiAvatarSpecialFoodTitle}"/>
<shvcont:BottomTextControl
Grid.Row="1"
Grid.Column="0"
Margin="0,16,0,0"
Text="{Binding Item.Name}">
<shvcont:ItemIcon Icon="{Binding Item.Icon, Converter={StaticResource ItemIconConverter}}" Quality="{Binding Item.RankLevel}"/>
</shvcont:BottomTextControl>
<TextBlock
Grid.Column="1"
Margin="16,0,0,0"
Style="{StaticResource BaseTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewPageWiKiAvatarOriginalFoodTitle}"/>
<shvcont:BottomTextControl
Grid.Row="1"
Grid.Column="1"
Margin="16,16,0,0"
Text="{Binding OriginItem.Name}">
<shvcont:ItemIcon Icon="{Binding OriginItem.Icon, Converter={StaticResource ItemIconConverter}}" Quality="{Binding OriginItem.RankLevel}"/>
</shvcont:BottomTextControl>
<StackPanel
Grid.RowSpan="4"
Grid.Column="2"
Margin="16,0,0,0">
<TextBlock
Grid.Row="2"
Grid.ColumnSpan="4"
Text="{Binding Item.Description}"
TextWrapping="Wrap"/>
<TextBlock
Grid.Row="3"
Grid.ColumnSpan="4"
Margin="0,16,0,0"
Text="{Binding Item.EffectDescription}"
TextWrapping="Wrap"/>
</StackPanel>
Margin="16"
Style="{StaticResource BorderCardStyle}">
<cwc:ConstrainedBox AspectRatio="320:1024">
<shci:CachedImage CornerRadius="{ThemeResource ControlCornerRadius}" Source="{Binding Selected.Icon, Converter={StaticResource GachaAvatarIconConverter}}"/>
</cwc:ConstrainedBox>
</Border>
</Grid>
</Expander>
</Border>
</cwc:ConstrainedBox>
<!-- 衣装 -->
<Border Style="{ThemeResource BorderCardStyle}">
<Border.Resources>
<SolidColorBrush x:Key="ExpanderContentBackground" Color="Transparent"/>
<SolidColorBrush x:Key="ExpanderHeaderBackground" Color="Transparent"/>
</Border.Resources>
<Expander
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Header="{shcm:ResourceString Name=ViewPageWiKiAvatarCostumeHeader}"
IsExpanded="True">
<ItemsControl
Margin="0,0,0,-16"
ItemTemplate="{StaticResource CostumeTemplate}"
ItemsSource="{Binding Selected.Costumes}"/>
</Expander>
</Border>
<!-- 料理 -->
<Border Style="{ThemeResource BorderCardStyle}">
<Border.Resources>
<SolidColorBrush x:Key="ExpanderContentBackground" Color="Transparent"/>
<SolidColorBrush x:Key="ExpanderHeaderBackground" Color="Transparent"/>
</Border.Resources>
<Expander
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Header="{shcm:ResourceString Name=ViewPageWiKiAvatarFoodHeader}"
IsExpanded="True">
<Grid DataContext="{Binding Selected.CookBonusView}">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
Style="{StaticResource BaseTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewPageWiKiAvatarSpecialFoodTitle}"/>
<shvcont:BottomTextControl
Grid.Row="1"
Grid.Column="0"
Margin="0,16,0,0"
Text="{Binding Item.Name}">
<shvcont:ItemIcon Icon="{Binding Item.Icon, Converter={StaticResource ItemIconConverter}}" Quality="{Binding Item.RankLevel}"/>
</shvcont:BottomTextControl>
<TextBlock
Grid.Column="1"
Margin="16,0,0,0"
Style="{StaticResource BaseTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewPageWiKiAvatarOriginalFoodTitle}"/>
<shvcont:BottomTextControl
Grid.Row="1"
Grid.Column="1"
Margin="16,16,0,0"
Text="{Binding OriginItem.Name}">
<shvcont:ItemIcon Icon="{Binding OriginItem.Icon, Converter={StaticResource ItemIconConverter}}" Quality="{Binding OriginItem.RankLevel}"/>
</shvcont:BottomTextControl>
<StackPanel
Grid.RowSpan="4"
Grid.Column="2"
Margin="16,0,0,0">
<TextBlock
Grid.Row="2"
Grid.ColumnSpan="4"
Text="{Binding Item.Description}"
TextWrapping="Wrap"/>
<TextBlock
Grid.Row="3"
Grid.ColumnSpan="4"
Margin="0,16,0,0"
Text="{Binding Item.EffectDescription}"
TextWrapping="Wrap"/>
</StackPanel>
</Grid>
</Expander>
</Border>
<!-- 资料 -->
<Border Style="{ThemeResource BorderCardStyle}">
<Border.Resources>
<SolidColorBrush x:Key="ToggleButtonBackground" Color="Transparent"/>
<SolidColorBrush x:Key="ExpanderContentBackground" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackground" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackgroundDisabled" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackgroundPointerOver" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackgroundPressed" Color="Transparent"/>
</Border.Resources>
<ScrollViewer VerticalScrollBarVisibility="Hidden">
<cwc:SettingsExpander
Header="{shcm:ResourceString Name=ViewPageWiKiAvatarQuotesHeader}"
ItemTemplate="{StaticResource FetterStoryTemplate}"
ItemsSource="{Binding Selected.FetterInfo.Fetters}"/>
</ScrollViewer>
</Border>
<!-- 衣装 -->
<Border Style="{ThemeResource BorderCardStyle}">
<Border.Resources>
<SolidColorBrush x:Key="ExpanderContentBackground" Color="Transparent"/>
<SolidColorBrush x:Key="ExpanderHeaderBackground" Color="Transparent"/>
</Border.Resources>
<Expander
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Header="{shcm:ResourceString Name=ViewPageWiKiAvatarCostumeHeader}"
IsExpanded="True">
<ItemsControl
Margin="0,0,0,-16"
ItemTemplate="{StaticResource CostumeTemplate}"
ItemsSource="{Binding Selected.Costumes}"/>
</Expander>
</Border>
<!-- 故事 -->
<Border Style="{ThemeResource BorderCardStyle}">
<Border.Resources>
<SolidColorBrush x:Key="ToggleButtonBackground" Color="Transparent"/>
<SolidColorBrush x:Key="ExpanderContentBackground" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackground" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackgroundDisabled" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackgroundPointerOver" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackgroundPressed" Color="Transparent"/>
</Border.Resources>
<ScrollViewer VerticalScrollBarVisibility="Hidden">
<cwc:SettingsExpander
Header="{shcm:ResourceString Name=ViewPageWiKiAvatarStoriesHeader}"
ItemTemplate="{StaticResource FetterStoryTemplate}"
ItemsSource="{Binding Selected.FetterInfo.FetterStories}"/>
</ScrollViewer>
</Border>
</StackPanel>
</ScrollViewer>
<!-- 资料 -->
<Border Style="{ThemeResource BorderCardStyle}">
<Border.Resources>
<SolidColorBrush x:Key="ToggleButtonBackground" Color="Transparent"/>
<SolidColorBrush x:Key="ExpanderContentBackground" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackground" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackgroundDisabled" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackgroundPointerOver" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackgroundPressed" Color="Transparent"/>
</Border.Resources>
<ScrollViewer VerticalScrollBarVisibility="Hidden">
<cwc:SettingsExpander
Header="{shcm:ResourceString Name=ViewPageWiKiAvatarQuotesHeader}"
ItemTemplate="{StaticResource FetterStoryTemplate}"
ItemsSource="{Binding Selected.FetterInfo.Fetters}"/>
</ScrollViewer>
</Border>
<!-- 故事 -->
<Border Style="{ThemeResource BorderCardStyle}">
<Border.Resources>
<SolidColorBrush x:Key="ToggleButtonBackground" Color="Transparent"/>
<SolidColorBrush x:Key="ExpanderContentBackground" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackground" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackgroundDisabled" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackgroundPointerOver" Color="Transparent"/>
<SolidColorBrush x:Key="SettingsCardBackgroundPressed" Color="Transparent"/>
</Border.Resources>
<ScrollViewer VerticalScrollBarVisibility="Hidden">
<cwc:SettingsExpander
Header="{shcm:ResourceString Name=ViewPageWiKiAvatarStoriesHeader}"
ItemTemplate="{StaticResource FetterStoryTemplate}"
ItemsSource="{Binding Selected.FetterInfo.FetterStories}"/>
</ScrollViewer>
</Border>
</StackPanel>
</ScrollViewer>
</Grid>
</SplitView.Content>
</SplitView>
</Border>
@@ -733,19 +745,33 @@
<cwc:Case Value="Grid">
<Border Margin="16,0,16,16" cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
<Border Style="{ThemeResource AcrylicBorderCardStyle}">
<GridView
Padding="16,16,4,4"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left"
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
ItemTemplate="{StaticResource AvatarGridTemplate}"
ItemsSource="{Binding Avatars}"
SelectedItem="{Binding Selected, Mode=TwoWay}"
SelectionMode="Single">
<mxi:Interaction.Behaviors>
<shcb:SelectedItemInViewBehavior/>
</mxi:Interaction.Behaviors>
</GridView>
<Grid Padding="16,16,4,4">
<StackPanel VerticalAlignment="Center" Visibility="{Binding Avatars.Count, Converter={StaticResource Int32ToVisibilityRevertConverter}}">
<shci:CachedImage
Height="120"
MinWidth="{ThemeResource SettingsCardContentControlMinWidth}"
EnableLazyLoading="False"
Source="{StaticResource UI_EmotionIcon89}"/>
<TextBlock
Margin="0,5,0,21"
HorizontalAlignment="Center"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{shcm:ResourceString Name=ControlAutoSuggestBoxNotFoundValue}"/>
</StackPanel>
<GridView
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left"
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
ItemTemplate="{StaticResource AvatarGridTemplate}"
ItemsSource="{Binding Avatars}"
SelectedItem="{Binding Selected, Mode=TwoWay}"
SelectionMode="Single"
Visibility="{Binding Avatars.Count, Converter={StaticResource Int32ToVisibilityConverter}}">
<mxi:Interaction.Behaviors>
<shcb:SelectedItemInViewBehavior/>
</mxi:Interaction.Behaviors>
</GridView>
</Grid>
</Border>
</Border>
</cwc:Case>

View File

@@ -185,6 +185,7 @@
PlaceholderText="{shcm:ResourceString Name=ViewPageWiKiWeaponAutoSuggestBoxPlaceHolder}"
QueryIcon="{cw:FontIconSource Glyph=&#xE721;}"
SuggestedItemTemplate="{StaticResource TokenTemplate}"
SuggestedItemsSource="{Binding AvailableTokens.Values}"
Text="{Binding FilterToken, Mode=TwoWay}"
TokenItemTemplate="{StaticResource TokenTemplate}">
<shca:AutoSuggestTokenBox.ItemsPanel>
@@ -232,111 +233,125 @@
</ListView>
</SplitView.Pane>
<SplitView.Content>
<ScrollViewer>
<StackPanel Padding="16" Spacing="16">
<Border Style="{ThemeResource BorderCardStyle}">
<Border.Background>
<ImageBrush ImageSource="ms-appx:///Resource/Icon/UI_GachaShowPanel_Bg_Weapon.png"/>
</Border.Background>
<cwc:ConstrainedBox AspectRatio="2048:1024">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border Grid.ColumnSpan="2" Background="{ThemeResource DarkOnlyOverlayMaskColorBrush}"/>
<ScrollViewer
Grid.Column="0"
Margin="16"
VerticalScrollBarVisibility="Hidden">
<StackPanel>
<shvc:BottomTextControl MaxWidth="80" Text="{shcm:ResourceString Name=ViewPageWiKiWeaponBeforeAscensionTitle}">
<shvc:ItemIcon Icon="{Binding Selected.Icon, Converter={StaticResource EquipIconConverter}}" Quality="{Binding Selected.RankLevel}"/>
</shvc:BottomTextControl>
<shvc:BottomTextControl Margin="0,16,0,0" Text="{shcm:ResourceString Name=ViewPageWiKiWeaponAfterAscensionTitle}">
<shvc:ItemIcon Icon="{Binding Selected.AwakenIcon, Converter={StaticResource EquipIconConverter}}" Quality="{Binding Selected.RankLevel}"/>
</shvc:BottomTextControl>
</StackPanel>
</ScrollViewer>
<Grid Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="176*"/>
<ColumnDefinition Width="848*"/>
</Grid.ColumnDefinitions>
<shci:CachedImage
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Stretch"
Source="{Binding Selected.Icon, Converter={StaticResource GachaEquipIconConverter}}"/>
</Grid>
<TextBlock
Grid.Column="1"
Margin="16"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{Binding Selected.Name}"/>
</Grid>
</cwc:ConstrainedBox>
</Border>
<TextBlock Text="{Binding Selected.Description}" TextWrapping="Wrap"/>
<shvc:BaseValueSlider
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
BaseValueInfo="{Binding BaseValueInfo, Mode=OneWay}"/>
<Border Padding="16" Style="{ThemeResource BorderCardStyle}">
<StackPanel Spacing="16">
<TextBlock
Margin="0,0,0,0"
Style="{StaticResource BaseTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewPageWiKiAvatarAscensionMaterialsHeader}"/>
<ItemsControl ItemTemplate="{StaticResource CultivateItemTemplate}" ItemsSource="{Binding Selected.CultivationItemsView}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<cwc:UniformGrid
ColumnSpacing="8"
Columns="3"
RowSpacing="8"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</Border>
<Border Padding="16" Style="{ThemeResource BorderCardStyle}">
<StackPanel Spacing="16" Visibility="{Binding Selected.Affix, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{Binding Selected.Affix.Name}"/>
<Pivot
Margin="-16,-16,0,0"
HeaderTemplate="{StaticResource AffixPivotHeaderTemplate}"
ItemTemplate="{StaticResource AffixPivotItemTemplate}"
ItemsSource="{Binding Selected.Affix.Descriptions}"/>
</StackPanel>
</Border>
<Border Padding="16" Style="{ThemeResource BorderCardStyle}">
<StackPanel Spacing="16">
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageWiKiAvatarTeamCombinationHeader}"/>
<ItemsControl ItemTemplate="{StaticResource CollocationTemplate}" ItemsSource="{Binding Selected.Collocation.Avatars}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<cwc:UniformGrid
ColumnSpacing="8"
Columns="3"
RowSpacing="8"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</Border>
<Grid Padding="16">
<StackPanel VerticalAlignment="Center" Visibility="{Binding Weapons.Count, Converter={StaticResource Int32ToVisibilityRevertConverter}}">
<shci:CachedImage
Height="120"
MinWidth="{ThemeResource SettingsCardContentControlMinWidth}"
EnableLazyLoading="False"
Source="{StaticResource UI_EmotionIcon89}"/>
<TextBlock
Margin="0,5,0,21"
HorizontalAlignment="Center"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{shcm:ResourceString Name=ControlAutoSuggestBoxNotFoundValue}"/>
</StackPanel>
</ScrollViewer>
<ScrollViewer Visibility="{Binding Weapons.Count, Converter={StaticResource Int32ToVisibilityConverter}}">
<StackPanel Spacing="16">
<Border Style="{ThemeResource BorderCardStyle}">
<Border.Background>
<ImageBrush ImageSource="ms-appx:///Resource/Icon/UI_GachaShowPanel_Bg_Weapon.png"/>
</Border.Background>
<cwc:ConstrainedBox AspectRatio="2048:1024">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border Grid.ColumnSpan="2" Background="{ThemeResource DarkOnlyOverlayMaskColorBrush}"/>
<ScrollViewer
Grid.Column="0"
Margin="16"
VerticalScrollBarVisibility="Hidden">
<StackPanel>
<shvc:BottomTextControl MaxWidth="80" Text="{shcm:ResourceString Name=ViewPageWiKiWeaponBeforeAscensionTitle}">
<shvc:ItemIcon Icon="{Binding Selected.Icon, Converter={StaticResource EquipIconConverter}}" Quality="{Binding Selected.RankLevel}"/>
</shvc:BottomTextControl>
<shvc:BottomTextControl Margin="0,16,0,0" Text="{shcm:ResourceString Name=ViewPageWiKiWeaponAfterAscensionTitle}">
<shvc:ItemIcon Icon="{Binding Selected.AwakenIcon, Converter={StaticResource EquipIconConverter}}" Quality="{Binding Selected.RankLevel}"/>
</shvc:BottomTextControl>
</StackPanel>
</ScrollViewer>
<Grid Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="176*"/>
<ColumnDefinition Width="848*"/>
</Grid.ColumnDefinitions>
<shci:CachedImage
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Stretch"
Source="{Binding Selected.Icon, Converter={StaticResource GachaEquipIconConverter}}"/>
</Grid>
<TextBlock
Grid.Column="1"
Margin="16"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{Binding Selected.Name}"/>
</Grid>
</cwc:ConstrainedBox>
</Border>
<TextBlock Text="{Binding Selected.Description}" TextWrapping="Wrap"/>
<shvc:BaseValueSlider
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
BaseValueInfo="{Binding BaseValueInfo, Mode=OneWay}"/>
<Border Padding="16" Style="{ThemeResource BorderCardStyle}">
<StackPanel Spacing="16">
<TextBlock
Margin="0,0,0,0"
Style="{StaticResource BaseTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewPageWiKiAvatarAscensionMaterialsHeader}"/>
<ItemsControl ItemTemplate="{StaticResource CultivateItemTemplate}" ItemsSource="{Binding Selected.CultivationItemsView}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<cwc:UniformGrid
ColumnSpacing="8"
Columns="3"
RowSpacing="8"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</Border>
<Border Padding="16" Style="{ThemeResource BorderCardStyle}">
<StackPanel Spacing="16" Visibility="{Binding Selected.Affix, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{Binding Selected.Affix.Name}"/>
<Pivot
Margin="-16,-16,0,0"
HeaderTemplate="{StaticResource AffixPivotHeaderTemplate}"
ItemTemplate="{StaticResource AffixPivotItemTemplate}"
ItemsSource="{Binding Selected.Affix.Descriptions}"/>
</StackPanel>
</Border>
<Border Padding="16" Style="{ThemeResource BorderCardStyle}">
<StackPanel Spacing="16">
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageWiKiAvatarTeamCombinationHeader}"/>
<ItemsControl ItemTemplate="{StaticResource CollocationTemplate}" ItemsSource="{Binding Selected.Collocation.Avatars}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<cwc:UniformGrid
ColumnSpacing="8"
Columns="3"
RowSpacing="8"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</Grid>
</SplitView.Content>
</SplitView>
</Border>
@@ -345,19 +360,34 @@
<cwc:Case Value="Grid">
<Border Margin="16,0,16,16" cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
<Border Style="{ThemeResource AcrylicBorderCardStyle}">
<GridView
Padding="16,16,4,4"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left"
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
ItemTemplate="{StaticResource WeaponGridTemplate}"
ItemsSource="{Binding Weapons}"
SelectedItem="{Binding Selected, Mode=TwoWay}"
SelectionMode="Single">
<mxi:Interaction.Behaviors>
<shcb:SelectedItemInViewBehavior/>
</mxi:Interaction.Behaviors>
</GridView>
<Grid Padding="16,16,4,4">
<StackPanel VerticalAlignment="Center" Visibility="{Binding Weapons.Count, Converter={StaticResource Int32ToVisibilityRevertConverter}}">
<shci:CachedImage
Height="120"
MinWidth="{ThemeResource SettingsCardContentControlMinWidth}"
EnableLazyLoading="False"
Source="{StaticResource UI_EmotionIcon89}"/>
<TextBlock
Margin="0,5,0,21"
HorizontalAlignment="Center"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{shcm:ResourceString Name=ControlAutoSuggestBoxNotFoundValue}"/>
</StackPanel>
<GridView
Padding="16,16,4,4"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left"
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
ItemTemplate="{StaticResource WeaponGridTemplate}"
ItemsSource="{Binding Weapons}"
SelectedItem="{Binding Selected, Mode=TwoWay}"
SelectionMode="Single"
Visibility="{Binding Weapons.Count, Converter={StaticResource Int32ToVisibilityConverter}}">
<mxi:Interaction.Behaviors>
<shcb:SelectedItemInViewBehavior/>
</mxi:Interaction.Behaviors>
</GridView>
</Grid>
</Border>
</Border>
</cwc:Case>

View File

@@ -14,6 +14,106 @@
xmlns:shvu="using:Snap.Hutao.ViewModel.User"
d:DataContext="{d:DesignInstance shvu:UserViewModel}"
mc:Ignorable="d">
<UserControl.Resources>
<shc:BindingProxy x:Key="ViewModelBindingProxy" DataContext="{Binding}"/>
<DataTemplate x:Key="UserGameRoleTemplate">
<StackPanel Padding="0,6">
<TextBlock Text="{Binding Nickname}"/>
<TextBlock
Margin="0,2,0,0"
Opacity="0.6"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Description}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="UserTemplate">
<Grid Padding="0,12" Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<PersonPicture
Height="32"
Margin="2,0"
HorizontalAlignment="Left"
ProfilePicture="{Binding UserInfo.AvatarUrl, Mode=OneWay}"/>
<TextBlock
Grid.Column="1"
Margin="12,0,0,0"
VerticalAlignment="Center"
Text="{Binding UserInfo.Nickname}"/>
<TextBlock
Grid.Column="2"
VerticalAlignment="Center"
Text="HoYoLAB"
Visibility="{Binding IsOversea}"/>
<StackPanel
x:Name="ButtonPanel"
Grid.Column="3"
Orientation="Horizontal"
Visibility="Collapsed">
<Button
Margin="12,0,0,0"
VerticalAlignment="Stretch"
Background="Transparent"
Command="{Binding DataContext.CopyCookieCommand, Source={StaticResource ViewModelBindingProxy}}"
CommandParameter="{Binding}"
Content="{StaticResource FontIconContentCopy}"
FontFamily="{StaticResource SymbolThemeFontFamily}"
Style="{StaticResource ButtonRevealStyle}"
ToolTipService.ToolTip="{shcm:ResourceString Name=ViewUserCopyCookieAction}"/>
<Button
Margin="6,0,0,0"
HorizontalAlignment="Right"
VerticalAlignment="Stretch"
Background="Transparent"
Command="{Binding DataContext.RemoveUserCommand, Source={StaticResource ViewModelBindingProxy}}"
CommandParameter="{Binding}"
Content="{StaticResource FontIconContentDelete}"
FontFamily="{StaticResource SymbolThemeFontFamily}"
Style="{StaticResource ButtonRevealStyle}"
ToolTipService.ToolTip="{shcm:ResourceString Name=ViewUserRemoveAction}"/>
</StackPanel>
<Grid.Resources>
<Storyboard x:Name="ButtonPanelVisibleStoryboard">
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonPanel" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Name="ButtonPanelCollapsedStoryboard">
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonPanel" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</Grid.Resources>
<mxi:Interaction.Behaviors>
<mxic:EventTriggerBehavior EventName="PointerEntered">
<mxim:ControlStoryboardAction Storyboard="{StaticResource ButtonPanelVisibleStoryboard}"/>
</mxic:EventTriggerBehavior>
<mxic:EventTriggerBehavior EventName="PointerExited">
<mxim:ControlStoryboardAction Storyboard="{StaticResource ButtonPanelCollapsedStoryboard}"/>
</mxic:EventTriggerBehavior>
</mxi:Interaction.Behaviors>
</Grid>
</DataTemplate>
</UserControl.Resources>
<mxi:Interaction.Behaviors>
<shcb:InvokeCommandOnLoadedBehavior Command="{Binding OpenUICommand}"/>
</mxi:Interaction.Behaviors>
@@ -57,7 +157,6 @@
<StaticResource x:Key="ButtonForegroundPressed" ResourceKey="NavigationViewItemForegroundPressed"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<shc:BindingProxy x:Key="ViewModelBindingProxy" DataContext="{Binding}"/>
</ResourceDictionary>
</StackPanel.Resources>
@@ -79,17 +178,9 @@
Grid.Column="1"
Margin="1,0,0,0"
VerticalAlignment="Center"
Text="{Binding SelectedUser.UserInfo.Nickname, Mode=OneWay}"
Text="{Binding SelectedUser.UserInfo.Nickname, Mode=OneWay, FallbackValue={shcm:ResourceString Name=ViewUserNoUserHint}}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap"/>
<TextBlock
Grid.Column="1"
Margin="1,0,0,0"
VerticalAlignment="Center"
Text="{shcm:ResourceString Name=ViewUserNoUserHint}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap"
Visibility="{Binding Users.Count, Converter={StaticResource Int32ToVisibilityRevertConverter}}"/>
<FontIcon
Grid.Column="2"
Margin="0,0,8,0"
@@ -231,29 +322,20 @@
<Grid Grid.Column="1" Width="280">
<StackPanel Visibility="{Binding Users.Count, Converter={StaticResource Int32ToVisibilityConverter}}">
<TextBlock
Margin="10,6,0,6"
Style="{StaticResource BaseTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewUserRole}"/>
<ListView
Grid.Row="1"
Margin="4"
ItemsSource="{Binding SelectedUser.UserGameRoles}"
SelectedItem="{Binding SelectedUser.SelectedUserGameRole, Mode=TwoWay}"
SelectionMode="Single">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Padding="0,6">
<TextBlock Text="{Binding Nickname}"/>
<TextBlock
Margin="0,2,0,0"
Opacity="0.6"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Description}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackPanel Visibility="{Binding SelectedUser, Converter={StaticResource EmptyObjectToVisibilityConverter}, Mode=OneWay}">
<TextBlock
Margin="10,6,0,6"
Style="{StaticResource BaseTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewUserRole}"/>
<ListView
Grid.Row="1"
Margin="4"
ItemTemplate="{StaticResource UserGameRoleTemplate}"
ItemsSource="{Binding SelectedUser.UserGameRoles}"
SelectedItem="{Binding SelectedUser.SelectedUserGameRole, Mode=TwoWay}"
SelectionMode="Single"/>
</StackPanel>
<TextBlock
Margin="10,6,0,6"
Style="{StaticResource BaseTextBlockStyle}"
@@ -263,6 +345,7 @@
Margin="4"
AllowDrop="{Binding RuntimeOptions.IsElevated, Converter={StaticResource BoolNegationConverter}}"
CanReorderItems="{Binding RuntimeOptions.IsElevated, Converter={StaticResource BoolNegationConverter}}"
ItemTemplate="{StaticResource UserTemplate}"
ItemsSource="{Binding Users}"
SelectedItem="{Binding SelectedUser, Mode=TwoWay}"
SelectionMode="Single">
@@ -275,91 +358,6 @@
Severity="Warning"
Visibility="{Binding RuntimeOptions.IsElevated, Converter={StaticResource BoolToVisibilityConverter}}"/>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<Grid Padding="0,12" Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<PersonPicture
Height="32"
Margin="2,0"
HorizontalAlignment="Left"
ProfilePicture="{Binding UserInfo.AvatarUrl, Mode=OneWay}"/>
<TextBlock
Grid.Column="1"
Margin="12,0,0,0"
VerticalAlignment="Center"
Text="{Binding UserInfo.Nickname}"/>
<TextBlock
Grid.Column="2"
VerticalAlignment="Center"
Text="HoYoLAB"
Visibility="{Binding IsOversea}"/>
<StackPanel
x:Name="ButtonPanel"
Grid.Column="3"
Orientation="Horizontal"
Visibility="Collapsed">
<Button
Margin="12,0,0,0"
VerticalAlignment="Stretch"
Background="Transparent"
Command="{Binding DataContext.CopyCookieCommand, Source={StaticResource ViewModelBindingProxy}}"
CommandParameter="{Binding}"
Content="{StaticResource FontIconContentCopy}"
FontFamily="{StaticResource SymbolThemeFontFamily}"
Style="{StaticResource ButtonRevealStyle}"
ToolTipService.ToolTip="{shcm:ResourceString Name=ViewUserCopyCookieAction}"/>
<Button
Margin="6,0,0,0"
HorizontalAlignment="Right"
VerticalAlignment="Stretch"
Background="Transparent"
Command="{Binding DataContext.RemoveUserCommand, Source={StaticResource ViewModelBindingProxy}}"
CommandParameter="{Binding}"
Content="{StaticResource FontIconContentDelete}"
FontFamily="{StaticResource SymbolThemeFontFamily}"
Style="{StaticResource ButtonRevealStyle}"
ToolTipService.ToolTip="{shcm:ResourceString Name=ViewUserRemoveAction}"/>
</StackPanel>
<Grid.Resources>
<Storyboard x:Name="ButtonPanelVisibleStoryboard">
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonPanel" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Name="ButtonPanelCollapsedStoryboard">
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonPanel" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</Grid.Resources>
<mxi:Interaction.Behaviors>
<mxic:EventTriggerBehavior EventName="PointerEntered">
<mxim:ControlStoryboardAction Storyboard="{StaticResource ButtonPanelVisibleStoryboard}"/>
</mxic:EventTriggerBehavior>
<mxic:EventTriggerBehavior EventName="PointerExited">
<mxim:ControlStoryboardAction Storyboard="{StaticResource ButtonPanelCollapsedStoryboard}"/>
</mxic:EventTriggerBehavior>
</mxi:Interaction.Behaviors>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
<TextBlock

View File

@@ -381,26 +381,29 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
{
SetProperty(ref selectedAchievementGoal, null);
if (!string.IsNullOrEmpty(search))
if (string.IsNullOrEmpty(search))
{
if (uint.TryParse(search, out uint achievementId))
{
Achievements.Filter = view => view.Inner.Id == achievementId;
return;
}
if (VersionRegex().IsMatch(search))
{
Achievements.Filter = view => view.Inner.Version == search;
return;
}
Achievements.Filter = view =>
{
return view.Inner.Title.Contains(search, StringComparison.CurrentCultureIgnoreCase)
|| view.Inner.Description.Contains(search, StringComparison.CurrentCultureIgnoreCase);
};
Achievements.Filter = default!;
return;
}
if (uint.TryParse(search, out uint achievementId))
{
Achievements.Filter = view => view.Inner.Id == achievementId;
return;
}
if (VersionRegex().IsMatch(search))
{
Achievements.Filter = view => view.Inner.Version == search;
return;
}
Achievements.Filter = view =>
{
return view.Inner.Title.Contains(search, StringComparison.CurrentCultureIgnoreCase)
|| view.Inner.Description.Contains(search, StringComparison.CurrentCultureIgnoreCase);
};
}
}

View File

@@ -28,7 +28,7 @@ internal sealed class StatisticsCultivateItem
public Material Inner { get; }
/// <summary>
/// 对应背包物品的个数
/// 对应需求物品的个数
/// </summary>
public uint Count { get; set; }
@@ -40,10 +40,10 @@ internal sealed class StatisticsCultivateItem
/// <summary>
/// 是否完成
/// </summary>
public bool IsFinished { get => Count >= TotalCount; }
public bool IsFinished { get => TotalCount >= Count; }
/// <summary>
/// 格式化总数
/// </summary>
public string CountFormatted { get => $"{Count}/{TotalCount}"; }
public string CountFormatted { get => $"{TotalCount}/{Count}"; }
}

View File

@@ -67,10 +67,13 @@ internal sealed partial class UserViewModel : ObservableObject
}
}
if (SetProperty(ref selectedUser, value))
if (!ReferenceEquals(selectedUser, value))
{
selectedUser = value;
userService.Current = value;
}
OnPropertyChanged(nameof(SelectedUser));
}
}
@@ -216,6 +219,11 @@ internal sealed partial class UserViewModel : ObservableObject
try
{
if (user.IsSelected)
{
SelectedUser = default;
}
await userService.RemoveUserAsync(user).ConfigureAwait(false);
infoBarService.Success(SH.FormatViewModelUserRemoved(user.UserInfo?.Nickname));
}

View File

@@ -119,12 +119,12 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel
availableTokens = FrozenDictionary.ToFrozenDictionary(
[
.. avatars.Select(avatar => KeyValuePair.Create(avatar.Name, new SearchToken(SearchTokenKind.Avatar, avatar.Name, sideIconUri: AvatarSideIconConverter.IconNameToUri(avatar.SideIcon)))),
.. IntrinsicFrozen.AssociationTypes.Select(assoc => KeyValuePair.Create(assoc, new SearchToken(SearchTokenKind.AssociationType, assoc, iconUri: AssociationTypeIconConverter.AssociationTypeNameToIconUri(assoc)))),
.. IntrinsicFrozen.BodyTypes.Select(b => KeyValuePair.Create(b, new SearchToken(SearchTokenKind.BodyType, b))),
.. IntrinsicFrozen.ElementNames.Select(e => KeyValuePair.Create(e, new SearchToken(SearchTokenKind.ElementName, e, iconUri: ElementNameIconConverter.ElementNameToIconUri(e)))),
.. IntrinsicFrozen.ItemQualities.Select(i => KeyValuePair.Create(i, new SearchToken(SearchTokenKind.ItemQuality, i, quality: QualityColorConverter.QualityNameToColor(i)))),
.. IntrinsicFrozen.WeaponTypes.Select(w => KeyValuePair.Create(w, new SearchToken(SearchTokenKind.WeaponType, w, iconUri: WeaponTypeIconConverter.WeaponTypeNameToIconUri(w)))),
.. avatars.Select((avatar, index) => KeyValuePair.Create(avatar.Name, new SearchToken(SearchTokenKind.Avatar, avatar.Name, index, sideIconUri: AvatarSideIconConverter.IconNameToUri(avatar.SideIcon)))),
.. IntrinsicFrozen.AssociationTypeNameValues.Select(nv => KeyValuePair.Create(nv.Name, new SearchToken(SearchTokenKind.AssociationType, nv.Name, (int)nv.Value, iconUri: AssociationTypeIconConverter.AssociationTypeToIconUri(nv.Value)))),
.. IntrinsicFrozen.BodyTypeNameValues.Select(nv => KeyValuePair.Create(nv.Name, new SearchToken(SearchTokenKind.BodyType, nv.Name, (int)nv.Value))),
.. IntrinsicFrozen.ElementNameValues.Select(nv => KeyValuePair.Create(nv.Name, new SearchToken(SearchTokenKind.ElementName, nv.Name, nv.Value, iconUri: ElementNameIconConverter.ElementNameToIconUri(nv.Name)))),
.. IntrinsicFrozen.ItemQualityNameValues.Select(nv => KeyValuePair.Create(nv.Name, new SearchToken(SearchTokenKind.ItemQuality, nv.Name, (int)nv.Value, quality: QualityColorConverter.QualityToColor(nv.Value)))),
.. IntrinsicFrozen.WeaponTypeNameValues.Select(nv => KeyValuePair.Create(nv.Name, new SearchToken(SearchTokenKind.WeaponType, nv.Name, (int)nv.Value, iconUri: WeaponTypeIconConverter.WeaponTypeToIconUri(nv.Value)))),
]);
return true;
@@ -246,10 +246,11 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel
if (FilterTokens.IsNullOrEmpty())
{
Avatars.Filter = default!;
return;
}
Avatars.Filter = AvatarFilter.Compile(FilterTokens);
else
{
Avatars.Filter = AvatarFilter.Compile(FilterTokens);
}
if (Selected is not null && Avatars.Contains(Selected))
{

View File

@@ -119,10 +119,10 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel
availableTokens = FrozenDictionary.ToFrozenDictionary(
[
.. weapons.Select(w => KeyValuePair.Create(w.Name, new SearchToken(SearchTokenKind.Weapon, w.Name, sideIconUri: EquipIconConverter.IconNameToUri(w.Icon)))),
.. IntrinsicFrozen.FightProperties.Select(f => KeyValuePair.Create(f, new SearchToken(SearchTokenKind.FightProperty, f))),
.. IntrinsicFrozen.ItemQualities.Select(i => KeyValuePair.Create(i, new SearchToken(SearchTokenKind.ItemQuality, i, quality: QualityColorConverter.QualityNameToColor(i)))),
.. IntrinsicFrozen.WeaponTypes.Select(w => KeyValuePair.Create(w, new SearchToken(SearchTokenKind.WeaponType, w, iconUri: WeaponTypeIconConverter.WeaponTypeNameToIconUri(w)))),
.. weapons.Select((weapon, index) => KeyValuePair.Create(weapon.Name, new SearchToken(SearchTokenKind.Weapon, weapon.Name, index, sideIconUri: EquipIconConverter.IconNameToUri(weapon.Icon)))),
.. IntrinsicFrozen.FightPropertyNameValues.Select(nv => KeyValuePair.Create(nv.Name, new SearchToken(SearchTokenKind.FightProperty, nv.Name, (int)nv.Value))),
.. IntrinsicFrozen.ItemQualityNameValues.Select(nv => KeyValuePair.Create(nv.Name, new SearchToken(SearchTokenKind.ItemQuality, nv.Name, (int)nv.Value, quality: QualityColorConverter.QualityToColor(nv.Value)))),
.. IntrinsicFrozen.WeaponTypeNameValues.Select(nv => KeyValuePair.Create(nv.Name, new SearchToken(SearchTokenKind.WeaponType, nv.Name, (int)nv.Value, iconUri: WeaponTypeIconConverter.WeaponTypeToIconUri(nv.Value)))),
]);
}
catch (OperationCanceledException)
@@ -228,10 +228,11 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel
if (FilterTokens.IsNullOrEmpty())
{
Weapons.Filter = default!;
return;
}
Weapons.Filter = WeaponFilter.Compile(FilterTokens);
else
{
Weapons.Filter = WeaponFilter.Compile(FilterTokens);
}
if (Selected is not null && Weapons.Contains(Selected))
{