diff --git a/Unige.sln b/Unige.sln index 9de7b7e..35d8d71 100644 --- a/Unige.sln +++ b/Unige.sln @@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OgeSharp", "OgeSharp\OgeSha EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnigeWebUtility", "UnigeWebUtility\UnigeWebUtility.csproj", "{3568E75E-90CB-4A03-B2E3-D8F413ABF68E}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnigeSoftware", "UnigeSoftware\UnigeSoftware.csproj", "{991CA739-1B61-4D43-B7BF-88840944C08C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +23,10 @@ Global {3568E75E-90CB-4A03-B2E3-D8F413ABF68E}.Debug|Any CPU.Build.0 = Debug|Any CPU {3568E75E-90CB-4A03-B2E3-D8F413ABF68E}.Release|Any CPU.ActiveCfg = Release|Any CPU {3568E75E-90CB-4A03-B2E3-D8F413ABF68E}.Release|Any CPU.Build.0 = Release|Any CPU + {991CA739-1B61-4D43-B7BF-88840944C08C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {991CA739-1B61-4D43-B7BF-88840944C08C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {991CA739-1B61-4D43-B7BF-88840944C08C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {991CA739-1B61-4D43-B7BF-88840944C08C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/UnigeSoftware/App.axaml b/UnigeSoftware/App.axaml new file mode 100644 index 0000000..d94f412 --- /dev/null +++ b/UnigeSoftware/App.axaml @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/UnigeSoftware/App.axaml.cs b/UnigeSoftware/App.axaml.cs new file mode 100644 index 0000000..6dc1881 --- /dev/null +++ b/UnigeSoftware/App.axaml.cs @@ -0,0 +1,21 @@ +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Markup.Xaml; +using UnigeSoftware.ViewModels; +using UnigeSoftware.Views; + +namespace UnigeSoftware { + public class App : Application { + public override void Initialize() => AvaloniaXamlLoader.Load(this); + + public override void OnFrameworkInitializationCompleted() { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { + desktop.MainWindow = new MainWindow { + DataContext = new MainWindowViewModel(), + }; + } + + base.OnFrameworkInitializationCompleted(); + } + } +} diff --git a/UnigeSoftware/Assets/avalonia-logo.ico b/UnigeSoftware/Assets/avalonia-logo.ico new file mode 100644 index 0000000..da8d49f Binary files /dev/null and b/UnigeSoftware/Assets/avalonia-logo.ico differ diff --git a/UnigeSoftware/Assets/discord-mark-light.png b/UnigeSoftware/Assets/discord-mark-light.png new file mode 100644 index 0000000..25d8f2b Binary files /dev/null and b/UnigeSoftware/Assets/discord-mark-light.png differ diff --git a/UnigeSoftware/Assets/github-mark-light.png b/UnigeSoftware/Assets/github-mark-light.png new file mode 100644 index 0000000..ea6ff54 Binary files /dev/null and b/UnigeSoftware/Assets/github-mark-light.png differ diff --git a/UnigeSoftware/FodyWeavers.xml b/UnigeSoftware/FodyWeavers.xml new file mode 100644 index 0000000..63fc148 --- /dev/null +++ b/UnigeSoftware/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/UnigeSoftware/Program.cs b/UnigeSoftware/Program.cs new file mode 100644 index 0000000..871a896 --- /dev/null +++ b/UnigeSoftware/Program.cs @@ -0,0 +1,22 @@ +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.ReactiveUI; +using System; + +namespace UnigeSoftware { + 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() + .UsePlatformDetect() + .LogToTrace() + .UseReactiveUI(); + } +} diff --git a/UnigeSoftware/UnigeSoftware.csproj b/UnigeSoftware/UnigeSoftware.csproj new file mode 100644 index 0000000..39bf9e3 --- /dev/null +++ b/UnigeSoftware/UnigeSoftware.csproj @@ -0,0 +1,32 @@ + + + WinExe + net5.0 + enable + true + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UnigeSoftware/ViewLocator.cs b/UnigeSoftware/ViewLocator.cs new file mode 100644 index 0000000..2a6025c --- /dev/null +++ b/UnigeSoftware/ViewLocator.cs @@ -0,0 +1,22 @@ +using Avalonia.Controls; +using Avalonia.Controls.Templates; +using ReactiveUI; +using System; + +namespace UnigeSoftware { + public class ViewLocator : IDataTemplate { + public IControl Build(object data) { + var name = data.GetType().FullName!.Replace("ViewModel", "View"); + var type = Type.GetType(name); + + if (type != null) { + return (Control)Activator.CreateInstance(type)!; + } else { + return new TextBlock { Text = "Not Found: " + name }; + } + } + + public bool Match(object data) => data is ReactiveObject; + + } +} diff --git a/UnigeSoftware/ViewModels/ConnectViewModel.cs b/UnigeSoftware/ViewModels/ConnectViewModel.cs new file mode 100644 index 0000000..5ac784f --- /dev/null +++ b/UnigeSoftware/ViewModels/ConnectViewModel.cs @@ -0,0 +1,63 @@ +using ReactiveUI; +using ReactiveUI.Fody.Helpers; +using ReactiveUI.Validation.Abstractions; +using ReactiveUI.Validation.Contexts; +using ReactiveUI.Validation.Extensions; +using System; +using System.Diagnostics; +using System.Reactive; +using System.Reactive.Linq; + +namespace UnigeSoftware.ViewModels { + + public class ConnectViewModel : ReactiveObject, IValidatableViewModel { + + private readonly MainWindowViewModel MainWindow; + public ValidationContext ValidationContext { get; } = new ValidationContext(); + + [Reactive] public string Username { get; set; } + [Reactive] public string Password { get; set; } + + public ConnectViewModel(MainWindowViewModel mainWindow) { + + // Save the main window view model + MainWindow = mainWindow; + + // Create the commands + ConnectCommand = ReactiveCommand.CreateFromObservable(DoConnect); + OpenFromExplorerCommand = ReactiveCommand.Create(DoOpenWebpage); + + // Username and password cannot be empty + this.ValidationRule(viewModel => viewModel.Username, username => !string.IsNullOrEmpty(username), "Le nom d'utilisateur ne peut pas être vide"); + this.ValidationRule(viewModel => viewModel.Password, password => !string.IsNullOrEmpty(password), "Le mot de passe ne peut pas être vide"); + + } + + #region Commands + + public ReactiveCommand ConnectCommand { get; } + public ReactiveCommand OpenFromExplorerCommand { get; } + + // TODO: Maybe not working on other OS + private void DoOpenWebpage(string url) => Process.Start("explorer", url); + + private IObservable DoConnect() => Observable.Start(() => { + + // If the fields are not validated + if (!ValidationContext.GetIsValid()) return; + + // If the credentials are correct + if (MainWindow.Oge.Login(Username, Password)) { + + // Tell the main window that we are connected + MainWindow.OnConnected(); + + } + + }); + + #endregion + + } + +} diff --git a/UnigeSoftware/ViewModels/HomeViewModel.cs b/UnigeSoftware/ViewModels/HomeViewModel.cs new file mode 100644 index 0000000..27cbee0 --- /dev/null +++ b/UnigeSoftware/ViewModels/HomeViewModel.cs @@ -0,0 +1,16 @@ +using ReactiveUI; +using ReactiveUI.Fody.Helpers; + +namespace UnigeSoftware.ViewModels { + + public class HomeViewModel : ReactiveObject { + + [Reactive] public string Note { get; set; } + + public HomeViewModel(MainWindowViewModel mainWindow) { + + } + + } + +} diff --git a/UnigeSoftware/ViewModels/MainWindowViewModel.cs b/UnigeSoftware/ViewModels/MainWindowViewModel.cs new file mode 100644 index 0000000..edf91a1 --- /dev/null +++ b/UnigeSoftware/ViewModels/MainWindowViewModel.cs @@ -0,0 +1,22 @@ +using OgeSharp; +using ReactiveUI; +using ReactiveUI.Fody.Helpers; + +namespace UnigeSoftware.ViewModels { + public class MainWindowViewModel : ReactiveObject { + + public Oge Oge = new Oge(); + + [Reactive] public ReactiveObject Content { get; set; } + + public MainWindowViewModel() { + + // Initialize the connect view model + Content = new ConnectViewModel(this); + + } + + public void OnConnected() => Content = new HomeViewModel(this); + + } +} diff --git a/UnigeSoftware/Views/ConnectView.axaml b/UnigeSoftware/Views/ConnectView.axaml new file mode 100644 index 0000000..1a754e1 --- /dev/null +++ b/UnigeSoftware/Views/ConnectView.axaml @@ -0,0 +1,53 @@ + + + + + + + Connexion à OGE + + + Nom d'utilisateur: + + + + + Mot de passe: + + + + + + + + + + + + + + + + + + diff --git a/UnigeSoftware/Views/ConnectView.axaml.cs b/UnigeSoftware/Views/ConnectView.axaml.cs new file mode 100644 index 0000000..7b2f2cf --- /dev/null +++ b/UnigeSoftware/Views/ConnectView.axaml.cs @@ -0,0 +1,25 @@ +using Avalonia.ReactiveUI; +using ReactiveUI; +using ReactiveUI.Validation.Extensions; +using System.Reactive.Disposables; +using UnigeSoftware.ViewModels; + +namespace UnigeSoftware.Views { + + public partial class ConnectView : ReactiveUserControl { + + public ConnectView() { + InitializeComponent(); + + // Input validation + this.WhenActivated(disposables => { + + this.BindValidation(ViewModel, viewModel => viewModel.Username, view => view.UsernameError.Text).DisposeWith(disposables); + this.BindValidation(ViewModel, viewModel => viewModel.Password, view => view.PasswordError.Text).DisposeWith(disposables); + + }); + + } + + } +} diff --git a/UnigeSoftware/Views/HomeView.axaml b/UnigeSoftware/Views/HomeView.axaml new file mode 100644 index 0000000..677f926 --- /dev/null +++ b/UnigeSoftware/Views/HomeView.axaml @@ -0,0 +1,11 @@ + + + + + diff --git a/UnigeSoftware/Views/HomeView.axaml.cs b/UnigeSoftware/Views/HomeView.axaml.cs new file mode 100644 index 0000000..90200ff --- /dev/null +++ b/UnigeSoftware/Views/HomeView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace UnigeSoftware.Views { + public partial class HomeView : UserControl { + + public HomeView() => InitializeComponent(); + private void InitializeComponent() => AvaloniaXamlLoader.Load(this); + + } +} diff --git a/UnigeSoftware/Views/MainWindow.axaml b/UnigeSoftware/Views/MainWindow.axaml new file mode 100644 index 0000000..16f271d --- /dev/null +++ b/UnigeSoftware/Views/MainWindow.axaml @@ -0,0 +1,20 @@ + + + diff --git a/UnigeSoftware/Views/MainWindow.axaml.cs b/UnigeSoftware/Views/MainWindow.axaml.cs new file mode 100644 index 0000000..1d3a687 --- /dev/null +++ b/UnigeSoftware/Views/MainWindow.axaml.cs @@ -0,0 +1,18 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace UnigeSoftware.Views { + public partial class MainWindow : Window { + public MainWindow() { + InitializeComponent(); +#if DEBUG + this.AttachDevTools(); +#endif + } + + private void InitializeComponent() { + AvaloniaXamlLoader.Load(this); + } + } +}