feat(01-06): build WPF shell — MainWindow XAML, ViewModels, LogPanelSink wiring
- Add FeatureTabBase UserControl with ProgressBar/TextBlock/CancelButton strip (Visibility bound to IsRunning, shown only during operations) - Add MainWindowViewModel with TenantProfiles ObservableCollection, ConnectCommand, ClearSessionCommand, ManageProfilesCommand, ProgressUpdatedMessage subscription - Add ProfileManagementViewModel wrapping ProfileService CRUD with input validation - Add SettingsViewModel (extends FeatureViewModelBase) with language/folder settings - Update MainWindow.xaml: DockPanel shell with Toolbar, TabControl (8 tabs), 150px RichTextBox LogPanel, StatusBar (tenant name | ProgressStatus | ProgressPercentage) - MainWindow.xaml.cs: DI constructor, DataContext=viewModel, LoadProfilesAsync on Loaded - App.xaml.cs: register all services, wire LogPanelSink after MainWindow resolved, register DispatcherUnhandledException and UnobservedTaskException global handlers - App.xaml: add BoolToVisibilityConverter resource
This commit is contained in:
94
SharepointToolbox/ViewModels/Tabs/SettingsViewModel.cs
Normal file
94
SharepointToolbox/ViewModels/Tabs/SettingsViewModel.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
|
||||
public RelayCommand BrowseFolderCommand { get; }
|
||||
|
||||
public SettingsViewModel(SettingsService settingsService, ILogger<FeatureViewModelBase> logger)
|
||||
: base(logger)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
BrowseFolderCommand = new RelayCommand(BrowseFolder);
|
||||
}
|
||||
|
||||
public async Task LoadAsync()
|
||||
{
|
||||
var settings = await _settingsService.GetSettingsAsync();
|
||||
_selectedLanguage = settings.Lang;
|
||||
_dataFolder = settings.DataFolder;
|
||||
OnPropertyChanged(nameof(SelectedLanguage));
|
||||
OnPropertyChanged(nameof(DataFolder));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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.");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user