Adding dialog for checking new number

This commit is contained in:
Selim Mustafaev 2024-05-05 21:42:38 +03:00
parent e5afc6dbdc
commit b2f5aee4e7
13 changed files with 220 additions and 33 deletions

View File

@ -25,6 +25,7 @@ public partial class App : Application
services.AddTransient<HistoryViewModel>(); services.AddTransient<HistoryViewModel>();
services.AddTransient<AuthWindowViewModel>(); services.AddTransient<AuthWindowViewModel>();
services.AddTransient<MainWindowViewModel>(); services.AddTransient<MainWindowViewModel>();
services.AddTransient<CheckNumberViewModel>();
// Windows // Windows
services.AddWindowFactory<AuthWindow>(); services.AddWindowFactory<AuthWindow>();

21
AutoCat/Utils/Alerts.cs Normal file
View File

@ -0,0 +1,21 @@
using System;
using MsBox.Avalonia;
using MsBox.Avalonia.Dto;
using MsBox.Avalonia.Enums;
namespace AutoCat.Utils;
public class Alerts
{
public static async void ShowError(Exception error)
{
var msgBox = MessageBoxManager.GetMessageBoxStandard(new MessageBoxStandardParams
{
ButtonDefinitions = ButtonEnum.Ok,
ContentTitle = "Error",
ContentMessage = error.Message
});
await msgBox.ShowAsync();
}
}

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Reactive; using System.Reactive;
using System.Threading.Tasks; using System.Threading.Tasks;
using AutoCat.Utils;
using AutoCatCore.Services.Api; using AutoCatCore.Services.Api;
using AutoCatCore.Services.Storage; using AutoCatCore.Services.Storage;
using ReactiveUI; using ReactiveUI;
@ -65,7 +66,7 @@ public class AuthWindowViewModel: ViewModelBase
(login, password) => login.Length > 3 && password.Length > 3); (login, password) => login.Length > 3 && password.Length > 3);
LoginCommand = ReactiveCommand.CreateFromTask(Login, loginEnabled); LoginCommand = ReactiveCommand.CreateFromTask(Login, loginEnabled);
LoginCommand.ThrownExceptions.Subscribe(ShowError); LoginCommand.ThrownExceptions.Subscribe(Alerts.ShowError);
} }
private async Task Login() private async Task Login()
@ -74,16 +75,4 @@ public class AuthWindowViewModel: ViewModelBase
await _storageService.SetUser(user); await _storageService.SetUser(user);
ReplaceWithMainWindowEvent?.Invoke(this, EventArgs.Empty); ReplaceWithMainWindowEvent?.Invoke(this, EventArgs.Empty);
} }
private async void ShowError(Exception error)
{
var msgBox = MessageBoxManager.GetMessageBoxStandard(new MessageBoxStandardParams
{
ButtonDefinitions = ButtonEnum.Ok,
ContentTitle = "Error",
ContentMessage = error.Message
});
await msgBox.ShowAsync();
}
} }

View File

@ -0,0 +1,65 @@
using System;
using System.Reactive;
using System.Reactive.Linq;
using System.Threading.Tasks;
using AutoCat.Utils;
using AutoCatCore.Model;
using AutoCatCore.Services.Api;
using DynamicData.Binding;
using ReactiveUI;
namespace AutoCat.ViewModels;
public class CheckNumberViewModel : ViewModelBase
{
#region Fields
private string _plateNumber = "";
#endregion
#region Dependencies
private readonly IApiService _apiService;
#endregion
#region Commands
public ReactiveCommand<string, Unit> CheckCommand { get; }
#endregion
#region Properties
public string PlateNumber
{
get => _plateNumber;
set => this.RaiseAndSetIfChanged(ref _plateNumber, value);
}
public Vehicle? Vehicle { get; set; }
#endregion
#region Events
public event EventHandler? AutoCloseEvent;
#endregion
public CheckNumberViewModel(IApiService apiService)
{
_apiService = apiService;
var checkEnabled = this.WhenAnyValue(vm => vm.PlateNumber, n => n.Length >= 8);
CheckCommand = ReactiveCommand.CreateFromTask<string>(Check, checkEnabled);
CheckCommand.ThrownExceptions.Subscribe(Alerts.ShowError);
}
private async Task Check(string number)
{
Vehicle = await _apiService.CheckNumber(number);
AutoCloseEvent?.Invoke(this, EventArgs.Empty);
}
}

View File

@ -1,4 +1,5 @@
using System; using System;
using AutoCatCore.Model;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Data; using Avalonia.Data;

View File

@ -0,0 +1,38 @@
<UserControl xmlns="https://github.com/avaloniaui"
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:utils="using:AutoCat.Utils"
xmlns:vm="using:AutoCat.ViewModels"
xmlns:ext="using:AutoCat.Extensions"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="AutoCat.Windows.CheckNumberDialog"
x:DataType="vm:CheckNumberViewModel"
x:CompileBindings="true"
DataContext="{utils:ViewModelProvider vm:CheckNumberViewModel}">
<StackPanel Orientation="Vertical"
HorizontalAlignment="Stretch"
Spacing="32"
Margin="0 16">
<Grid ColumnDefinitions="* 16 Auto" HorizontalAlignment="Stretch">
<TextBox Grid.Column="0"
Name="PlateNumberBox"
Watermark="Plate Number"
Text="{Binding PlateNumber}"
IsEnabled="{ReflectionBinding !CheckCommand.IsExecuting^}"/>
<Button Grid.Column="2"
Content="Check"
Command="{Binding CheckCommand}"
CommandParameter="{Binding #PlateNumberBox.Text}"
IsEnabled="{ReflectionBinding !CheckCommand.IsExecuting^}"/>
</Grid>
<ProgressBar IsIndeterminate="True"
IsVisible="{ReflectionBinding CheckCommand.IsExecuting^}"/>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,15 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Markup.Xaml;
using FluentAvalonia.UI.Controls;
namespace AutoCat.Windows;
public partial class CheckNumberDialog : UserControl
{
public CheckNumberDialog()
{
InitializeComponent();
}
}

View File

@ -27,7 +27,9 @@
IsPaneOpen="false" IsPaneOpen="false"
OpenPaneLength="180"> OpenPaneLength="180">
<ui:NavigationView.MenuItems> <ui:NavigationView.MenuItems>
<ui:NavigationViewItem Content="History" Tag="HistoryPage" IconSource="Clock"/> <ui:NavigationViewItem Content="New number" Tag="Check" IconSource="Add" SelectsOnInvoked="False"/>
<ui:NavigationViewItem Content="History" Tag="History" IconSource="Clock"/>
<ui:NavigationViewItem Content="Search" Tag="Search" IconSource="Find"/>
</ui:NavigationView.MenuItems> </ui:NavigationView.MenuItems>
</ui:NavigationView> </ui:NavigationView>
</Grid> </Grid>

View File

@ -1,6 +1,8 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using AutoCat.Pages; using AutoCat.Pages;
using AutoCat.ViewModels;
using Avalonia.Controls; using Avalonia.Controls;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
@ -16,7 +18,18 @@ public partial class MainWindow : Window
InitializeComponent(); InitializeComponent();
NavView.SelectionChanged += NavSelectionChanged; NavView.SelectionChanged += NavSelectionChanged;
NavView.SelectedItem = NavView.MenuItems.First(); NavView.ItemInvoked += NavViewOnItemInvoked;
NavView.SelectedItem = NavView.MenuItems.First(x => (x as NavigationViewItem)?.Tag?.ToString() == "History");
}
private void NavViewOnItemInvoked(object? sender, NavigationViewItemInvokedEventArgs e)
{
switch (e.InvokedItemContainer.Tag)
{
case "Check":
ShowCheckNumberDialog();
break;
}
} }
private void NavSelectionChanged(object? sender, NavigationViewSelectionChangedEventArgs args) private void NavSelectionChanged(object? sender, NavigationViewSelectionChangedEventArgs args)
@ -25,9 +38,41 @@ public partial class MainWindow : Window
{ {
NavView.Content = _settingsPage; NavView.Content = _settingsPage;
} }
else else if (args.SelectedItem is NavigationViewItem item)
{ {
switch (item.Tag)
{
case "History":
break;
case "Search":
NavView.Content = _historyPage; NavView.Content = _historyPage;
break;
} }
} }
}
private async void ShowCheckNumberDialog()
{
var dialog = new ContentDialog()
{
Title = "Check new number",
CloseButtonText = "Cancel"
};
var dialogContent = new CheckNumberDialog();
dialog.Content = dialogContent;
var dialogTask = dialog.ShowAsync();
if (dialogContent.DataContext is CheckNumberViewModel vm)
{
vm.AutoCloseEvent += (sender, args) =>
{
dialog.Hide();
Console.WriteLine($"Checked number: {vm.Vehicle?.Number}");
};
}
await dialogTask;
}
} }

View File

@ -2,7 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace AutoCat.Views; namespace AutoCatCore.Model;
//[CreateFromString(MethodName = "AutoCat.Controls.PlateNumber.ConvertFromString")] //[CreateFromString(MethodName = "AutoCat.Controls.PlateNumber.ConvertFromString")]
public class PlateNumber public class PlateNumber
@ -37,9 +37,4 @@ public class PlateNumber
{ {
return _numberEnglish[6..]; return _numberEnglish[6..];
} }
public static PlateNumber ConvertFromString(string number)
{
return new PlateNumber(number);
}
} }

View File

@ -3,14 +3,21 @@ using System.Text.Json.Serialization;
namespace AutoCatCore.Model namespace AutoCatCore.Model
{ {
public class User public class User(string email, string token)
{ {
[Key] [Key]
public string Email { get; set; } [MaxLength(50)]
public string? Token { get; set; } public string Email { get; set; } = email;
[MaxLength(300)]
public string? Token { get; set; } = token;
[JsonIgnore] [JsonIgnore]
[MaxLength(300)]
public string? FirebaseIdToken { get; set; } public string? FirebaseIdToken { get; set; }
[JsonIgnore] [JsonIgnore]
[MaxLength(300)]
public string? FirebaseRefreshToken { get; set; } public string? FirebaseRefreshToken { get; set; }
} }
} }

View File

@ -1,3 +1,4 @@
using System.Net.Http.Json;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using AutoCat.Model.Requests; using AutoCat.Model.Requests;
@ -14,13 +15,15 @@ public class ApiService : IApiService
public ApiService(IStorageService storageService) public ApiService(IStorageService storageService)
{ {
_httpClient = new HttpClient(); _httpClient = new HttpClient();
_httpClient.BaseAddress = new Uri("https://vps.aliencat.pro:8443"); _httpClient.BaseAddress = new Uri("http://127.0.0.1:3000");
SetAccessToken(storageService.AuthToken); SetAccessToken(storageService.AuthToken);
} }
private static T GetDataOrThrow<T>(string response) private static async Task<T> GetDataOrThrow<T>(HttpResponseMessage response)
{ {
var resp = JsonSerializer.Deserialize<Response<T>>(response, new JsonSerializerOptions { string responseStr = await response.Content.ReadAsStringAsync();
var resp = JsonSerializer.Deserialize<Response<T>>(responseStr, new JsonSerializerOptions {
PropertyNameCaseInsensitive = true PropertyNameCaseInsensitive = true
}); });
@ -50,8 +53,7 @@ public class ApiService : IApiService
}); });
var content = new StringContent(json, Encoding.UTF8, "application/json"); var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync("user/login", content); var response = await _httpClient.PostAsync("user/login", content);
var respStr = await response.Content.ReadAsStringAsync(); var result = await GetDataOrThrow<User>(response);
var result = GetDataOrThrow<User>(respStr);
SetAccessToken(result.Token); SetAccessToken(result.Token);
return result; return result;
} }
@ -59,7 +61,12 @@ public class ApiService : IApiService
public async Task<PagedResponse<Vehicle>> GetVehicles() public async Task<PagedResponse<Vehicle>> GetVehicles()
{ {
var response = await _httpClient.GetAsync("vehicles"); var response = await _httpClient.GetAsync("vehicles");
var respStr = await response.Content.ReadAsStringAsync(); return await GetDataOrThrow<PagedResponse<Vehicle>>(response);
return GetDataOrThrow<PagedResponse<Vehicle>>(respStr); }
public async Task<Vehicle> CheckNumber(string number)
{
var response = await _httpClient.PostAsJsonAsync("vehicles/check", new { number });
return await GetDataOrThrow<Vehicle>(response);
} }
} }

View File

@ -7,4 +7,5 @@ public interface IApiService
{ {
Task<User> Login(string email, string password); Task<User> Login(string email, string password);
Task<PagedResponse<Vehicle>> GetVehicles(); Task<PagedResponse<Vehicle>> GetVehicles();
Task<Vehicle> CheckNumber(string number);
} }