chore: release v2.4

- Add theme system (Dark/Light palettes, ModernTheme, ThemeManager)
- Add InputDialog, Spinner common view
- Add DuplicatesCsvExportService
- Refresh views, dialogs, and view models across tabs
- Update localization strings (en/fr)
- Tweak services (transfer, permissions, search, user access, ownership elevation, bulk operations)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dev
2026-04-20 11:23:11 +02:00
parent 8f30a60d2a
commit f4cc81bb71
64 changed files with 3315 additions and 405 deletions
@@ -12,6 +12,7 @@ public partial class SettingsViewModel : FeatureViewModelBase
{
private readonly SettingsService _settingsService;
private readonly IBrandingService _brandingService;
private readonly ThemeManager _themeManager;
private string _selectedLanguage = "en";
public string SelectedLanguage
@@ -39,6 +40,19 @@ public partial class SettingsViewModel : FeatureViewModelBase
}
}
private string _selectedTheme = "System";
public string SelectedTheme
{
get => _selectedTheme;
set
{
if (_selectedTheme == value) return;
_selectedTheme = value;
OnPropertyChanged();
_ = ApplyThemeAsync(value);
}
}
private bool _autoTakeOwnership;
public bool AutoTakeOwnership
{
@@ -63,11 +77,12 @@ public partial class SettingsViewModel : FeatureViewModelBase
public IAsyncRelayCommand BrowseMspLogoCommand { get; }
public IAsyncRelayCommand ClearMspLogoCommand { get; }
public SettingsViewModel(SettingsService settingsService, IBrandingService brandingService, ILogger<FeatureViewModelBase> logger)
public SettingsViewModel(SettingsService settingsService, IBrandingService brandingService, ThemeManager themeManager, ILogger<FeatureViewModelBase> logger)
: base(logger)
{
_settingsService = settingsService;
_brandingService = brandingService;
_themeManager = themeManager;
BrowseFolderCommand = new RelayCommand(BrowseFolder);
BrowseMspLogoCommand = new AsyncRelayCommand(BrowseMspLogoAsync);
ClearMspLogoCommand = new AsyncRelayCommand(ClearMspLogoAsync);
@@ -79,14 +94,29 @@ public partial class SettingsViewModel : FeatureViewModelBase
_selectedLanguage = settings.Lang;
_dataFolder = settings.DataFolder;
_autoTakeOwnership = settings.AutoTakeOwnership;
_selectedTheme = settings.Theme;
OnPropertyChanged(nameof(SelectedLanguage));
OnPropertyChanged(nameof(DataFolder));
OnPropertyChanged(nameof(AutoTakeOwnership));
OnPropertyChanged(nameof(SelectedTheme));
var mspLogo = await _brandingService.GetMspLogoAsync();
MspLogoPreview = mspLogo is not null ? $"data:{mspLogo.MimeType};base64,{mspLogo.Base64}" : null;
}
private async Task ApplyThemeAsync(string mode)
{
try
{
_themeManager.ApplyFromString(mode);
await _settingsService.SetThemeAsync(mode);
}
catch (Exception ex)
{
StatusMessage = ex.Message;
}
}
private async Task ApplyLanguageAsync(string code)
{
try