- AppSettings.AutoTakeOwnership bool property defaulting to false - PermissionEntry.WasAutoElevated optional param (default false, last position) - SettingsService.SetAutoTakeOwnershipAsync persists toggle - IOwnershipElevationService interface + OwnershipElevationService wrapping Tenant.SetSiteAdmin - SettingsViewModel.AutoTakeOwnership property loads and persists via SetAutoTakeOwnershipAsync - DI registration in App.xaml.cs (Phase 18 section) - 8 new tests: models, persistence, service, viewmodel
152 lines
4.6 KiB
C#
152 lines
4.6 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 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 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, ILogger<FeatureViewModelBase> logger)
|
|
: base(logger)
|
|
{
|
|
_settingsService = settingsService;
|
|
_brandingService = brandingService;
|
|
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;
|
|
OnPropertyChanged(nameof(SelectedLanguage));
|
|
OnPropertyChanged(nameof(DataFolder));
|
|
OnPropertyChanged(nameof(AutoTakeOwnership));
|
|
|
|
var mspLogo = await _brandingService.GetMspLogoAsync();
|
|
MspLogoPreview = mspLogo is not null ? $"data:{mspLogo.MimeType};base64,{mspLogo.Base64}" : null;
|
|
}
|
|
|
|
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.");
|
|
}
|
|
}
|