Files
Sharepoint-Toolbox/SharepointToolbox/ViewModels/Tabs/SettingsViewModel.cs
T
Dev f4cc81bb71 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>
2026-04-20 11:23:11 +02:00

182 lines
5.4 KiB
C#

using System.Globalization;
using Microsoft.Win32;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Extensions.Logging;
using SharepointToolbox.Core.Models;
using SharepointToolbox.Localization;
using SharepointToolbox.Services;
namespace SharepointToolbox.ViewModels.Tabs;
public partial class SettingsViewModel : FeatureViewModelBase
{
private readonly SettingsService _settingsService;
private readonly IBrandingService _brandingService;
private readonly ThemeManager _themeManager;
private string _selectedLanguage = "en";
public string SelectedLanguage
{
get => _selectedLanguage;
set
{
if (_selectedLanguage == value) return;
_selectedLanguage = value;
OnPropertyChanged();
_ = ApplyLanguageAsync(value);
}
}
private string _dataFolder = string.Empty;
public string DataFolder
{
get => _dataFolder;
set
{
if (_dataFolder == value) return;
_dataFolder = value;
OnPropertyChanged();
_ = _settingsService.SetDataFolderAsync(value);
}
}
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
{
get => _autoTakeOwnership;
set
{
if (_autoTakeOwnership == value) return;
_autoTakeOwnership = value;
OnPropertyChanged();
_ = _settingsService.SetAutoTakeOwnershipAsync(value);
}
}
private string? _mspLogoPreview;
public string? MspLogoPreview
{
get => _mspLogoPreview;
private set { _mspLogoPreview = value; OnPropertyChanged(); }
}
public RelayCommand BrowseFolderCommand { get; }
public IAsyncRelayCommand BrowseMspLogoCommand { get; }
public IAsyncRelayCommand ClearMspLogoCommand { get; }
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);
}
public async Task LoadAsync()
{
var settings = await _settingsService.GetSettingsAsync();
_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
{
TranslationSource.Instance.CurrentCulture = new CultureInfo(code);
await _settingsService.SetLanguageAsync(code);
}
catch (Exception ex)
{
StatusMessage = ex.Message;
}
}
private void BrowseFolder()
{
// OpenFolderDialog is available in .NET 8+ via Microsoft.Win32
var dialog = new OpenFolderDialog
{
Title = "Select data output folder",
InitialDirectory = string.IsNullOrEmpty(_dataFolder)
? Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
: _dataFolder
};
if (dialog.ShowDialog() == true)
{
DataFolder = dialog.FolderName;
}
}
private async Task BrowseMspLogoAsync()
{
var dialog = new OpenFileDialog
{
Title = "Select MSP logo",
Filter = "Image files (*.png;*.jpg;*.jpeg)|*.png;*.jpg;*.jpeg",
};
if (dialog.ShowDialog() != true) return;
try
{
var logo = await _brandingService.ImportLogoAsync(dialog.FileName);
await _brandingService.SaveMspLogoAsync(logo);
MspLogoPreview = $"data:{logo.MimeType};base64,{logo.Base64}";
}
catch (Exception ex)
{
StatusMessage = ex.Message;
}
}
private async Task ClearMspLogoAsync()
{
await _brandingService.ClearMspLogoAsync();
MspLogoPreview = null;
}
protected override Task RunOperationAsync(CancellationToken ct, IProgress<OperationProgress> progress)
{
// Settings tab has no long-running operation
throw new NotSupportedException("Settings tab does not have a run operation.");
}
}