104 lines
2.6 KiB
C#
104 lines
2.6 KiB
C#
using Avalonia.Markup.Xaml;
|
|
using Avalonia.Media.Imaging;
|
|
using LibationAvalonia.ViewModels;
|
|
using ReactiveUI;
|
|
using System.IO;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace LibationAvalonia.Dialogs.Login
|
|
{
|
|
public partial class CaptchaDialog : DialogWindow
|
|
{
|
|
public string Password => _viewModel.Password;
|
|
public string Answer => _viewModel.Answer;
|
|
|
|
private CaptchaDialogViewModel _viewModel;
|
|
public CaptchaDialog()
|
|
{
|
|
InitializeComponent();
|
|
}
|
|
|
|
public CaptchaDialog(string password, byte[] captchaImage) :this()
|
|
{
|
|
//Avalonia doesn't support animated gifs.
|
|
//Deconstruct gifs into frames and manually switch them.
|
|
using var gif = SixLabors.ImageSharp.Image.Load(captchaImage);
|
|
var gifEncoder = new SixLabors.ImageSharp.Formats.Gif.GifEncoder();
|
|
var gifFrames = new Bitmap[gif.Frames.Count];
|
|
|
|
for (int i = 0; i < gif.Frames.Count; i++)
|
|
{
|
|
using var framems = new MemoryStream();
|
|
|
|
using var clonedFrame = gif.Frames.CloneFrame(i);
|
|
|
|
clonedFrame.Save(framems, gifEncoder);
|
|
framems.Position = 0;
|
|
gifFrames[i] = new Bitmap(framems);
|
|
}
|
|
|
|
DataContext = _viewModel = new(password, gifFrames);
|
|
}
|
|
|
|
private void InitializeComponent()
|
|
{
|
|
AvaloniaXamlLoader.Load(this);
|
|
}
|
|
|
|
protected override async Task SaveAndCloseAsync()
|
|
{
|
|
if (string.IsNullOrWhiteSpace(_viewModel.Password))
|
|
{
|
|
await MessageBox.Show(this, "Please re-enter your password");
|
|
return;
|
|
}
|
|
|
|
Serilog.Log.Logger.Information("Submit button clicked: {@DebugInfo}", new { _viewModel.Answer });
|
|
|
|
await _viewModel.StopAsync();
|
|
await base.SaveAndCloseAsync();
|
|
}
|
|
|
|
public async void Submit_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
|
|
=> await SaveAndCloseAsync();
|
|
}
|
|
|
|
public class CaptchaDialogViewModel : ViewModelBase
|
|
{
|
|
public string Answer { get; set; }
|
|
public string Password { get; set; }
|
|
public Bitmap CaptchaImage { get => _captchaImage; private set => this.RaiseAndSetIfChanged(ref _captchaImage, value); }
|
|
|
|
private Bitmap _captchaImage;
|
|
private bool keepSwitching = true;
|
|
private readonly Task FrameSwitch;
|
|
private readonly Bitmap[] GifFrames;
|
|
private const int FRAME_INTERVAL_MS = 100;
|
|
|
|
public CaptchaDialogViewModel(string password, Bitmap[] gifFrames)
|
|
{
|
|
Password = password;
|
|
GifFrames = gifFrames;
|
|
FrameSwitch = SwitchFramesAsync();
|
|
}
|
|
|
|
public async Task StopAsync()
|
|
{
|
|
keepSwitching = false;
|
|
await FrameSwitch;
|
|
}
|
|
|
|
private async Task SwitchFramesAsync()
|
|
{
|
|
int index = 0;
|
|
while(keepSwitching)
|
|
{
|
|
CaptchaImage = GifFrames[index++];
|
|
|
|
index %= GifFrames.Length;
|
|
await Task.Delay(FRAME_INTERVAL_MS);
|
|
}
|
|
}
|
|
}
|
|
}
|