This commit is contained in:
DismissedLight
2022-05-05 22:59:56 +08:00
9 changed files with 339 additions and 4 deletions

View File

@@ -3,6 +3,8 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.UI.Xaml;
using Snap.Hutao.Core;
using Snap.Hutao.Web.Request;
namespace Snap.Hutao;

View File

@@ -0,0 +1,39 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Net.Http;
namespace Snap.Hutao.Core;
/// <summary>
/// Http Json 处理
/// </summary>
public class HttpJson
{
private readonly Json json;
private readonly HttpClient httpClient;
/// <summary>
/// 初始化一个新的 Http Json 处理 实例
/// </summary>
/// <param name="json">Json 处理器</param>
/// <param name="httpClient">http 客户端</param>
public HttpJson(Json json, HttpClient httpClient)
{
this.json = json;
this.httpClient = httpClient;
}
/// <summary>
/// 从网站上下载json并转换为对象
/// </summary>
/// <typeparam name="T">对象的类型</typeparam>
/// <param name="url">链接</param>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>Json字符串中的反序列化对象, 如果反序列化失败会抛出异常</returns>
public async Task<T?> FromWebsiteAsync<T>(string url, CancellationToken cancellationToken = default)
{
string response = await httpClient.GetStringAsync(url, cancellationToken);
return json.ToObject<T>(response);
}
}

View File

@@ -0,0 +1,133 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Newtonsoft.Json;
using System.IO;
namespace Snap.Hutao.Core;
/// <summary>
/// Json操作
/// </summary>
[Injection(InjectAs.Transient)]
public class Json
{
private readonly ILogger logger;
private readonly JsonSerializerSettings jsonSerializerSettings = new()
{
DateFormatString = "yyyy'-'MM'-'dd' 'HH':'mm':'ss.FFFFFFFK",
Formatting = Formatting.Indented,
};
/// <summary>
/// 初始化一个新的 Json操作 实例
/// </summary>
/// <param name="logger">日志器</param>
public Json(ILogger<Json> logger)
{
this.logger = logger;
}
/// <summary>
/// 将JSON反序列化为指定的.NET类型
/// </summary>
/// <typeparam name="T">要反序列化的对象的类型</typeparam>
/// <param name="value">要反序列化的JSON</param>
/// <returns>Json字符串中的反序列化对象, 如果反序列化失败会抛出异常</returns>
public T? ToObject<T>(string value)
{
try
{
return JsonConvert.DeserializeObject<T>(value);
}
catch (Exception ex)
{
logger.LogError("反序列化Json时遇到问题:{ex}", ex);
}
return default;
}
/// <summary>
/// 将JSON反序列化为指定的.NET类型
/// 若为null则返回一个新建的实例
/// </summary>
/// <typeparam name="T">指定的类型</typeparam>
/// <param name="value">字符串</param>
/// <returns>Json字符串中的反序列化对象, 如果反序列化失败会抛出异常</returns>
public T ToObjectOrNew<T>(string value)
where T : new()
{
return ToObject<T>(value) ?? new T();
}
/// <summary>
/// 将指定的对象序列化为JSON字符串
/// </summary>
/// <param name="value">要序列化的对象</param>
/// <returns>对象的JSON字符串表示形式</returns>
public string Stringify(object? value)
{
return JsonConvert.SerializeObject(value, jsonSerializerSettings);
}
/// <summary>
/// 使用 <see cref="FileMode.Open"/>, <see cref="FileAccess.Read"/> 和 <see cref="FileShare.Read"/> 从文件中读取后转化为实体类
/// </summary>
/// <typeparam name="T">要反序列化的对象的类型</typeparam>
/// <param name="fileName">存放JSON数据的文件路径</param>
/// <returns>JSON字符串中的反序列化对象, 如果反序列化失败则抛出异常,若文件不存在则返回 <see langword="null"/></returns>
public T? FromFile<T>(string fileName)
{
if (File.Exists(fileName))
{
// FileShare.Read is important to read some file
using (StreamReader sr = new(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)))
{
return ToObject<T>(sr.ReadToEnd());
}
}
else
{
return default;
}
}
/// <summary>
/// 使用 <see cref="FileMode.Open"/>, <see cref="FileAccess.Read"/> 和 <see cref="FileShare.Read"/> 从文件中读取后转化为实体类
/// 若为null则返回一个新建的实例
/// </summary>
/// <typeparam name="T">要反序列化的对象的类型</typeparam>
/// <param name="fileName">存放JSON数据的文件路径</param>
/// <returns>JSON字符串中的反序列化对象</returns>
public T FromFileOrNew<T>(string fileName)
where T : new()
{
return FromFile<T>(fileName) ?? new T();
}
/// <summary>
/// 从文件中读取后转化为实体类
/// </summary>
/// <typeparam name="T">要反序列化的对象的类型</typeparam>
/// <param name="file">存放JSON数据的文件</param>
/// <returns>JSON字符串中的反序列化对象</returns>
public T? FromFile<T>(FileInfo file)
{
using (StreamReader sr = file.OpenText())
{
return ToObject<T>(sr.ReadToEnd());
}
}
/// <summary>
/// 将对象保存到文件
/// </summary>
/// <param name="fileName">文件名称</param>
/// <param name="value">对象</param>
public void ToFile(string fileName, object? value)
{
File.WriteAllText(fileName, Stringify(value));
}
}

View File

@@ -0,0 +1,43 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace Snap.Hutao.Core;
/// <summary>
/// 简单的实现了 <see cref="INotifyPropertyChanged"/> 接口
/// </summary>
public class Observable : INotifyPropertyChanged
{
/// <inheritdoc/>
public event PropertyChangedEventHandler? PropertyChanged;
/// <summary>
/// 设置字段的值
/// </summary>
/// <typeparam name="T">字段类型</typeparam>
/// <param name="storage">现有值</param>
/// <param name="value">新的值</param>
/// <param name="propertyName">属性名称</param>
protected void Set<T>([NotNullIfNotNull("value")] ref T storage, T value, [CallerMemberName] string propertyName = default!)
{
if (Equals(storage, value))
{
return;
}
storage = value;
OnPropertyChanged(propertyName);
}
/// <summary>
/// 触发 <see cref="PropertyChanged"/>
/// </summary>
/// <param name="propertyName">属性名称</param>
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

View File

@@ -14,7 +14,6 @@ namespace Snap.Hutao.Core.Threading;
public class Watcher : Observable
{
private readonly bool isReusable;
private bool hasUsed;
private bool isWorking;
private bool isCompleted;

View File

@@ -95,6 +95,16 @@
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="View\Page\AnnouncementContentPage.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="View\Page\AnnouncementPage.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="View\Page\SettingPage.xaml">
<Generator>MSBuild:Compile</Generator>

View File

@@ -0,0 +1,86 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Data;
namespace Snap.Hutao.View.Converter;
/// <summary>
/// This class converts a boolean value into an other object.
/// Can be used to convert true/false to visibility, a couple of colors, couple of images, etc.
/// </summary>
public class BoolToObjectConverter : DependencyObject, IValueConverter
{
/// <summary>
/// Identifies the <see cref="TrueValue"/> property.
/// </summary>
public static readonly DependencyProperty TrueValueProperty =
DependencyProperty.Register(nameof(TrueValue), typeof(object), typeof(BoolToObjectConverter), new PropertyMetadata(null));
/// <summary>
/// Identifies the <see cref="FalseValue"/> property.
/// </summary>
public static readonly DependencyProperty FalseValueProperty =
DependencyProperty.Register(nameof(FalseValue), typeof(object), typeof(BoolToObjectConverter), new PropertyMetadata(null));
/// <summary>
/// Gets or sets the value to be returned when the boolean is true
/// </summary>
public object TrueValue
{
get => GetValue(TrueValueProperty);
set => SetValue(TrueValueProperty, value);
}
/// <summary>
/// Gets or sets the value to be returned when the boolean is false
/// </summary>
public object FalseValue
{
get => GetValue(FalseValueProperty);
set => SetValue(FalseValueProperty, value);
}
/// <summary>
/// Convert a boolean value to an other object.
/// </summary>
/// <param name="value">The source data being passed to the target.</param>
/// <param name="targetType">The type of the target property, as a type reference.</param>
/// <param name="parameter">An optional parameter to be used to invert the converter logic.</param>
/// <param name="language">The language of the conversion.</param>
/// <returns>The value to be passed to the target dependency property.</returns>
public object Convert(object value, Type targetType, object parameter, string language)
{
bool boolValue = value is bool valid && valid;
// Negate if needed
if (ConvertHelper.TryParseBool(parameter))
{
boolValue = !boolValue;
}
return ConvertHelper.Convert(boolValue ? TrueValue : FalseValue, targetType);
}
/// <summary>
/// Convert back the value to a boolean
/// </summary>
/// <remarks>If the <paramref name="value"/> parameter is a reference type, <see cref="TrueValue"/> must match its reference to return true.</remarks>
/// <param name="value">The target data being passed to the source.</param>
/// <param name="targetType">The type of the target property, as a type reference (System.Type for Microsoft .NET, a TypeName helper struct for Visual C++ component extensions (C++/CX)).</param>
/// <param name="parameter">An optional parameter to be used to invert the converter logic.</param>
/// <param name="language">The language of the conversion.</param>
/// <returns>The value to be passed to the source object.</returns>
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
bool result = Equals(value, ConvertHelper.Convert(TrueValue, value.GetType()));
if (ConvertHelper.TryParseBool(parameter))
{
result = !result;
}
return result;
}
}

View File

@@ -0,0 +1,21 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
namespace Snap.Hutao.View.Converter;
/// <summary>
/// This class converts a boolean value into a Visibility enumeration.
/// </summary>
public class BoolToVisibilityConverter : BoolToObjectConverter
{
/// <summary>
/// Initializes a new instance of the <see cref="BoolToVisibilityConverter"/> class.
/// </summary>
public BoolToVisibilityConverter()
{
TrueValue = Visibility.Visible;
FalseValue = Visibility.Collapsed;
}
}

View File

@@ -29,9 +29,11 @@
<Frame x:Name="ContentFrame">
<Frame.ContentTransitions>
<NavigationThemeTransition>
<DrillInNavigationTransitionInfo/>
</NavigationThemeTransition>
<TransitionCollection>
<NavigationThemeTransition>
<DrillInNavigationTransitionInfo/>
</NavigationThemeTransition>
</TransitionCollection>
</Frame.ContentTransitions>
</Frame>
</NavigationView>