Initial commit
This commit is contained in:
commit
e86b971d62
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
/packages/
|
||||||
|
riderModule.iml
|
||||||
|
/_ReSharper.Caches/
|
||||||
|
.idea/
|
||||||
22
AutoCat.sln
Normal file
22
AutoCat.sln
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoCat", "AutoCat\AutoCat.csproj", "{9FB32BFB-805B-49F2-B5A2-E1F5A0C06A62}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoCatCore", "AutoCatCore\AutoCatCore.csproj", "{39A58D42-E1FA-4442-A7E3-7616D35AC770}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{9FB32BFB-805B-49F2-B5A2-E1F5A0C06A62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{9FB32BFB-805B-49F2-B5A2-E1F5A0C06A62}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{9FB32BFB-805B-49F2-B5A2-E1F5A0C06A62}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{9FB32BFB-805B-49F2-B5A2-E1F5A0C06A62}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{39A58D42-E1FA-4442-A7E3-7616D35AC770}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{39A58D42-E1FA-4442-A7E3-7616D35AC770}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{39A58D42-E1FA-4442-A7E3-7616D35AC770}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{39A58D42-E1FA-4442-A7E3-7616D35AC770}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
6
AutoCat.sln.DotSettings.user
Normal file
6
AutoCat.sln.DotSettings.user
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/SweaWarningsMode/@EntryValue">ShowAndRun</s:String>
|
||||||
|
<s:String x:Key="/Default/Environment/AssemblyExplorer/XmlDocument/@EntryValue"><AssemblyExplorer>
|
||||||
|
<Assembly Path="/Users/selim/.nuget/packages/avalonia/11.0.0/ref/net6.0/Avalonia.Markup.dll" />
|
||||||
|
<Assembly Path="/Users/selim/Documents/dev/AutoCatAvalonia/AutoCat/bin/Debug/net7.0/Avalonia.Base.dll" />
|
||||||
|
</AssemblyExplorer></s:String></wpf:ResourceDictionary>
|
||||||
BIN
AutoCat/.DS_Store
vendored
Normal file
BIN
AutoCat/.DS_Store
vendored
Normal file
Binary file not shown.
14
AutoCat/App.axaml
Normal file
14
AutoCat/App.axaml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<Application xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="using:AutoCat"
|
||||||
|
x:Class="AutoCat.App"
|
||||||
|
RequestedThemeVariant="Default">
|
||||||
|
|
||||||
|
<Application.DataTemplates>
|
||||||
|
<local:ViewLocator/>
|
||||||
|
</Application.DataTemplates>
|
||||||
|
|
||||||
|
<Application.Styles>
|
||||||
|
<FluentTheme/>
|
||||||
|
</Application.Styles>
|
||||||
|
</Application>
|
||||||
58
AutoCat/App.axaml.cs
Normal file
58
AutoCat/App.axaml.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
using AutoCat.Utils;
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using AutoCat.ViewModels;
|
||||||
|
using AutoCat.Views;
|
||||||
|
using AutoCatCore.Services.Api;
|
||||||
|
using AutoCatCore.Services.Storage;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
|
||||||
|
namespace AutoCat;
|
||||||
|
|
||||||
|
public partial class App : Application
|
||||||
|
{
|
||||||
|
public IHost AppHost { get; private set; }
|
||||||
|
|
||||||
|
private static void RegisterDependencies(HostBuilderContext context, IServiceCollection services)
|
||||||
|
{
|
||||||
|
// Services
|
||||||
|
services.AddSingleton<IApiService, ApiService>();
|
||||||
|
services.AddSingleton<IStorageService, StorageService>();
|
||||||
|
|
||||||
|
// ViewModels
|
||||||
|
services.AddTransient<AuthWindowViewModel>();
|
||||||
|
services.AddTransient<MainWindowViewModel>();
|
||||||
|
|
||||||
|
// Windows
|
||||||
|
services.AddWindowFactory<AuthWindow>();
|
||||||
|
services.AddWindowFactory<MainWindow>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public App()
|
||||||
|
{
|
||||||
|
AppHost = Host.CreateDefaultBuilder()
|
||||||
|
.ConfigureServices(RegisterDependencies)
|
||||||
|
.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnFrameworkInitializationCompleted()
|
||||||
|
{
|
||||||
|
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
|
{
|
||||||
|
var storageService = AppHost.Services.GetRequiredService<IStorageService>();
|
||||||
|
|
||||||
|
desktop.MainWindow = storageService.IsLoggedIn
|
||||||
|
? AppHost.Services.GetRequiredService<MainWindow>()
|
||||||
|
: AppHost.Services.GetRequiredService<AuthWindow>();
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnFrameworkInitializationCompleted();
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
AutoCat/Assets/avalonia-logo.ico
Normal file
BIN
AutoCat/Assets/avalonia-logo.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 172 KiB |
34
AutoCat/AutoCat.csproj
Normal file
34
AutoCat/AutoCat.csproj
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
||||||
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
|
<AvaloniaUseCompiledBindingsByDefault>false</AvaloniaUseCompiledBindingsByDefault>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<AvaloniaResource Include="Assets\**" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<TrimmerRootAssembly Include="Avalonia.Themes.Fluent" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Avalonia" Version="11.0.0" />
|
||||||
|
<PackageReference Include="Avalonia.Desktop" Version="11.0.0" />
|
||||||
|
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||||
|
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.0" />
|
||||||
|
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.0" />
|
||||||
|
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0" />
|
||||||
|
<PackageReference Include="MessageBox.Avalonia" Version="3.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\AutoCatCore\AutoCatCore.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
31
AutoCat/Extensions/TernaryExtension.cs
Normal file
31
AutoCat/Extensions/TernaryExtension.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using System;
|
||||||
|
using Avalonia.Data;
|
||||||
|
using Avalonia.Data.Converters;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Avalonia.Markup.Xaml.MarkupExtensions;
|
||||||
|
|
||||||
|
namespace AutoCat.Extensions;
|
||||||
|
|
||||||
|
public class TernaryExtension : MarkupExtension
|
||||||
|
{
|
||||||
|
public TernaryExtension()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Path { get; set; }
|
||||||
|
|
||||||
|
public object True { get; set; }
|
||||||
|
|
||||||
|
public object False { get; set; }
|
||||||
|
|
||||||
|
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
var binding = new ReflectionBindingExtension(Path)
|
||||||
|
{
|
||||||
|
Mode = BindingMode.OneWay,
|
||||||
|
Converter = new FuncValueConverter<bool, object>(e => e ? True : False)
|
||||||
|
};
|
||||||
|
|
||||||
|
return binding.ProvideValue(serviceProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
12
AutoCat/Mocks/AuthWindowViewModelMock.cs
Normal file
12
AutoCat/Mocks/AuthWindowViewModelMock.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System.Reactive;
|
||||||
|
using AutoCat.ViewModels;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace AutoCat.Mocks;
|
||||||
|
|
||||||
|
public class AuthWindowViewModelMock: ViewModelBase
|
||||||
|
{
|
||||||
|
public string Email { get; set; } = "";
|
||||||
|
public string Password { get; set; } = "";
|
||||||
|
public ReactiveCommand<Unit, Unit> LoginCommand { get; } = ReactiveCommand.Create(() => { });
|
||||||
|
}
|
||||||
22
AutoCat/Program.cs
Normal file
22
AutoCat/Program.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AutoCat;
|
||||||
|
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
||||||
|
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
||||||
|
// yet and stuff might break.
|
||||||
|
[STAThread]
|
||||||
|
public static void Main(string[] args) => BuildAvaloniaApp()
|
||||||
|
.StartWithClassicDesktopLifetime(args);
|
||||||
|
|
||||||
|
// Avalonia configuration, don't remove; also used by visual designer.
|
||||||
|
public static AppBuilder BuildAvaloniaApp()
|
||||||
|
=> AppBuilder.Configure<App>()
|
||||||
|
.UsePlatformDetect()
|
||||||
|
.LogToTrace()
|
||||||
|
.UseReactiveUI();
|
||||||
|
}
|
||||||
23
AutoCat/Utils/AbstractFactory.cs
Normal file
23
AutoCat/Utils/AbstractFactory.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AutoCat.Utils;
|
||||||
|
|
||||||
|
public interface IAbstractFactory<out T>
|
||||||
|
{
|
||||||
|
T Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AbstractFactory<T> : IAbstractFactory<T>
|
||||||
|
{
|
||||||
|
private readonly Func<T> _factory;
|
||||||
|
|
||||||
|
public AbstractFactory(Func<T> factory)
|
||||||
|
{
|
||||||
|
_factory = factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Create()
|
||||||
|
{
|
||||||
|
return _factory();
|
||||||
|
}
|
||||||
|
}
|
||||||
15
AutoCat/Utils/DIExtentions.cs
Normal file
15
AutoCat/Utils/DIExtentions.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace AutoCat.Utils;
|
||||||
|
|
||||||
|
public static class DependencyInjectionExtensions
|
||||||
|
{
|
||||||
|
public static void AddWindowFactory<TWindow>(this IServiceCollection services) where TWindow: Window
|
||||||
|
{
|
||||||
|
services.AddTransient<TWindow>();
|
||||||
|
services.AddSingleton<Func<TWindow>>(x => () => x.GetService<TWindow>()!);
|
||||||
|
services.AddSingleton<IAbstractFactory<TWindow>, AbstractFactory<TWindow>>();
|
||||||
|
}
|
||||||
|
}
|
||||||
24
AutoCat/Utils/ViewModelProvider.cs
Normal file
24
AutoCat/Utils/ViewModelProvider.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
|
namespace AutoCat.Utils;
|
||||||
|
|
||||||
|
public class ViewModelProvider: MarkupExtension
|
||||||
|
{
|
||||||
|
private readonly Type _viewModelType;
|
||||||
|
|
||||||
|
public ViewModelProvider(Type viewModelType)
|
||||||
|
{
|
||||||
|
_viewModelType = viewModelType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
if (Application.Current is App app)
|
||||||
|
return app.AppHost.Services.GetService(_viewModelType)
|
||||||
|
?? throw new Exception("Error finding ViewModel");
|
||||||
|
else
|
||||||
|
throw new Exception("Error getting App instance");
|
||||||
|
}
|
||||||
|
}
|
||||||
27
AutoCat/ViewLocator.cs
Normal file
27
AutoCat/ViewLocator.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.Templates;
|
||||||
|
using AutoCat.ViewModels;
|
||||||
|
|
||||||
|
namespace AutoCat;
|
||||||
|
|
||||||
|
public class ViewLocator : IDataTemplate
|
||||||
|
{
|
||||||
|
public Control Build(object data)
|
||||||
|
{
|
||||||
|
var name = data.GetType().FullName!.Replace("ViewModel", "View");
|
||||||
|
var type = Type.GetType(name);
|
||||||
|
|
||||||
|
if (type != null)
|
||||||
|
{
|
||||||
|
return (Control)Activator.CreateInstance(type)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TextBlock { Text = "Not Found: " + name };
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Match(object data)
|
||||||
|
{
|
||||||
|
return data is ViewModelBase;
|
||||||
|
}
|
||||||
|
}
|
||||||
83
AutoCat/ViewModels/AuthWindowViewModel.cs
Normal file
83
AutoCat/ViewModels/AuthWindowViewModel.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reactive;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AutoCatCore.Services.Api;
|
||||||
|
using AutoCatCore.Services.Storage;
|
||||||
|
using ReactiveUI;
|
||||||
|
using MsBox.Avalonia;
|
||||||
|
using MsBox.Avalonia.Dto;
|
||||||
|
using MsBox.Avalonia.Enums;
|
||||||
|
|
||||||
|
namespace AutoCat.ViewModels;
|
||||||
|
|
||||||
|
public class AuthWindowViewModel: ViewModelBase
|
||||||
|
{
|
||||||
|
#region Dependencies
|
||||||
|
|
||||||
|
private readonly IApiService _apiService;
|
||||||
|
private readonly IStorageService _storageService;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private string _email = "";
|
||||||
|
private string _password = "";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public string Email
|
||||||
|
{
|
||||||
|
get => _email;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _email, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Password
|
||||||
|
{
|
||||||
|
get => _password;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _password, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Commands
|
||||||
|
|
||||||
|
public ReactiveCommand<Unit, Unit> LoginCommand { get; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public AuthWindowViewModel(IApiService apiService, IStorageService storageService)
|
||||||
|
{
|
||||||
|
_apiService = apiService;
|
||||||
|
_storageService = storageService;
|
||||||
|
|
||||||
|
var loginEnabled = this.WhenAnyValue(
|
||||||
|
vm => vm.Email,
|
||||||
|
vm => vm.Password,
|
||||||
|
(login, password) => login.Length > 3 && password.Length > 3);
|
||||||
|
|
||||||
|
LoginCommand = ReactiveCommand.CreateFromTask(Login, loginEnabled);
|
||||||
|
LoginCommand.ThrownExceptions.Subscribe(ShowError);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Login()
|
||||||
|
{
|
||||||
|
var user = await _apiService.Login(Email, Password);
|
||||||
|
//await _storageService.SetUser(user);
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void ShowError(Exception error)
|
||||||
|
{
|
||||||
|
var msgBox = MessageBoxManager.GetMessageBoxStandard(new MessageBoxStandardParams
|
||||||
|
{
|
||||||
|
ButtonDefinitions = ButtonEnum.Ok,
|
||||||
|
ContentTitle = "Error",
|
||||||
|
ContentMessage = error.Message
|
||||||
|
});
|
||||||
|
|
||||||
|
await msgBox.ShowAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
6
AutoCat/ViewModels/MainWindowViewModel.cs
Normal file
6
AutoCat/ViewModels/MainWindowViewModel.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace AutoCat.ViewModels;
|
||||||
|
|
||||||
|
public class MainWindowViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
public string Greeting => "Welcome to Avalonia!";
|
||||||
|
}
|
||||||
14
AutoCat/ViewModels/ViewModelBase.cs
Normal file
14
AutoCat/ViewModels/ViewModelBase.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace AutoCat.ViewModels;
|
||||||
|
|
||||||
|
public class ViewModelBase : ReactiveObject
|
||||||
|
{
|
||||||
|
public event EventHandler? ClosingRequest;
|
||||||
|
|
||||||
|
protected void Close()
|
||||||
|
{
|
||||||
|
ClosingRequest?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
37
AutoCat/Views/AuthWindow.axaml
Normal file
37
AutoCat/Views/AuthWindow.axaml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<Window 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:vm="using:AutoCat.ViewModels"
|
||||||
|
xmlns:utils="using:AutoCat.Utils"
|
||||||
|
xmlns:mocks="using:AutoCat.Mocks"
|
||||||
|
xmlns:ext="using:AutoCat.Extensions"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="AutoCat.Views.AuthWindow"
|
||||||
|
x:DataType="vm:AuthWindowViewModel"
|
||||||
|
Title="AuthWindow"
|
||||||
|
Width="800" Height="600"
|
||||||
|
DataContext="{utils:ViewModelProvider vm:AuthWindowViewModel}">
|
||||||
|
|
||||||
|
<Design.DataContext>
|
||||||
|
<mocks:AuthWindowViewModelMock/>
|
||||||
|
</Design.DataContext>
|
||||||
|
|
||||||
|
<StackPanel Orientation="Vertical"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Margin="100, 0"
|
||||||
|
Spacing="16">
|
||||||
|
<TextBox Watermark="Email"
|
||||||
|
Text="{Binding Email}"
|
||||||
|
IsEnabled="{Binding !LoginCommand.IsExecuting^}"/>
|
||||||
|
<TextBox Watermark="Password" PasswordChar="*"
|
||||||
|
Text="{Binding Password}"
|
||||||
|
IsEnabled="{Binding !LoginCommand.IsExecuting^}"/>
|
||||||
|
<Button Content="{ext:Ternary Path=LoginCommand.IsExecuting^, True=Logging In..., False=Log In}"
|
||||||
|
Command="{Binding LoginCommand}"
|
||||||
|
IsEnabled="{Binding !LoginCommand.IsExecuting^}"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Center"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Window>
|
||||||
20
AutoCat/Views/AuthWindow.axaml.cs
Normal file
20
AutoCat/Views/AuthWindow.axaml.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using AutoCat.ViewModels;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace AutoCat.Views;
|
||||||
|
|
||||||
|
public partial class AuthWindow : Window
|
||||||
|
{
|
||||||
|
public AuthWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
if (DataContext is ViewModelBase vm)
|
||||||
|
{
|
||||||
|
vm.ClosingRequest += (sender, args) =>
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
22
AutoCat/Views/MainWindow.axaml
Normal file
22
AutoCat/Views/MainWindow.axaml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<Window xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:vm="using:AutoCat.ViewModels"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
Width="800"
|
||||||
|
Height="600"
|
||||||
|
x:Class="AutoCat.Views.MainWindow"
|
||||||
|
x:DataType="vm:MainWindowViewModel"
|
||||||
|
Icon="/Assets/avalonia-logo.ico"
|
||||||
|
Title="AutoCat">
|
||||||
|
|
||||||
|
<Design.DataContext>
|
||||||
|
<!-- This only sets the DataContext for the previewer in an IDE,
|
||||||
|
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
|
||||||
|
<vm:MainWindowViewModel/>
|
||||||
|
</Design.DataContext>
|
||||||
|
|
||||||
|
<TextBlock Text="{Binding Greeting}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||||
|
|
||||||
|
</Window>
|
||||||
11
AutoCat/Views/MainWindow.axaml.cs
Normal file
11
AutoCat/Views/MainWindow.axaml.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace AutoCat.Views;
|
||||||
|
|
||||||
|
public partial class MainWindow : Window
|
||||||
|
{
|
||||||
|
public MainWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
18
AutoCat/app.manifest
Normal file
18
AutoCat/app.manifest
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<!-- This manifest is used on Windows only.
|
||||||
|
Don't remove it as it might cause problems with window transparency and embeded controls.
|
||||||
|
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
|
||||||
|
<assemblyIdentity version="1.0.0.0" name="AvaloniaTest.Desktop"/>
|
||||||
|
|
||||||
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
<application>
|
||||||
|
<!-- A list of the Windows versions that this application has been tested on
|
||||||
|
and is designed to work with. Uncomment the appropriate elements
|
||||||
|
and Windows will automatically select the most compatible environment. -->
|
||||||
|
|
||||||
|
<!-- Windows 10 -->
|
||||||
|
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||||
|
</application>
|
||||||
|
</compatibility>
|
||||||
|
</assembly>
|
||||||
BIN
AutoCatCore/.DS_Store
vendored
Normal file
BIN
AutoCatCore/.DS_Store
vendored
Normal file
Binary file not shown.
14
AutoCatCore/AutoCatCore.csproj
Normal file
14
AutoCatCore/AutoCatCore.csproj
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.4" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.4" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
19
AutoCatCore/Model/AutoCatDbContext.cs
Normal file
19
AutoCatCore/Model/AutoCatDbContext.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AutoCatCore.Model
|
||||||
|
{
|
||||||
|
class AutoCatDbContext: DbContext
|
||||||
|
{
|
||||||
|
public DbSet<User> Users { get; private set; }
|
||||||
|
|
||||||
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
|
{
|
||||||
|
optionsBuilder.UseSqlite("filename=autocat.db");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
AutoCatCore/Model/Osago.cs
Normal file
16
AutoCatCore/Model/Osago.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
namespace AutoCatCore.Model
|
||||||
|
{
|
||||||
|
public class Osago
|
||||||
|
{
|
||||||
|
public double Date { get; set; }
|
||||||
|
public string Number { get; set; }
|
||||||
|
public string Vin { get; set; }
|
||||||
|
public string PlateNumber { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Status { get; set; }
|
||||||
|
public string Restrictions { get; set; }
|
||||||
|
public string Insurant { get; set; }
|
||||||
|
public string Owner { get; set; }
|
||||||
|
public string UsageRegion { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
14
AutoCatCore/Model/Requests/Credentials.cs
Normal file
14
AutoCatCore/Model/Requests/Credentials.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AutoCat.Model.Requests
|
||||||
|
{
|
||||||
|
class Credentials
|
||||||
|
{
|
||||||
|
public string Email { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
13
AutoCatCore/Model/Requests/PagedResponse.cs
Normal file
13
AutoCatCore/Model/Requests/PagedResponse.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace AutoCatCore.Model.Requests
|
||||||
|
{
|
||||||
|
public class PagedResponse<T>
|
||||||
|
{
|
||||||
|
public int? Count { get; set; }
|
||||||
|
public string PageToken { get; set; }
|
||||||
|
public List<T> Items { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
8
AutoCatCore/Model/Requests/Response.cs
Normal file
8
AutoCatCore/Model/Requests/Response.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace AutoCatCore.Model.Requests;
|
||||||
|
|
||||||
|
internal class Response<T>
|
||||||
|
{
|
||||||
|
public bool Success { get; set; }
|
||||||
|
public T? Data { get; set; }
|
||||||
|
public string? Error { get; set; }
|
||||||
|
}
|
||||||
16
AutoCatCore/Model/User.cs
Normal file
16
AutoCatCore/Model/User.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace AutoCatCore.Model
|
||||||
|
{
|
||||||
|
public class User
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public string Email { get; set; }
|
||||||
|
public string? Token { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
|
public string? FirebaseIdToken { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
|
public string? FirebaseRefreshToken { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
31
AutoCatCore/Model/Vehicle.cs
Normal file
31
AutoCatCore/Model/Vehicle.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace AutoCatCore.Model
|
||||||
|
{
|
||||||
|
public class Vehicle
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public string Number { get; set; }
|
||||||
|
public string CurrentNumber { get; set; }
|
||||||
|
public string Vin1 { get; set; }
|
||||||
|
public string Vin2 { get; set; }
|
||||||
|
public string Sts { get; set; }
|
||||||
|
public string Pts { get; set; }
|
||||||
|
public VehicleBrand Brand { get; set; }
|
||||||
|
public VehicleModel Model { get; set; }
|
||||||
|
public string Color { get; set; }
|
||||||
|
public int Year { get; set; }
|
||||||
|
public string Category { get; set; }
|
||||||
|
public bool? IsRightWheel { get; set; }
|
||||||
|
public bool? IsJapanese { get; set; }
|
||||||
|
public double AddedDate { get; set; }
|
||||||
|
public double UpdatedDate { get; set; }
|
||||||
|
public string AddedBy { get; set; }
|
||||||
|
public VehicleEngine Engine { get; set; }
|
||||||
|
public List<VehiclePhoto> Photos { get; set; }
|
||||||
|
public List<VehicleEvent> Events { get; set; }
|
||||||
|
public List<Osago> OsagoContracts { get; set; } = new List<Osago>();
|
||||||
|
public List<VehicleOwnershipPeriod> OwnershipPeriods { get; set; } = new List<VehicleOwnershipPeriod>();
|
||||||
|
public List<VehicleAd> Ads { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
18
AutoCatCore/Model/VehicleAd.cs
Normal file
18
AutoCatCore/Model/VehicleAd.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace AutoCatCore.Model
|
||||||
|
{
|
||||||
|
public class VehicleAd
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Url { get; set; }
|
||||||
|
public string Price { get; set; }
|
||||||
|
public double Date { get; set; }
|
||||||
|
public string Mileage { get; set; }
|
||||||
|
public string Region { get; set; }
|
||||||
|
public string City { get; set; }
|
||||||
|
public string AdDescription { get; set; }
|
||||||
|
public List<string> Photos { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
8
AutoCatCore/Model/VehicleBrand.cs
Normal file
8
AutoCatCore/Model/VehicleBrand.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace AutoCatCore.Model
|
||||||
|
{
|
||||||
|
public class VehicleBrand
|
||||||
|
{
|
||||||
|
public VehicleName Name { get; set; }
|
||||||
|
public string Logo { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
11
AutoCatCore/Model/VehicleEngine.cs
Normal file
11
AutoCatCore/Model/VehicleEngine.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace AutoCatCore.Model
|
||||||
|
{
|
||||||
|
public class VehicleEngine
|
||||||
|
{
|
||||||
|
public string Number { get; set; }
|
||||||
|
public int? Volume { get; set; }
|
||||||
|
public double? PowerKw { get; set; }
|
||||||
|
public double? PowerHp { get; set; }
|
||||||
|
public string FuelType { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
14
AutoCatCore/Model/VehicleEvent.cs
Normal file
14
AutoCatCore/Model/VehicleEvent.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace AutoCatCore.Model
|
||||||
|
{
|
||||||
|
public class VehicleEvent
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public string Id { get; set; }
|
||||||
|
public double Date { get; set; }
|
||||||
|
public double Latitude { get; set; }
|
||||||
|
public double Longitude { get; set; }
|
||||||
|
public string Address { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
7
AutoCatCore/Model/VehicleModel.cs
Normal file
7
AutoCatCore/Model/VehicleModel.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace AutoCatCore.Model
|
||||||
|
{
|
||||||
|
public class VehicleModel
|
||||||
|
{
|
||||||
|
public VehicleName Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
8
AutoCatCore/Model/VehicleName.cs
Normal file
8
AutoCatCore/Model/VehicleName.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace AutoCatCore.Model
|
||||||
|
{
|
||||||
|
public class VehicleName
|
||||||
|
{
|
||||||
|
public string Original { get; set; }
|
||||||
|
public string Normalized { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
17
AutoCatCore/Model/VehicleOwnershipPeriod.cs
Normal file
17
AutoCatCore/Model/VehicleOwnershipPeriod.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace AutoCatCore.Model
|
||||||
|
{
|
||||||
|
public class VehicleOwnershipPeriod
|
||||||
|
{
|
||||||
|
public string LastOperation { get; set; }
|
||||||
|
public string OwnerType { get; set; }
|
||||||
|
public Int64 From { get; set; }
|
||||||
|
public Int64 To { get; set; }
|
||||||
|
public string Region { get; set; }
|
||||||
|
public string RegistrationRegion { get; set; }
|
||||||
|
public string Locality { get; set; }
|
||||||
|
public string Code { get; set; }
|
||||||
|
public string Street { get; set; }
|
||||||
|
public string Building { get; set; }
|
||||||
|
public string Inn { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
10
AutoCatCore/Model/VehiclePhoto.cs
Normal file
10
AutoCatCore/Model/VehiclePhoto.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace AutoCatCore.Model
|
||||||
|
{
|
||||||
|
public class VehiclePhoto
|
||||||
|
{
|
||||||
|
public string Brand { get; set; }
|
||||||
|
public string Model { get; set; }
|
||||||
|
public double Date { get; set; }
|
||||||
|
public string Url { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
63
AutoCatCore/Services/Api/ApiService.cs
Normal file
63
AutoCatCore/Services/Api/ApiService.cs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using AutoCat.Model.Requests;
|
||||||
|
using AutoCatCore.Model;
|
||||||
|
using AutoCatCore.Model.Requests;
|
||||||
|
|
||||||
|
namespace AutoCatCore.Services.Api;
|
||||||
|
|
||||||
|
public class ApiService : IApiService
|
||||||
|
{
|
||||||
|
private readonly HttpClient _httpClient;
|
||||||
|
|
||||||
|
public ApiService()
|
||||||
|
{
|
||||||
|
_httpClient = new HttpClient();
|
||||||
|
_httpClient.BaseAddress = new Uri("https://vps.aliencat.pro:8443");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static T GetDataOrThrow<T>(string response)
|
||||||
|
{
|
||||||
|
var resp = JsonSerializer.Deserialize<Response<T>>(response, new JsonSerializerOptions {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
});
|
||||||
|
|
||||||
|
if (resp is null)
|
||||||
|
throw new Exception("Error deserializing response");
|
||||||
|
|
||||||
|
if (resp.Success)
|
||||||
|
return resp.Data ?? throw new Exception("Empty response");
|
||||||
|
|
||||||
|
throw new Exception(resp.Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetAccessToken(string? token)
|
||||||
|
{
|
||||||
|
if (token is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_httpClient.DefaultRequestHeaders.Remove("Authorization");
|
||||||
|
_httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<User> Login(string email, string password)
|
||||||
|
{
|
||||||
|
var credentials = new Credentials { Email = email, Password = password };
|
||||||
|
var json = JsonSerializer.Serialize(credentials, new JsonSerializerOptions {
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||||
|
});
|
||||||
|
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
||||||
|
var response = await _httpClient.PostAsync("user/login", content);
|
||||||
|
var respStr = await response.Content.ReadAsStringAsync();
|
||||||
|
var result = GetDataOrThrow<User>(respStr);
|
||||||
|
SetAccessToken(result.Token);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PagedResponse<Vehicle>> GetVehicles()
|
||||||
|
{
|
||||||
|
var response = await _httpClient.GetAsync("vehicles");
|
||||||
|
var respStr = await response.Content.ReadAsStringAsync();
|
||||||
|
return GetDataOrThrow<PagedResponse<Vehicle>>(respStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
10
AutoCatCore/Services/Api/IApiService.cs
Normal file
10
AutoCatCore/Services/Api/IApiService.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using AutoCatCore.Model;
|
||||||
|
using AutoCatCore.Model.Requests;
|
||||||
|
|
||||||
|
namespace AutoCatCore.Services.Api;
|
||||||
|
|
||||||
|
public interface IApiService
|
||||||
|
{
|
||||||
|
Task<User> Login(string email, string password);
|
||||||
|
Task<PagedResponse<Vehicle>> GetVehicles();
|
||||||
|
}
|
||||||
10
AutoCatCore/Services/Storage/IStorageService.cs
Normal file
10
AutoCatCore/Services/Storage/IStorageService.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using AutoCatCore.Model;
|
||||||
|
|
||||||
|
namespace AutoCatCore.Services.Storage;
|
||||||
|
|
||||||
|
public interface IStorageService
|
||||||
|
{
|
||||||
|
public bool IsLoggedIn { get; }
|
||||||
|
|
||||||
|
public Task SetUser(User user);
|
||||||
|
}
|
||||||
33
AutoCatCore/Services/Storage/StorageService.cs
Normal file
33
AutoCatCore/Services/Storage/StorageService.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using AutoCatCore.Model;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace AutoCatCore.Services.Storage;
|
||||||
|
|
||||||
|
public class StorageService: IStorageService
|
||||||
|
{
|
||||||
|
private readonly AutoCatDbContext _dbContext;
|
||||||
|
|
||||||
|
public bool IsLoggedIn
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_dbContext.Users.Any())
|
||||||
|
return _dbContext.Users.First().Token != null;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SetUser(User user)
|
||||||
|
{
|
||||||
|
await _dbContext.Users.ExecuteDeleteAsync();
|
||||||
|
await _dbContext.Users.AddAsync(user);
|
||||||
|
await _dbContext.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StorageService()
|
||||||
|
{
|
||||||
|
_dbContext = new AutoCatDbContext();
|
||||||
|
_dbContext.Database.EnsureCreated();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user