diff --git a/LibreHardwareMonitor.Windows.WinUI/DialogService.cs b/LibreHardwareMonitor.Windows.WinUI/DialogService.cs new file mode 100644 index 0000000..895818d --- /dev/null +++ b/LibreHardwareMonitor.Windows.WinUI/DialogService.cs @@ -0,0 +1,376 @@ +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// Copyright (C) LibreHardwareMonitor and Contributors. + +using System; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Threading.Tasks; +using LibreHardwareMonitor.Hardware; +using LibreHardwareMonitor.Windows.WinUI.ViewModels; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Input; +using Windows.Storage; +using Windows.Storage.Pickers; +using WinRT.Interop; + +namespace LibreHardwareMonitor.Windows.WinUI; + +/// +/// Builds and shows the app's content dialogs (rename, pen color, sensor parameters, web-server settings and +/// authentication, save report, about) and the save-report file picker. Extracted from so the +/// modal UI flows live in one place; it reads the live through a provider and writes results +/// back through the view model. +/// +internal sealed class DialogService +{ + private readonly Func _xamlRootProvider; + private readonly MainWindowViewModel _viewModel; + private readonly IntPtr _windowHandle; + + public DialogService(Func xamlRootProvider, MainWindowViewModel viewModel, IntPtr windowHandle) + { + _xamlRootProvider = xamlRootProvider; + _viewModel = viewModel; + _windowHandle = windowHandle; + } + + public async Task RenameAsync(SensorTreeItemViewModel item) + { + if (!item.CanRename) + return; + + TextBox nameTextBox = new() { Text = item.Text, SelectionStart = 0, SelectionLength = item.Text.Length }; + ContentDialog dialog = new() + { + XamlRoot = _xamlRootProvider(), + Title = "Rename Sensor", + Content = nameTextBox, + PrimaryButtonText = "Save", + CloseButtonText = "Cancel", + DefaultButton = ContentDialogButton.Primary + }; + + if (await dialog.ShowAsync() == ContentDialogResult.Primary) + item.Text = nameTextBox.Text.Trim(); + } + + public async Task ShowPenColorAsync(SensorTreeItemViewModel item) + { + if (item.Sensor == null) + return; + + ColorPicker picker = new() + { + Color = item.PenColor ?? global::Windows.UI.Color.FromArgb(255, 0, 120, 212), + IsAlphaEnabled = false, + IsColorSliderVisible = true, + IsColorChannelTextInputVisible = true, + IsHexInputVisible = true + }; + + ContentDialog dialog = new() + { + XamlRoot = _xamlRootProvider(), + Title = "Pen Color", + Content = picker, + PrimaryButtonText = "Save", + CloseButtonText = "Cancel", + DefaultButton = ContentDialogButton.Primary + }; + + if (await dialog.ShowAsync() == ContentDialogResult.Primary) + _viewModel.SetSensorPenColor(item, picker.Color); + } + + public async Task ShowParametersAsync(SensorTreeItemViewModel item) + { + if (item.Sensor == null || item.Sensor.Parameters.Count == 0) + return; + + StackPanel panel = new() { Spacing = 10 }; + TextBlock caption = new() + { + Text = item.Sensor.Name, + FontWeight = new global::Windows.UI.Text.FontWeight { Weight = 600 }, + TextWrapping = TextWrapping.Wrap + }; + panel.Children.Add(caption); + + ParameterEditorRow[] rows = item.Sensor.Parameters.Select(CreateParameterEditorRow).ToArray(); + foreach (ParameterEditorRow row in rows) + panel.Children.Add(row.Container); + + ContentDialog dialog = new() + { + XamlRoot = _xamlRootProvider(), + Title = "Parameters", + Content = new ScrollViewer { Content = panel, MaxHeight = 520 }, + PrimaryButtonText = "OK", + CloseButtonText = "Cancel", + DefaultButton = ContentDialogButton.Primary + }; + dialog.PrimaryButtonClick += (sender, args) => + { + foreach (ParameterEditorRow row in rows) + { + if (row.UseDefault.IsChecked == true) + continue; + + if (!float.TryParse(row.Value.Text, NumberStyles.Float, CultureInfo.CurrentCulture, out float _) + && !float.TryParse(row.Value.Text, NumberStyles.Float, CultureInfo.InvariantCulture, out float _)) + { + row.Value.Header = "Invalid value"; + args.Cancel = true; + return; + } + } + + foreach (ParameterEditorRow row in rows) + { + if (row.UseDefault.IsChecked == true) + row.Parameter.IsDefault = true; + else if (float.TryParse(row.Value.Text, NumberStyles.Float, CultureInfo.CurrentCulture, out float currentCultureValue) + || float.TryParse(row.Value.Text, NumberStyles.Float, CultureInfo.InvariantCulture, out currentCultureValue)) + row.Parameter.Value = currentCultureValue; + } + }; + + await dialog.ShowAsync(); + } + + public async Task ShowWebServerSettingsAsync() + { + ComboBox interfaces = new() { MinWidth = 260 }; + foreach (string address in GetLocalIPv4Addresses()) + interfaces.Items.Add(address); + interfaces.Items.Add("0.0.0.0"); + interfaces.SelectedItem = interfaces.Items.Contains(_viewModel.ListenerIp) ? _viewModel.ListenerIp : "0.0.0.0"; + + TextBox port = new() + { + Header = "Port", + Text = _viewModel.ListenerPort.ToString(CultureInfo.InvariantCulture), + InputScope = new InputScope { Names = { new InputScopeName(InputScopeNameValue.Number) } } + }; + + HyperlinkButton link = new() + { + Content = _viewModel.WebServerUrl, + NavigateUri = new Uri(_viewModel.WebServerUrl) + }; + + StackPanel content = new() { Spacing = 12 }; + content.Children.Add(new TextBlock { Text = "Interface", FontWeight = new global::Windows.UI.Text.FontWeight { Weight = 600 } }); + content.Children.Add(interfaces); + content.Children.Add(port); + content.Children.Add(link); + + ContentDialog dialog = new() + { + XamlRoot = _xamlRootProvider(), + Title = "Remote Web Server", + Content = content, + PrimaryButtonText = "Save", + CloseButtonText = "Cancel", + DefaultButton = ContentDialogButton.Primary + }; + + dialog.PrimaryButtonClick += (_, args) => + { + if (!int.TryParse(port.Text, NumberStyles.Integer, CultureInfo.InvariantCulture, out int parsedPort) || parsedPort < 1 || parsedPort > 65535) + { + port.Header = "Port must be 1-65535"; + args.Cancel = true; + return; + } + + _viewModel.ListenerIp = interfaces.SelectedItem as string ?? "0.0.0.0"; + _viewModel.ListenerPort = parsedPort; + }; + + await dialog.ShowAsync(); + } + + public async Task ShowWebServerAuthenticationAsync() + { + CheckBox enabled = new() { Content = "Enable HTTP authentication", IsChecked = _viewModel.AuthWebServer }; + TextBox userName = new() + { + Header = "Username", + Text = _viewModel.AuthWebServerUserName, + IsEnabled = enabled.IsChecked == true + }; + PasswordBox password = new() + { + Header = "New password", + IsEnabled = enabled.IsChecked == true + }; + + enabled.Checked += (_, _) => userName.IsEnabled = password.IsEnabled = true; + enabled.Unchecked += (_, _) => userName.IsEnabled = password.IsEnabled = false; + + StackPanel content = new() { Spacing = 12 }; + content.Children.Add(enabled); + content.Children.Add(userName); + content.Children.Add(password); + + ContentDialog dialog = new() + { + XamlRoot = _xamlRootProvider(), + Title = "Remote Web Server Authentication", + Content = content, + PrimaryButtonText = "Save", + CloseButtonText = "Cancel", + DefaultButton = ContentDialogButton.Primary + }; + dialog.PrimaryButtonClick += (_, _) => + { + _viewModel.AuthWebServer = enabled.IsChecked == true; + _viewModel.AuthWebServerUserName = userName.Text; + _viewModel.SetAuthPassword(password.Password); + }; + + await dialog.ShowAsync(); + } + + public async Task SaveReportAsync() + { + FileSavePicker picker = new() + { + SuggestedFileName = "LibreHardwareMonitor.Report", + SuggestedStartLocation = PickerLocationId.DocumentsLibrary + }; + picker.FileTypeChoices.Add("Text", [".txt"]); + InitializeWithWindow.Initialize(picker, _windowHandle); + + StorageFile? file = await picker.PickSaveFileAsync(); + if (file == null) + return; + + CachedFileManager.DeferUpdates(file); + await FileIO.WriteTextAsync(file, _viewModel.GetReport()); + await CachedFileManager.CompleteUpdatesAsync(file); + } + + public async Task ShowAboutAsync() + { + StackPanel content = new() { Spacing = 8 }; + content.Children.Add(new TextBlock + { + Text = "Libre Hardware Monitor", + FontWeight = new global::Windows.UI.Text.FontWeight { Weight = 600 }, + FontSize = 18 + }); + content.Children.Add(new TextBlock + { + Text = $"Version {typeof(DialogService).Assembly.GetName().Version}", + TextWrapping = TextWrapping.Wrap + }); + content.Children.Add(new TextBlock + { + Text = "A free, open source hardware monitoring application.", + TextWrapping = TextWrapping.Wrap + }); + content.Children.Add(new HyperlinkButton + { + Content = "Project website", + NavigateUri = new Uri("https://github.com/LibreHardwareMonitor/LibreHardwareMonitor") + }); + content.Children.Add(new HyperlinkButton + { + Content = "Mozilla Public License 2.0", + NavigateUri = new Uri("https://www.mozilla.org/MPL/2.0/") + }); + + ContentDialog dialog = new() + { + XamlRoot = _xamlRootProvider(), + Title = "Libre Hardware Monitor", + Content = content, + CloseButtonText = "OK" + }; + await dialog.ShowAsync(); + } + + private static ParameterEditorRow CreateParameterEditorRow(IParameter parameter) + { + Grid grid = new() + { + ColumnDefinitions = + { + new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }, + new ColumnDefinition { Width = GridLength.Auto }, + new ColumnDefinition { Width = new GridLength(120) } + }, + RowDefinitions = + { + new RowDefinition { Height = GridLength.Auto }, + new RowDefinition { Height = GridLength.Auto } + }, + ColumnSpacing = 8 + }; + + TextBlock name = new() + { + Text = parameter.Name, + VerticalAlignment = VerticalAlignment.Center, + TextWrapping = TextWrapping.Wrap + }; + grid.Children.Add(name); + + CheckBox useDefault = new() + { + Content = "Default", + IsChecked = parameter.IsDefault, + VerticalAlignment = VerticalAlignment.Center + }; + Grid.SetColumn(useDefault, 1); + grid.Children.Add(useDefault); + + TextBox value = new() + { + Text = parameter.Value.ToString(CultureInfo.CurrentCulture), + IsEnabled = !parameter.IsDefault + }; + Grid.SetColumn(value, 2); + grid.Children.Add(value); + + TextBlock description = new() + { + Text = parameter.Description, + Opacity = 0.72, + TextWrapping = TextWrapping.Wrap + }; + Grid.SetRow(description, 1); + Grid.SetColumnSpan(description, 3); + grid.Children.Add(description); + + useDefault.Checked += (_, _) => value.IsEnabled = false; + useDefault.Unchecked += (_, _) => value.IsEnabled = true; + + return new ParameterEditorRow(parameter, grid, useDefault, value); + } + + private static string[] GetLocalIPv4Addresses() + { + try + { + return Dns.GetHostEntry(Dns.GetHostName()) + .AddressList + .Where(address => address.AddressFamily == AddressFamily.InterNetwork) + .Select(address => address.ToString()) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToArray(); + } + catch + { + return []; + } + } + + private sealed record ParameterEditorRow(IParameter Parameter, Grid Container, CheckBox UseDefault, TextBox Value); +} diff --git a/LibreHardwareMonitor.Windows.WinUI/MainWindow.cs b/LibreHardwareMonitor.Windows.WinUI/MainWindow.cs index fba7662..e919244 100644 --- a/LibreHardwareMonitor.Windows.WinUI/MainWindow.cs +++ b/LibreHardwareMonitor.Windows.WinUI/MainWindow.cs @@ -8,8 +8,6 @@ using System.Collections.Specialized; using System.Globalization; using System.IO; using System.Linq; -using System.Net; -using System.Net.Sockets; using System.Runtime.InteropServices; using System.Threading.Tasks; using LibreHardwareMonitor.Hardware; @@ -29,8 +27,6 @@ using Microsoft.UI.Xaml.Markup; using Microsoft.UI.Xaml.Media; using Microsoft.UI.Xaml.Shapes; using Windows.Graphics; -using Windows.Storage; -using Windows.Storage.Pickers; using WinRT.Interop; using IOPath = System.IO.Path; @@ -82,6 +78,7 @@ public sealed class MainWindow : Window private readonly Grid _sensorPane; private readonly WinUiStartupTrace? _startupTrace; private readonly TrayIconService _trayIconService; + private readonly DialogService _dialogService; private readonly Dictionary<(string Text, bool Bold), double> _textMeasurementCache = new(); private TextBlock? _measurementTextBlock; private readonly List _sensorRowGrids = []; @@ -131,6 +128,7 @@ public sealed class MainWindow : Window settings, () => ViewModel.TemperatureUnit)); _trayIconService.IsMainIconEnabled = ViewModel.MinimizeToTray; + _dialogService = new DialogService(() => Content.XamlRoot, ViewModel, WindowNative.GetWindowHandle(this)); Grid root = MeasureStartup("MainWindow.BuildRoot", BuildRoot); MeasureStartup("MainWindow.AssignContent", () => Content = root); @@ -382,7 +380,7 @@ public sealed class MainWindow : Window Bind(menuBar, Control.IsEnabledProperty, ViewModel, nameof(ViewModel.IsHardwareInteractionEnabled)); MenuBarItem file = new() { Title = "File" }; - file.Items.Add(CreateMenuItem("Save Report...", async (_, _) => await SaveReportAsync())); + file.Items.Add(CreateMenuItem("Save Report...", async (_, _) => await _dialogService.SaveReportAsync())); file.Items.Add(new MenuFlyoutSeparator()); file.Items.Add(CreateMenuItem("Reset", (_, _) => ViewModel.ResetHardware())); MenuFlyoutSubItem hardware = new() { Text = "Hardware" }; @@ -501,17 +499,17 @@ public sealed class MainWindow : Window ToggleMenuFlyoutItem runWebServer = CreateToggleItem("Run", nameof(ViewModel.RunWebServer)); runWebServer.IsEnabled = !ViewModel.IsWebServerUnavailable; webServer.Items.Add(runWebServer); - MenuFlyoutItem interfacePort = CreateMenuItem("Interface / Port", async (_, _) => await ShowWebServerSettingsAsync()); + MenuFlyoutItem interfacePort = CreateMenuItem("Interface / Port", async (_, _) => await _dialogService.ShowWebServerSettingsAsync()); interfacePort.IsEnabled = !ViewModel.IsWebServerUnavailable; webServer.Items.Add(interfacePort); - MenuFlyoutItem authentication = CreateMenuItem("Authentication", async (_, _) => await ShowWebServerAuthenticationAsync()); + MenuFlyoutItem authentication = CreateMenuItem("Authentication", async (_, _) => await _dialogService.ShowWebServerAuthenticationAsync()); authentication.IsEnabled = !ViewModel.IsWebServerUnavailable; webServer.Items.Add(authentication); options.Items.Add(webServer); menuBar.Items.Add(options); MenuBarItem help = new() { Title = "Help" }; - help.Items.Add(CreateMenuItem("About", async (_, _) => await ShowAboutAsync())); + help.Items.Add(CreateMenuItem("About", async (_, _) => await _dialogService.ShowAboutAsync())); menuBar.Items.Add(help); return menuBar; @@ -1024,7 +1022,7 @@ public sealed class MainWindow : Window row.DoubleTapped += async (_, _) => { if (item.Sensor?.Parameters.Count > 0) - await ShowParametersAsync(item); + await _dialogService.ShowParametersAsync(item); }; return row; } @@ -1033,9 +1031,9 @@ public sealed class MainWindow : Window { MenuFlyout flyout = new(); if (item.Sensor?.Parameters.Count > 0) - flyout.Items.Add(CreateMenuItem("Parameters...", async (_, _) => await ShowParametersAsync(item))); + flyout.Items.Add(CreateMenuItem("Parameters...", async (_, _) => await _dialogService.ShowParametersAsync(item))); - MenuFlyoutItem rename = CreateMenuItem("Rename", async (_, _) => await RenameNodeAsync(item)); + MenuFlyoutItem rename = CreateMenuItem("Rename", async (_, _) => await _dialogService.RenameAsync(item)); rename.IsEnabled = item.CanRename; flyout.Items.Add(rename); @@ -1081,7 +1079,7 @@ public sealed class MainWindow : Window hide.IsEnabled = item.CanHide; flyout.Items.Add(hide); flyout.Items.Add(new MenuFlyoutSeparator()); - MenuFlyoutItem penColor = CreateMenuItem("Pen Color...", async (_, _) => await ShowPenColorAsync(item)); + MenuFlyoutItem penColor = CreateMenuItem("Pen Color...", async (_, _) => await _dialogService.ShowPenColorAsync(item)); penColor.IsEnabled = item.Sensor != null; flyout.Items.Add(penColor); MenuFlyoutItem resetPenColor = CreateMenuItem("Reset Pen Color", (_, _) => ViewModel.SetSensorPenColor(item, null)); @@ -1215,264 +1213,6 @@ public sealed class MainWindow : Window return controlItem; } - private async Task RenameNodeAsync(SensorTreeItemViewModel item) - { - if (!item.CanRename) - return; - - TextBox nameTextBox = new() { Text = item.Text, SelectionStart = 0, SelectionLength = item.Text.Length }; - ContentDialog dialog = new() - { - XamlRoot = Content.XamlRoot, - Title = "Rename Sensor", - Content = nameTextBox, - PrimaryButtonText = "Save", - CloseButtonText = "Cancel", - DefaultButton = ContentDialogButton.Primary - }; - - if (await dialog.ShowAsync() == ContentDialogResult.Primary) - item.Text = nameTextBox.Text.Trim(); - } - - private async Task ShowPenColorAsync(SensorTreeItemViewModel item) - { - if (item.Sensor == null) - return; - - ColorPicker picker = new() - { - Color = item.PenColor ?? global::Windows.UI.Color.FromArgb(255, 0, 120, 212), - IsAlphaEnabled = false, - IsColorSliderVisible = true, - IsColorChannelTextInputVisible = true, - IsHexInputVisible = true - }; - - ContentDialog dialog = new() - { - XamlRoot = Content.XamlRoot, - Title = "Pen Color", - Content = picker, - PrimaryButtonText = "Save", - CloseButtonText = "Cancel", - DefaultButton = ContentDialogButton.Primary - }; - - if (await dialog.ShowAsync() == ContentDialogResult.Primary) - ViewModel.SetSensorPenColor(item, picker.Color); - } - - private async Task ShowParametersAsync(SensorTreeItemViewModel item) - { - if (item.Sensor == null || item.Sensor.Parameters.Count == 0) - return; - - StackPanel panel = new() { Spacing = 10 }; - TextBlock caption = new() - { - Text = item.Sensor.Name, - FontWeight = new global::Windows.UI.Text.FontWeight { Weight = 600 }, - TextWrapping = TextWrapping.Wrap - }; - panel.Children.Add(caption); - - ParameterEditorRow[] rows = item.Sensor.Parameters.Select(CreateParameterEditorRow).ToArray(); - foreach (ParameterEditorRow row in rows) - panel.Children.Add(row.Container); - - ContentDialog dialog = new() - { - XamlRoot = Content.XamlRoot, - Title = "Parameters", - Content = new ScrollViewer { Content = panel, MaxHeight = 520 }, - PrimaryButtonText = "OK", - CloseButtonText = "Cancel", - DefaultButton = ContentDialogButton.Primary - }; - dialog.PrimaryButtonClick += (sender, args) => - { - foreach (ParameterEditorRow row in rows) - { - if (row.UseDefault.IsChecked == true) - continue; - - if (!float.TryParse(row.Value.Text, NumberStyles.Float, CultureInfo.CurrentCulture, out float _) - && !float.TryParse(row.Value.Text, NumberStyles.Float, CultureInfo.InvariantCulture, out float _)) - { - row.Value.Header = "Invalid value"; - args.Cancel = true; - return; - } - } - - foreach (ParameterEditorRow row in rows) - { - if (row.UseDefault.IsChecked == true) - row.Parameter.IsDefault = true; - else if (float.TryParse(row.Value.Text, NumberStyles.Float, CultureInfo.CurrentCulture, out float currentCultureValue) - || float.TryParse(row.Value.Text, NumberStyles.Float, CultureInfo.InvariantCulture, out currentCultureValue)) - row.Parameter.Value = currentCultureValue; - } - }; - - await dialog.ShowAsync(); - } - - private static ParameterEditorRow CreateParameterEditorRow(IParameter parameter) - { - Grid grid = new() - { - ColumnDefinitions = - { - new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }, - new ColumnDefinition { Width = GridLength.Auto }, - new ColumnDefinition { Width = new GridLength(120) } - }, - RowDefinitions = - { - new RowDefinition { Height = GridLength.Auto }, - new RowDefinition { Height = GridLength.Auto } - }, - ColumnSpacing = 8 - }; - - TextBlock name = new() - { - Text = parameter.Name, - VerticalAlignment = VerticalAlignment.Center, - TextWrapping = TextWrapping.Wrap - }; - grid.Children.Add(name); - - CheckBox useDefault = new() - { - Content = "Default", - IsChecked = parameter.IsDefault, - VerticalAlignment = VerticalAlignment.Center - }; - Grid.SetColumn(useDefault, 1); - grid.Children.Add(useDefault); - - TextBox value = new() - { - Text = parameter.Value.ToString(CultureInfo.CurrentCulture), - IsEnabled = !parameter.IsDefault - }; - Grid.SetColumn(value, 2); - grid.Children.Add(value); - - TextBlock description = new() - { - Text = parameter.Description, - Opacity = 0.72, - TextWrapping = TextWrapping.Wrap - }; - Grid.SetRow(description, 1); - Grid.SetColumnSpan(description, 3); - grid.Children.Add(description); - - useDefault.Checked += (_, _) => value.IsEnabled = false; - useDefault.Unchecked += (_, _) => value.IsEnabled = true; - - return new ParameterEditorRow(parameter, grid, useDefault, value); - } - - private async Task ShowWebServerSettingsAsync() - { - ComboBox interfaces = new() { MinWidth = 260 }; - foreach (string address in GetLocalIPv4Addresses()) - interfaces.Items.Add(address); - interfaces.Items.Add("0.0.0.0"); - interfaces.SelectedItem = interfaces.Items.Contains(ViewModel.ListenerIp) ? ViewModel.ListenerIp : "0.0.0.0"; - - TextBox port = new() - { - Header = "Port", - Text = ViewModel.ListenerPort.ToString(CultureInfo.InvariantCulture), - InputScope = new InputScope { Names = { new InputScopeName(InputScopeNameValue.Number) } } - }; - - HyperlinkButton link = new() - { - Content = ViewModel.WebServerUrl, - NavigateUri = new Uri(ViewModel.WebServerUrl) - }; - - StackPanel content = new() { Spacing = 12 }; - content.Children.Add(new TextBlock { Text = "Interface", FontWeight = new global::Windows.UI.Text.FontWeight { Weight = 600 } }); - content.Children.Add(interfaces); - content.Children.Add(port); - content.Children.Add(link); - - ContentDialog dialog = new() - { - XamlRoot = Content.XamlRoot, - Title = "Remote Web Server", - Content = content, - PrimaryButtonText = "Save", - CloseButtonText = "Cancel", - DefaultButton = ContentDialogButton.Primary - }; - - dialog.PrimaryButtonClick += (_, args) => - { - if (!int.TryParse(port.Text, NumberStyles.Integer, CultureInfo.InvariantCulture, out int parsedPort) || parsedPort < 1 || parsedPort > 65535) - { - port.Header = "Port must be 1-65535"; - args.Cancel = true; - return; - } - - ViewModel.ListenerIp = interfaces.SelectedItem as string ?? "0.0.0.0"; - ViewModel.ListenerPort = parsedPort; - }; - - await dialog.ShowAsync(); - } - - private async Task ShowWebServerAuthenticationAsync() - { - CheckBox enabled = new() { Content = "Enable HTTP authentication", IsChecked = ViewModel.AuthWebServer }; - TextBox userName = new() - { - Header = "Username", - Text = ViewModel.AuthWebServerUserName, - IsEnabled = enabled.IsChecked == true - }; - PasswordBox password = new() - { - Header = "New password", - IsEnabled = enabled.IsChecked == true - }; - - enabled.Checked += (_, _) => userName.IsEnabled = password.IsEnabled = true; - enabled.Unchecked += (_, _) => userName.IsEnabled = password.IsEnabled = false; - - StackPanel content = new() { Spacing = 12 }; - content.Children.Add(enabled); - content.Children.Add(userName); - content.Children.Add(password); - - ContentDialog dialog = new() - { - XamlRoot = Content.XamlRoot, - Title = "Remote Web Server Authentication", - Content = content, - PrimaryButtonText = "Save", - CloseButtonText = "Cancel", - DefaultButton = ContentDialogButton.Primary - }; - dialog.PrimaryButtonClick += (_, _) => - { - ViewModel.AuthWebServer = enabled.IsChecked == true; - ViewModel.AuthWebServerUserName = userName.Text; - ViewModel.SetAuthPassword(password.Password); - }; - - await dialog.ShowAsync(); - } - private void SensorTree_SelectionChanged(TreeView sender, TreeViewSelectionChangedEventArgs args) { if (args.AddedItems.Count == 0) @@ -1486,65 +1226,6 @@ public sealed class MainWindow : Window ViewModel.SelectedItem = element.DataContext as SensorTreeItemViewModel; } - private async Task SaveReportAsync() - { - FileSavePicker picker = new() - { - SuggestedFileName = "LibreHardwareMonitor.Report", - SuggestedStartLocation = PickerLocationId.DocumentsLibrary - }; - picker.FileTypeChoices.Add("Text", [".txt"]); - InitializeWithWindow.Initialize(picker, WindowNative.GetWindowHandle(this)); - - StorageFile? file = await picker.PickSaveFileAsync(); - if (file == null) - return; - - CachedFileManager.DeferUpdates(file); - await FileIO.WriteTextAsync(file, ViewModel.GetReport()); - await CachedFileManager.CompleteUpdatesAsync(file); - } - - private async Task ShowAboutAsync() - { - StackPanel content = new() { Spacing = 8 }; - content.Children.Add(new TextBlock - { - Text = "Libre Hardware Monitor", - FontWeight = new global::Windows.UI.Text.FontWeight { Weight = 600 }, - FontSize = 18 - }); - content.Children.Add(new TextBlock - { - Text = $"Version {typeof(MainWindow).Assembly.GetName().Version}", - TextWrapping = TextWrapping.Wrap - }); - content.Children.Add(new TextBlock - { - Text = "A free, open source hardware monitoring application.", - TextWrapping = TextWrapping.Wrap - }); - content.Children.Add(new HyperlinkButton - { - Content = "Project website", - NavigateUri = new Uri("https://github.com/LibreHardwareMonitor/LibreHardwareMonitor") - }); - content.Children.Add(new HyperlinkButton - { - Content = "Mozilla Public License 2.0", - NavigateUri = new Uri("https://www.mozilla.org/MPL/2.0/") - }); - - ContentDialog dialog = new() - { - XamlRoot = Content.XamlRoot, - Title = "Libre Hardware Monitor", - Content = content, - CloseButtonText = "OK" - }; - await dialog.ShowAsync(); - } - private void ResetPlot() { ViewModel.ResetPlot(); @@ -2286,23 +1967,6 @@ public sealed class MainWindow : Window return item; } - private static string[] GetLocalIPv4Addresses() - { - try - { - return Dns.GetHostEntry(Dns.GetHostName()) - .AddressList - .Where(address => address.AddressFamily == AddressFamily.InterNetwork) - .Select(address => address.ToString()) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToArray(); - } - catch - { - return []; - } - } - private const int ShowWindowHide = 0; private const int ShowWindowShow = 5; private const int ShowWindowMinimize = 6; @@ -2337,8 +2001,6 @@ public sealed class MainWindow : Window private sealed record PlotSeriesSample(PlotSeriesViewModel Series, IReadOnlyList Points); - private sealed record ParameterEditorRow(IParameter Parameter, Grid Container, CheckBox UseDefault, TextBox Value); - private static void Bind(DependencyObject target, DependencyProperty property, object source, string path, BindingMode mode = BindingMode.OneWay) { BindingOperations.SetBinding(target, property, new Binding