Skip to content

Commit

Permalink
integrate redeem code system
Browse files Browse the repository at this point in the history
  • Loading branch information
qhy040404 authored and Lightczx committed Jan 7, 2025
1 parent 3469851 commit 25907d3
Show file tree
Hide file tree
Showing 21 changed files with 390 additions and 12 deletions.
6 changes: 6 additions & 0 deletions src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1493,6 +1493,9 @@
<data name="ViewDialogHutaoPassportUnregisterTitle" xml:space="preserve">
<value>注销胡桃通行证账号</value>
</data>
<data name="ViewDialogHutaoPassportUseRedeemCodeTitle" xml:space="preserve">
<value>使用胡桃云兑换码</value>
</data>
<data name="ViewDialogImportExportApp" xml:space="preserve">
<value>导出 App</value>
</data>
Expand Down Expand Up @@ -2690,6 +2693,9 @@
<data name="ViewPageHutaoPassportPasswordRequirementHint" xml:space="preserve">
<value>至少需要 8 个字符</value>
</data>
<data name="ViewPageHutaoPassportRedeemCodeHint" xml:space="preserve">
<value>请输入兑换码</value>
</data>
<data name="ViewPageHutaoPassportRegisterHeader" xml:space="preserve">
<value>注册</value>
</data>
Expand Down
21 changes: 21 additions & 0 deletions src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoUserOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Snap.Hutao.Core.Setting;
using Snap.Hutao.Service.Notification;
using Snap.Hutao.Web.Hutao;
using Snap.Hutao.Web.Hutao.Redeem;
using Snap.Hutao.Web.Hutao.Response;
using Snap.Hutao.Web.Response;

Expand Down Expand Up @@ -127,6 +128,26 @@ public async ValueTask RefreshUserInfoAsync(CancellationToken token = default)
}
}

public async ValueTask UseRedeemCodeAsync(string code, CancellationToken token = default)
{
using (await operationLock.LockAsync(nameof(UseRedeemCodeAsync)).ConfigureAwait(false))
{
using (IServiceScope scope = serviceProvider.CreateScope())
{
HutaoRedeemCodeClient hutaoRedeemCodeClient = scope.ServiceProvider.GetRequiredService<HutaoRedeemCodeClient>();
HutaoResponse<RedeemUseResponse> response = await hutaoRedeemCodeClient.UseRedeemCodeAsync(new(code), token).ConfigureAwait(false);

if (!ResponseValidator.TryValidate(response, scope.ServiceProvider))
{
return;
}

infoBarService.Information(response.GetLocalizationMessageOrMessage());
await RefreshUserInfoAsync(token).ConfigureAwait(false);
}
}
}

public async ValueTask LoginAsync(string username, string password, bool resuming = false, CancellationToken token = default)
{
using (await operationLock.LockAsync(nameof(LoginAsync)).ConfigureAwait(false))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<ContentDialog
x:Class="Snap.Hutao.UI.Xaml.View.Dialog.HutaoPassportUseRedeemCodeDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:shuxm="using:Snap.Hutao.UI.Xaml.Markup"
Title="{shuxm:ResourceString Name=ViewDialogHutaoPassportUseRedeemCodeTitle}"
CloseButtonText="{shuxm:ResourceString Name=ContentDialogCancelCloseButtonText}"
DefaultButton="Primary"
PrimaryButtonText="{shuxm:ResourceString Name=ContentDialogConfirmPrimaryButtonText}"
Style="{StaticResource DefaultContentDialogStyle}"
mc:Ignorable="d">

<TextBox
IsSpellCheckEnabled="False"
PlaceholderText="{shuxm:ResourceString Name=ViewPageHutaoPassportRedeemCodeHint}"
Text="{x:Bind RedeemCode, Mode=TwoWay}"/>
</ContentDialog>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.

using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Factory.ContentDialog;
using Snap.Hutao.Service.Notification;

namespace Snap.Hutao.UI.Xaml.View.Dialog;

[ConstructorGenerated(InitializeComponent = true)]
[DependencyProperty("RedeemCode", typeof(string))]
internal sealed partial class HutaoPassportUseRedeemCodeDialog : ContentDialog
{
private readonly IContentDialogFactory contentDialogFactory;
private readonly IServiceScopeFactory serviceScopeFactory;
private readonly IInfoBarService infoBarService;

public async ValueTask<ValueResult<bool, string>> GetInputAsync()
{
ContentDialogResult result = await contentDialogFactory.EnqueueAndShowAsync(this).ShowTask.ConfigureAwait(false);
await contentDialogFactory.TaskContext.SwitchToMainThreadAsync();
return new(result is ContentDialogResult.Primary, RedeemCode);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@
</Button>
</cwc:SettingsCard>
<cwc:SettingsCard
Command="{Binding OpenRedeemWebsiteCommand}"
Command="{Binding UseRedeemCodeCommand}"
Description="{shuxm:ResourceString Name=ViewPageSettingHutaoPassportRedeemCodeDescription}"
Header="{shuxm:ResourceString Name=ViewPageSettingHutaoPassportRedeemCodeHeader}"
IsClickEnabled="True"/>
Expand Down
45 changes: 44 additions & 1 deletion src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/TestPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
xmlns:shuxc="using:Snap.Hutao.UI.Xaml.Control"
xmlns:shuxvww="using:Snap.Hutao.UI.Xaml.View.Window.WebView2"
xmlns:shv="using:Snap.Hutao.ViewModel"
xmlns:shwhr="using:Snap.Hutao.Web.Hutao.Redeem"
d:DataContext="{d:DesignInstance shv:TestViewModel}"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
Expand Down Expand Up @@ -217,6 +218,48 @@
</StackPanel>
</cwc:SettingsCard>

<Expander
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Header="Generate Redeem Code"
IsExpanded="True">
<StackPanel Spacing="8">
<NumberBox
Header="Count"
PlaceholderText="Code count"
Text="{Binding RedeemCodeGenerateOption.Count, Mode=TwoWay}"/>
<StackPanel Orientation="Horizontal" Spacing="8">
<CheckBox Content="IsTimeLimited" IsChecked="{Binding RedeemCodeGenerateOption.IsTimeLimited, Mode=TwoWay}"/>
<CheckBox Content="IsTimesLimited" IsChecked="{Binding RedeemCodeGenerateOption.IsTimesLimited, Mode=TwoWay}"/>
</StackPanel>
<shuxc:SizeRestrictedContentControl>
<ComboBox
Header="ServiceType"
ItemsSource="{cwh:EnumValues Type=shwhr:RedeemCodeTargetServiceType}"
SelectedItem="{Binding RedeemCodeGenerateOption.ServiceType, Mode=TwoWay}"/>
</shuxc:SizeRestrictedContentControl>
<NumberBox
Header="Value"
PlaceholderText="Days"
Text="{Binding RedeemCodeGenerateOption.Value, Mode=TwoWay}"/>
<TextBox
Header="Description"
PlaceholderText="Code description"
Text="{Binding RedeemCodeGenerateOption.Description, Mode=TwoWay}"/>
<NumberBox
Header="Expire Hours"
IsEnabled="{Binding RedeemCodeGenerateOption.IsTimeLimited}"
PlaceholderText="72"
Text="{Binding RedeemCodeGenerateOption.ExpireHours, Mode=TwoWay}"/>
<NumberBox
Header="Times"
IsEnabled="{Binding RedeemCodeGenerateOption.IsTimesLimited}"
PlaceholderText="Limited times"
Text="{Binding RedeemCodeGenerateOption.Times, Mode=TwoWay}"/>
<Button Command="{Binding GenerateRedeemCodeCommand}" Content="Generate"/>
</StackPanel>
</Expander>

<TextBlock Style="{ThemeResource SettingsSectionHeaderTextBlockStyle}" Text="Testing"/>
<cwc:SettingsCard
Command="{Binding ScreenCaptureCommand}"
Expand Down Expand Up @@ -306,4 +349,4 @@
</ScrollViewer>
</Border>

</shuxc:ScopedPage>
</shuxc:ScopedPage>
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using Snap.Hutao.UI.Xaml.View.Dialog;
using Snap.Hutao.UI.Xaml.View.Page;
using Snap.Hutao.Web.Endpoint.Hutao;
using Windows.System;

namespace Snap.Hutao.ViewModel.HutaoPassport;

Expand All @@ -21,12 +20,6 @@ internal sealed partial class HutaoPassportViewModel : Abstraction.ViewModel

public partial HutaoUserOptions HutaoUserOptions { get; }

[Command("OpenRedeemWebsiteCommand")]
private async Task OpenRedeemWebsiteAsync()
{
await Launcher.LaunchUriAsync(hutaoEndpointsFactory.Create().HomaWebsite("redeem.html").ToUri());
}

[Command("OpenTestPageCommand")]
private async Task OpenTestPageAsync()
{
Expand Down Expand Up @@ -150,6 +143,25 @@ private async Task ResetPasswordAsync()
await HutaoUserOptions.ResetPasswordAsync(username, password, verifyCode).ConfigureAwait(false);
}

[Command("UseRedeemCodeCommand")]
private async Task UseRedeemCodeAsync()
{
HutaoPassportUseRedeemCodeDialog dialog = await contentDialogFactory.CreateInstanceAsync<HutaoPassportUseRedeemCodeDialog>().ConfigureAwait(false);
(bool isOk, string redeemCode) = await dialog.GetInputAsync().ConfigureAwait(false);

if (!isOk)
{
return;
}

if (string.IsNullOrEmpty(redeemCode))
{
return;
}

await HutaoUserOptions.UseRedeemCodeAsync(redeemCode).ConfigureAwait(false);
}

[Command("RefreshUserInfoCommand")]
private async Task RefreshUserInfoAsync()
{
Expand Down
83 changes: 82 additions & 1 deletion src/Snap.Hutao/Snap.Hutao/ViewModel/TestViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.

using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Core.DataTransfer;
using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.Core.Graphics;
using Snap.Hutao.Core.IO;
Expand All @@ -23,9 +25,10 @@
using Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect;
using Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.Branch;
using Snap.Hutao.Web.Hutao.HutaoAsAService;
using Snap.Hutao.Web.Hutao.Redeem;
using Snap.Hutao.Web.Hutao.Response;
using Snap.Hutao.Web.Response;
using Snap.Hutao.Win32.Foundation;
using System.Data.SqlTypes;
using System.IO;

namespace Snap.Hutao.ViewModel;
Expand All @@ -38,6 +41,7 @@ internal sealed partial class TestViewModel : Abstraction.ViewModel
private readonly ICurrentXamlWindowReference currentXamlWindowReference;
private readonly IGameScreenCaptureService gameScreenCaptureService;
private readonly IContentDialogFactory contentDialogFactory;
private readonly IClipboardProvider clipboardProvider;
private readonly IServiceProvider serviceProvider;
private readonly IInfoBarService infoBarService;
private readonly ILogger<TestViewModel> logger;
Expand All @@ -55,6 +59,8 @@ internal sealed partial class TestViewModel : Abstraction.ViewModel

public DesignationOptions CdnDesignationOptions { get; } = new();

public RedeemCodeGenerateOptions RedeemCodeGenerateOption { get; set => SetProperty(ref field, value); } = new();

public bool SuppressMetadataInitialization
{
get => LocalSetting.Get(SettingKeys.SuppressMetadataInitialization, false);
Expand Down Expand Up @@ -448,6 +454,62 @@ private async Task ExtractGameExeAsync()
}
}

[Command("GenerateRedeemCodeCommand")]
private async Task GenerateRedeemCodeAsync()
{
RedeemCodeType type = RedeemCodeType.None;
if (RedeemCodeGenerateOption.IsTimeLimited)
{
type |= RedeemCodeType.TimeLimited;
}

if (RedeemCodeGenerateOption.IsTimesLimited)
{
type |= RedeemCodeType.TimesLimited;
}

if (type is RedeemCodeType.None)
{
infoBarService.Warning("Please select at least one type");
return;
}

if (RedeemCodeGenerateOption.ServiceType is RedeemCodeTargetServiceType.None)
{
infoBarService.Warning("Please select a service type");
return;
}

RedeemGenerateRequest request = new()
{
Count = (uint)RedeemCodeGenerateOption.Count,
Type = type,
ServiceType = RedeemCodeGenerateOption.ServiceType,
Value = RedeemCodeGenerateOption.Value,
Description = RedeemCodeGenerateOption.Description,
ExpireTime = DateTimeOffset.UtcNow.AddHours(RedeemCodeGenerateOption.ExpireHours),
Times = (uint)RedeemCodeGenerateOption.Times,
};

using (IServiceScope scope = serviceProvider.CreateScope())
{
HutaoAsAServiceClient hutaoAsAServiceClient = scope.ServiceProvider.GetRequiredService<HutaoAsAServiceClient>();
HutaoResponse<RedeemGenerateResponse> response = await hutaoAsAServiceClient.GenerateRedeemCodesAsync(request).ConfigureAwait(false);
if (ResponseValidator.TryValidate(response, scope.ServiceProvider, out RedeemGenerateResponse? generateResponse))
{
string message = $"""
{response.Message}
{string.Join(Environment.NewLine, generateResponse.Codes)}
Copied to clipboard
""";
await clipboardProvider.SetTextAsync(string.Join(", ", generateResponse.Codes)).ConfigureAwait(false);
infoBarService.Success(message, 0);
await taskContext.SwitchToMainThreadAsync();
RedeemCodeGenerateOption = new();
}
}
}

internal sealed class ExtractOptions
{
public bool IsOversea { get; set; }
Expand All @@ -461,4 +523,23 @@ internal sealed class DesignationOptions

public int Days { get; set; }
}

internal sealed class RedeemCodeGenerateOptions : ObservableObject
{
public int Count { get; set; }

public bool IsTimeLimited { get; set => SetProperty(ref field, value); }

public bool IsTimesLimited { get; set => SetProperty(ref field, value); }

public RedeemCodeTargetServiceType ServiceType { get; set; }

public int Value { get; set; }

public string Description { get; set; } = default!;

public int ExpireHours { get; set; }

public int Times { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ internal interface IHomaEndpoints :
IHomaPassportEndpoints,
IHomaSpiralAbyssEndpoints,
IHomaRoleCombatEndpoints,
IHomaDistributionEndpoints
IHomaDistributionEndpoints,
IHomaRedeemCodeEndpoints
{
public string HomaWebsite(string path)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.

namespace Snap.Hutao.Web.Endpoint.Hutao;

internal interface IHomaRedeemCodeEndpoints : IHomaRootAccess
{
public string RedeemCodeUse()
{
return $"{Root}/Redeem/Use";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@ public string CdnDesignation(string userName, int days)
{
return $"{Root}/Service/Distribution/Designation?userName={userName}&days={days}";
}

public string RedeemCodeGenerate()
{
return $"{Root}/Service/Redeem/Generate";
}
}
Loading

0 comments on commit 25907d3

Please sign in to comment.