diff --git a/Marechai.App/App.xaml b/Marechai.App/App.xaml
index 115bc560..f7b0ef4a 100644
--- a/Marechai.App/App.xaml
+++ b/Marechai.App/App.xaml
@@ -8,7 +8,7 @@
-
+
@@ -17,6 +17,10 @@
+
+
+
+
diff --git a/Marechai.App/App.xaml.cs b/Marechai.App/App.xaml.cs
index b329691d..d026f431 100644
--- a/Marechai.App/App.xaml.cs
+++ b/Marechai.App/App.xaml.cs
@@ -27,6 +27,7 @@ using ProcessorsListViewModel = Marechai.App.Presentation.ViewModels.ProcessorsL
using SettingsViewModel = Marechai.App.Presentation.ViewModels.SettingsViewModel;
using SoundSynthDetailViewModel = Marechai.App.Presentation.ViewModels.SoundSynthDetailViewModel;
using SoundSynthsListViewModel = Marechai.App.Presentation.ViewModels.SoundSynthsListViewModel;
+using LoginViewModel = Marechai.App.Presentation.ViewModels.LoginViewModel;
namespace Marechai.App;
@@ -164,6 +165,7 @@ public partial class App : Application
services.AddTransient();
services.AddTransient();
services.AddTransient();
+ services.AddTransient();
})
.UseNavigation(RegisterRoutes));
@@ -181,6 +183,7 @@ public partial class App : Application
{
views.Register(new ViewMap(ViewModel: typeof(ShellViewModel)),
new ViewMap(),
+ new ViewMap(),
new ViewMap(),
new ViewMap(),
new ViewMap(),
@@ -203,6 +206,7 @@ public partial class App : Application
views.FindByViewModel(),
Nested:
[
+ new RouteMap("Login", views.FindByViewModel()),
new RouteMap("Main",
views.FindByViewModel(),
true,
diff --git a/Marechai.App/Presentation/ViewModels/LoginViewModel.cs b/Marechai.App/Presentation/ViewModels/LoginViewModel.cs
new file mode 100644
index 00000000..429b0425
--- /dev/null
+++ b/Marechai.App/Presentation/ViewModels/LoginViewModel.cs
@@ -0,0 +1,93 @@
+#nullable enable
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Uno.Extensions.Authentication;
+using Uno.Extensions.Navigation;
+
+namespace Marechai.App.Presentation.ViewModels;
+
+public partial class LoginViewModel : ObservableObject
+{
+ private readonly IAuthenticationService _authService;
+ private readonly INavigator _navigator;
+ private readonly IStringLocalizer _stringLocalizer;
+
+ [ObservableProperty]
+ private string _email = string.Empty;
+ [ObservableProperty]
+ private string? _errorMessage;
+ [ObservableProperty]
+ private bool _isLoggingIn;
+ [ObservableProperty]
+ private string _password = string.Empty;
+
+ public LoginViewModel(INavigator navigator, IAuthenticationService authService, IStringLocalizer stringLocalizer)
+ {
+ _navigator = navigator;
+ _authService = authService;
+ _stringLocalizer = stringLocalizer;
+ }
+
+ [RelayCommand]
+ private async Task LoginAsync()
+ {
+ // Clear previous error
+ ErrorMessage = null;
+
+ // Validate inputs
+ if(string.IsNullOrWhiteSpace(Email))
+ {
+ ErrorMessage = _stringLocalizer["LoginPage.Error.EmailRequired"];
+
+ return;
+ }
+
+ if(string.IsNullOrWhiteSpace(Password))
+ {
+ ErrorMessage = _stringLocalizer["LoginPage.Error.PasswordRequired"];
+
+ return;
+ }
+
+ IsLoggingIn = true;
+
+ try
+ {
+ var credentials = new Dictionary
+ {
+ ["Email"] = Email,
+ ["Password"] = Password
+ };
+
+ bool success = await _authService.LoginAsync(null, credentials, null, CancellationToken.None);
+
+ if(success)
+ {
+ // Navigate back to main page on successful login
+ await _navigator.NavigateRouteAsync(this, "/Main");
+ }
+ else
+ {
+ // Check if there's an error message in credentials
+ if(credentials.TryGetValue("error", out string? error))
+ ErrorMessage = error;
+ else
+ ErrorMessage = _stringLocalizer["LoginPage.Error.LoginFailed"];
+ }
+ }
+ catch(Exception ex)
+ {
+ ErrorMessage = ex.Message;
+ }
+ finally
+ {
+ IsLoggingIn = false;
+ }
+ }
+
+ [RelayCommand]
+ private void ClearError() => ErrorMessage = null;
+}
\ No newline at end of file
diff --git a/Marechai.App/Presentation/ViewModels/MainViewModel.cs b/Marechai.App/Presentation/ViewModels/MainViewModel.cs
index bdc3912d..ea7e7e55 100644
--- a/Marechai.App/Presentation/ViewModels/MainViewModel.cs
+++ b/Marechai.App/Presentation/ViewModels/MainViewModel.cs
@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
+using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using Marechai.App.Services;
+using Uno.Extensions.Authentication;
using Uno.Extensions.Navigation;
using Uno.Extensions.Toolkit;
@@ -10,8 +12,9 @@ namespace Marechai.App.Presentation.ViewModels;
public partial class MainViewModel : ObservableObject
{
- private readonly IStringLocalizer _localizer;
- private readonly INavigator _navigator;
+ private readonly IAuthenticationService _authService;
+ private readonly IStringLocalizer _localizer;
+ private readonly INavigator _navigator;
[ObservableProperty]
private bool _isSidebarOpen = true;
[ObservableProperty]
@@ -27,10 +30,12 @@ public partial class MainViewModel : ObservableObject
private bool _sidebarContentVisible = true;
public MainViewModel(IStringLocalizer localizer, IOptions appInfo, INavigator navigator,
- NewsViewModel newsViewModel, IColorThemeService colorThemeService, IThemeService themeService)
+ NewsViewModel newsViewModel, IColorThemeService colorThemeService, IThemeService themeService,
+ IAuthenticationService authService)
{
_navigator = navigator;
_localizer = localizer;
+ _authService = authService;
NewsViewModel = newsViewModel;
Title = "Marechai";
Title += $" - {localizer["ApplicationName"]}";
@@ -62,6 +67,9 @@ public partial class MainViewModel : ObservableObject
LoginLogoutCommand = new RelayCommand(HandleLoginLogout);
ToggleSidebarCommand = new RelayCommand(() => IsSidebarOpen = !IsSidebarOpen);
+ // Subscribe to authentication events
+ _authService.LoggedOut += OnLoggedOut;
+
UpdateLoginLogoutButtonText();
}
@@ -157,16 +165,39 @@ public partial class MainViewModel : ObservableObject
};
}
- private void UpdateLoginLogoutButtonText()
+ private async void UpdateLoginLogoutButtonText()
{
- // TODO: Check if user is logged in
- // For now, always show "Login"
- LoginLogoutButtonText = LocalizedStrings["Login"];
+ bool isAuthenticated = await _authService.IsAuthenticated(CancellationToken.None);
+ LoginLogoutButtonText = isAuthenticated ? LocalizedStrings["Logout"] : LocalizedStrings["Login"];
}
- private static void HandleLoginLogout()
+ private void OnLoggedOut(object? sender, EventArgs e)
{
- // TODO: Implement login/logout logic
+ // Update button text when user logs out
+ UpdateLoginLogoutButtonText();
+ }
+
+ public void RefreshAuthenticationState()
+ {
+ // Public method to refresh authentication state (called after login)
+ UpdateLoginLogoutButtonText();
+ }
+
+ private async void HandleLoginLogout()
+ {
+ bool isAuthenticated = await _authService.IsAuthenticated(CancellationToken.None);
+
+ if(isAuthenticated)
+ {
+ // Logout
+ await _authService.LogoutAsync(null, CancellationToken.None);
+ UpdateLoginLogoutButtonText();
+ }
+ else
+ {
+ // Navigate to login page - use absolute path starting from root
+ await _navigator.NavigateRouteAsync(this, "/Login");
+ }
}
private async Task NavigateTo(string destination)
diff --git a/Marechai.App/Presentation/ViewModels/ShellViewModel.cs b/Marechai.App/Presentation/ViewModels/ShellViewModel.cs
index 13edb3f6..45b4f5a3 100644
--- a/Marechai.App/Presentation/ViewModels/ShellViewModel.cs
+++ b/Marechai.App/Presentation/ViewModels/ShellViewModel.cs
@@ -8,5 +8,6 @@ public class ShellViewModel
public ShellViewModel(INavigator navigator) => _navigator = navigator;
- // Add code here to initialize or attach event handlers to singleton services
+ // Users can browse the app without authentication
+ // Login is available from the sidebar when needed
}
\ No newline at end of file
diff --git a/Marechai.App/Presentation/Views/LoginPage.xaml b/Marechai.App/Presentation/Views/LoginPage.xaml
new file mode 100644
index 00000000..35fc19b2
--- /dev/null
+++ b/Marechai.App/Presentation/Views/LoginPage.xaml
@@ -0,0 +1,209 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Marechai.App/Presentation/Views/LoginPage.xaml.cs b/Marechai.App/Presentation/Views/LoginPage.xaml.cs
new file mode 100644
index 00000000..a53a5479
--- /dev/null
+++ b/Marechai.App/Presentation/Views/LoginPage.xaml.cs
@@ -0,0 +1,33 @@
+using Windows.System;
+using Marechai.App.Presentation.ViewModels;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Input;
+
+namespace Marechai.App.Presentation.Views;
+
+public sealed partial class LoginPage : Page
+{
+ public LoginPage() => InitializeComponent();
+
+ private void OnEmailKeyDown(object sender, KeyRoutedEventArgs e)
+ {
+ if(e.Key == VirtualKey.Enter)
+ {
+ // Move focus to password field
+ PasswordBox.Focus(FocusState.Keyboard);
+ e.Handled = true;
+ }
+ }
+
+ private void OnPasswordKeyDown(object sender, KeyRoutedEventArgs e)
+ {
+ if(e.Key == VirtualKey.Enter)
+ {
+ // Trigger login when Enter is pressed
+ if(DataContext is LoginViewModel viewModel && LoginButton.IsEnabled) viewModel.LoginCommand.Execute(null);
+
+ e.Handled = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Marechai.App/Strings/en/Resources.resw b/Marechai.App/Strings/en/Resources.resw
index 8a318269..c5ae151f 100644
--- a/Marechai.App/Strings/en/Resources.resw
+++ b/Marechai.App/Strings/en/Resources.resw
@@ -224,4 +224,51 @@
Design system changes will be applied the next time you start the application. Color theme changes are applied immediately.
+
+
+
+ Sign In to Marechai
+
+
+ Welcome back! Please sign in to continue.
+
+
+ Email Address
+
+
+ Enter your email
+
+
+ Password
+
+
+ Enter your password
+
+
+ Sign In
+
+
+ Sign In
+
+
+ Signing in...
+
+
+ Forgot your password?
+
+
+ Don't have an account?
+
+
+ Sign up
+
+
+ Email address is required.
+
+
+ Password is required.
+
+
+ Login failed. Please check your credentials and try again.
+
diff --git a/Marechai.App/Strings/es/Resources.resw b/Marechai.App/Strings/es/Resources.resw
index 07bac86e..697a2816 100644
--- a/Marechai.App/Strings/es/Resources.resw
+++ b/Marechai.App/Strings/es/Resources.resw
@@ -224,4 +224,51 @@
Los cambios del sistema de diseño se aplicarán la próxima vez que inicie la aplicación. Los cambios de tema de color se aplican inmediatamente.
+
+
+
+ Iniciar Sesión en Marechai
+
+
+ ¡Bienvenido de nuevo! Por favor, inicia sesión para continuar.
+
+
+ Dirección de Correo Electrónico
+
+
+ Ingrese su correo electrónico
+
+
+ Contraseña
+
+
+ Ingrese su contraseña
+
+
+ Iniciar Sesión
+
+
+ Iniciar Sesión
+
+
+ Iniciando sesión...
+
+
+ ¿Olvidó su contraseña?
+
+
+ ¿No tiene una cuenta?
+
+
+ Registrarse
+
+
+ La dirección de correo electrónico es obligatoria.
+
+
+ La contraseña es obligatoria.
+
+
+ Error al iniciar sesión. Por favor, verifique sus credenciales e intente nuevamente.
+
diff --git a/Marechai.App/Strings/fr/Resources.resw b/Marechai.App/Strings/fr/Resources.resw
index e16e0b04..4cb720e7 100644
--- a/Marechai.App/Strings/fr/Resources.resw
+++ b/Marechai.App/Strings/fr/Resources.resw
@@ -222,6 +222,53 @@
Système de Conception
- Les modifications du système de conception seront appliquées au prochain démarrage de l'application. Les modifications du thème de couleur sont appliquées immédiatement.
+ Les modifications du système de conception seront appliquées la prochaine fois que vous démarrerez l'application. Les modifications du thème de couleur sont appliquées immédiatement.
+
+
+
+
+ Se Connecter à Marechai
+
+
+ Bienvenue ! Veuillez vous connecter pour continuer.
+
+
+ Adresse E-mail
+
+
+ Entrez votre e-mail
+
+
+ Mot de Passe
+
+
+ Entrez votre mot de passe
+
+
+ Se Connecter
+
+
+ Se Connecter
+
+
+ Connexion en cours...
+
+
+ Mot de passe oublié ?
+
+
+ Vous n'avez pas de compte ?
+
+
+ S'inscrire
+
+
+ L'adresse e-mail est requise.
+
+
+ Le mot de passe est requis.
+
+
+ Échec de la connexion. Veuillez vérifier vos identifiants et réessayer.
diff --git a/Marechai.App/Strings/pt-BR/Resources.resw b/Marechai.App/Strings/pt-BR/Resources.resw
index 96a3ee19..8cae6460 100644
--- a/Marechai.App/Strings/pt-BR/Resources.resw
+++ b/Marechai.App/Strings/pt-BR/Resources.resw
@@ -222,6 +222,53 @@
Sistema de Design
- As alterações do sistema de design serão aplicadas na próxima vez que você iniciar o aplicativo. As alterações de tema de cor são aplicadas imediatamente.
+ As alterações no sistema de design serão aplicadas na próxima vez que você iniciar o aplicativo. As alterações no tema de cores são aplicadas imediatamente.
+
+
+
+
+ Entrar no Marechai
+
+
+ Bem-vindo de volta! Por favor, faça login para continuar.
+
+
+ Endereço de E-mail
+
+
+ Digite seu e-mail
+
+
+ Senha
+
+
+ Digite sua senha
+
+
+ Entrar
+
+
+ Entrar
+
+
+ Entrando...
+
+
+ Esqueceu sua senha?
+
+
+ Não tem uma conta?
+
+
+ Cadastre-se
+
+
+ O endereço de e-mail é obrigatório.
+
+
+ A senha é obrigatória.
+
+
+ Falha no login. Por favor, verifique suas credenciais e tente novamente.