227 lines
8.6 KiB
C#
227 lines
8.6 KiB
C#
using System;
|
|
using System.Threading.Tasks;
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
using CommunityToolkit.Mvvm.Input;
|
|
using LANCommander.Launcher.Services;
|
|
using LANCommander.SDK.Providers;
|
|
using LANCommander.SDK.Services;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace LANCommander.Launcher.ViewModels;
|
|
|
|
public partial class MainWindowViewModel : ViewModelBase
|
|
{
|
|
private readonly IServiceProvider _serviceProvider;
|
|
private readonly IConnectionClient _connectionClient;
|
|
private readonly AuthenticationService _authenticationService;
|
|
private readonly SettingsProvider<Settings.Settings> _settingsProvider;
|
|
private readonly ILogger<MainWindowViewModel> _logger;
|
|
|
|
[ObservableProperty]
|
|
[NotifyPropertyChangedFor(nameof(IsLogoVisible))]
|
|
private ViewModelBase _currentView;
|
|
|
|
[ObservableProperty]
|
|
private string _title = "LANCommander Launcher";
|
|
|
|
[ObservableProperty]
|
|
private bool _isShellActive;
|
|
|
|
[ObservableProperty]
|
|
[NotifyPropertyChangedFor(nameof(IsNotBigScreenMode))]
|
|
private bool _isBigScreenMode;
|
|
|
|
public bool IsNotBigScreenMode => !IsBigScreenMode;
|
|
|
|
public bool IsLogoVisible => CurrentView != ServerSelectionViewModel && CurrentView != LoginViewModel;
|
|
public bool ShowTitlebarTint => !IsShellActive || ShellViewModel.IsTitlebarTinted;
|
|
|
|
public event EventHandler? BigScreenModeChanged;
|
|
public event EventHandler? ExitLauncherRequested;
|
|
|
|
[RelayCommand]
|
|
private void EnterBigScreenMode()
|
|
{
|
|
IsBigScreenMode = true;
|
|
_settingsProvider.Update(s => s.Window.BigScreenMode = true);
|
|
BigScreenModeChanged?.Invoke(this, EventArgs.Empty);
|
|
}
|
|
|
|
[RelayCommand]
|
|
private void ExitBigScreenMode()
|
|
{
|
|
IsBigScreenMode = false;
|
|
_settingsProvider.Update(s => s.Window.BigScreenMode = false);
|
|
BigScreenModeChanged?.Invoke(this, EventArgs.Empty);
|
|
}
|
|
|
|
[RelayCommand]
|
|
private void ExitLauncher()
|
|
{
|
|
ExitLauncherRequested?.Invoke(this, EventArgs.Empty);
|
|
}
|
|
|
|
partial void OnCurrentViewChanged(ViewModelBase value)
|
|
{
|
|
IsShellActive = value is ShellViewModel;
|
|
OnPropertyChanged(nameof(ShowTitlebarTint));
|
|
}
|
|
|
|
public SplashViewModel SplashViewModel { get; }
|
|
public ServerSelectionViewModel ServerSelectionViewModel { get; }
|
|
public LoginViewModel LoginViewModel { get; }
|
|
public ShellViewModel ShellViewModel { get; }
|
|
|
|
public MainWindowViewModel(
|
|
IServiceProvider serviceProvider,
|
|
IConnectionClient connectionClient,
|
|
AuthenticationService authenticationService,
|
|
SettingsProvider<Settings.Settings> settingsProvider)
|
|
{
|
|
_serviceProvider = serviceProvider;
|
|
_connectionClient = connectionClient;
|
|
_authenticationService = authenticationService;
|
|
_settingsProvider = settingsProvider;
|
|
_logger = serviceProvider.GetRequiredService<ILogger<MainWindowViewModel>>();
|
|
|
|
SplashViewModel = new SplashViewModel();
|
|
ServerSelectionViewModel = new ServerSelectionViewModel(connectionClient, settingsProvider, serviceProvider.GetRequiredService<BeaconClient>());
|
|
LoginViewModel = new LoginViewModel(connectionClient, authenticationService, serviceProvider.GetRequiredService<AuthenticationClient>(), settingsProvider);
|
|
ShellViewModel = new ShellViewModel(serviceProvider);
|
|
|
|
// Propagate shell titlebar tint changes
|
|
ShellViewModel.PropertyChanged += (_, e) =>
|
|
{
|
|
if (e.PropertyName == nameof(ShellViewModel.IsTitlebarTinted))
|
|
OnPropertyChanged(nameof(ShowTitlebarTint));
|
|
};
|
|
|
|
// Wire up navigation events
|
|
ServerSelectionViewModel.ServerConnected += OnServerConnected;
|
|
LoginViewModel.LoginSucceeded += OnLoginSucceeded;
|
|
LoginViewModel.ChangeServerRequested += OnChangeServerRequested;
|
|
ShellViewModel.LogoutRequested += OnLogoutRequested;
|
|
|
|
// Start with splash screen
|
|
_currentView = SplashViewModel;
|
|
|
|
// Restore big screen mode from settings or command line
|
|
if (settingsProvider.CurrentValue.Window.BigScreenMode)
|
|
_isBigScreenMode = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enables big screen mode from an external source (e.g. command line).
|
|
/// Must be called before InitializeAsync so the event fires after the window is ready.
|
|
/// </summary>
|
|
public void SetBigScreenMode()
|
|
{
|
|
_isBigScreenMode = true;
|
|
}
|
|
|
|
public async Task InitializeAsync()
|
|
{
|
|
SplashViewModel.UpdateStatus("Checking connection...");
|
|
|
|
// Check if we have a saved server address and valid token
|
|
var settings = _settingsProvider.CurrentValue;
|
|
|
|
if (settings.Authentication?.ServerAddress != null)
|
|
{
|
|
SplashViewModel.UpdateStatus("Connecting to server...");
|
|
await _connectionClient.UpdateServerAddressAsync(settings.Authentication.ServerAddress.ToString());
|
|
|
|
// Check if server is reachable
|
|
var serverOnline = await _connectionClient.PingAsync();
|
|
|
|
if (_authenticationService.HasStoredCredentials())
|
|
{
|
|
if (serverOnline)
|
|
{
|
|
try
|
|
{
|
|
SplashViewModel.UpdateStatus("Authenticating...");
|
|
// Try to login with stored credentials
|
|
await _authenticationService.Login();
|
|
|
|
if (_connectionClient.IsConnected())
|
|
{
|
|
SplashViewModel.UpdateStatus("Loading library...");
|
|
// Token is valid - go directly to shell in online mode
|
|
ShellViewModel.SetOfflineMode(false);
|
|
await ShellViewModel.InitializeAsync();
|
|
CurrentView = ShellViewModel;
|
|
return;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Token validation failed");
|
|
// Token validation failed - continue to check offline mode
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Server offline but we have stored credentials - go to shell in offline mode
|
|
_logger.LogInformation("Server unreachable, starting in offline mode with stored credentials");
|
|
SplashViewModel.UpdateStatus("Server offline, starting in offline mode...");
|
|
await _connectionClient.EnableOfflineModeAsync();
|
|
ShellViewModel.SetOfflineMode(true);
|
|
await ShellViewModel.InitializeAsync();
|
|
CurrentView = ShellViewModel;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// We have a server but no valid token - go to login
|
|
// If server is offline and no credentials, user stays on login (can't proceed)
|
|
LoginViewModel.ServerAddress = settings.Authentication.ServerAddress.ToString();
|
|
LoginViewModel.IsServerOffline = !serverOnline;
|
|
|
|
if (serverOnline)
|
|
await LoginViewModel.LoadAuthenticationProvidersAsync();
|
|
|
|
CurrentView = LoginViewModel;
|
|
|
|
if (serverOnline)
|
|
await LoginViewModel.TryAutoRedirectToProviderAsync();
|
|
|
|
return;
|
|
}
|
|
|
|
// No saved server - show server selection
|
|
CurrentView = ServerSelectionViewModel;
|
|
}
|
|
|
|
private async void OnServerConnected(object? sender, EventArgs e)
|
|
{
|
|
LoginViewModel.ServerAddress = _connectionClient.GetServerAddress()?.ToString() ?? string.Empty;
|
|
LoginViewModel.IsServerOffline = false;
|
|
await LoginViewModel.LoadAuthenticationProvidersAsync();
|
|
CurrentView = LoginViewModel;
|
|
await LoginViewModel.TryAutoRedirectToProviderAsync();
|
|
}
|
|
|
|
private async void OnLoginSucceeded(object? sender, EventArgs e)
|
|
{
|
|
// Show the splash screen with a loading message while initializing
|
|
SplashViewModel.UpdateStatus("Loading library...");
|
|
CurrentView = SplashViewModel;
|
|
|
|
// Initialize shell fully before switching view to avoid rendering uninitialized state
|
|
ShellViewModel.SetOfflineMode(false);
|
|
await ShellViewModel.InitializeAsync();
|
|
CurrentView = ShellViewModel;
|
|
}
|
|
|
|
private void OnChangeServerRequested(object? sender, EventArgs e)
|
|
{
|
|
CurrentView = ServerSelectionViewModel;
|
|
}
|
|
|
|
private void OnLogoutRequested(object? sender, EventArgs e)
|
|
{
|
|
CurrentView = LoginViewModel;
|
|
}
|
|
}
|