Console MessageBox, admin mode

This commit is contained in:
2023-08-28 13:49:54 +02:00
parent bb44ca0308
commit bc865011d3
18 changed files with 313 additions and 88 deletions

View File

@@ -10,6 +10,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using TerminalUI;
using TerminalUI.ConsoleDrivers;
using TerminalUI.Models;
namespace FileTime.ConsoleUI.App;
@@ -138,6 +139,14 @@ public class App : IApplication
Thread.Sleep(10);
}
_consoleDriver.ExitRestrictedMode();
_consoleDriver.Clear();
var size = _consoleDriver.GetWindowSize();
var shutdownText = "Shutting down...";
_consoleDriver.SetCursorPosition(new Position(size.Width / 2 - shutdownText.Length / 2, size.Height / 2));
_consoleDriver.Write(shutdownText);
Task.Run(async () => await _lifecycleService.ExitAsync()).Wait();
}

View File

@@ -51,35 +51,96 @@ public class Dialogs
};
}
private void UpdateReadInputsFocus()
public IView<IRootViewModel> View()
{
foreach (var readInputsChild in _readInputs.Children)
var root = new Grid<IRootViewModel>()
{
if (readInputsChild.DataContext == _inputElementToFocus)
Margin = 5,
ChildInitializer =
{
if (FindFocusable(readInputsChild) is { } focusable)
{
focusable.Focus();
_inputElementToFocus = null;
break;
}
ReadInputs(),
MessageBox()
}
}
};
IFocusable? FindFocusable(IView view)
{
if (view is IFocusable focusable) return focusable;
foreach (var viewVisualChild in view.VisualChildren)
{
if (FindFocusable(viewVisualChild) is { } focusableChild)
return focusableChild;
}
return null;
}
return root;
}
public IView<IRootViewModel> View()
private IView<IRootViewModel> MessageBox()
{
var okButton = new Button<IRootViewModel>
{
Margin = "0 0 5 0",
Content = new TextBlock<IRootViewModel>()
.Setup(t => t.Bind(
t,
dc => dc.DialogService.LastMessageBox.Value.OkText,
t => t.Text)),
}.WithClickHandler(b => b.DataContext?.DialogService.LastMessageBox.Value?.Ok());
var cancelButton =
new Button<IRootViewModel>
{
Margin = "0 0 5 0",
Content = new TextBlock<IRootViewModel>()
.Setup(t => t.Bind(
t,
dc => dc.DialogService.LastMessageBox.Value.CancelText,
t => t.Text)),
}
.Setup(b => b.Bind(
b,
dc => dc.DialogService.LastMessageBox.Value.ShowCancel,
b => b.IsVisible))
.WithClickHandler(b => b.DataContext?.DialogService.LastMessageBox.Value?.Cancel());
var root = new Border<IRootViewModel>
{
Margin = 5,
BorderThickness = 1,
Background = SpecialColor.None,
Content = new Grid<IRootViewModel>
{
RowDefinitionsObject = "Auto Auto",
ChildInitializer =
{
new TextBlock<IRootViewModel>()
.Setup(t => t.Bind(
t,
dc => dc.DialogService.LastMessageBox.Value.Text,
t => t.Text)),
new StackPanel<IRootViewModel>
{
Orientation = Orientation.Horizontal,
Extensions = {new GridPositionExtension(0, 1)},
ChildInitializer =
{
okButton,
cancelButton
}
}
}
}
};
root.Bind(
root,
d => d.DialogService.LastMessageBox.Value != null,
v => v.IsVisible,
fallbackValue: false);
((INotifyPropertyChanged) root).PropertyChanged += (_, e) =>
{
if (e.PropertyName == nameof(IView.IsVisible))
{
okButton.Focus();
}
};
return root;
}
private IView<IRootViewModel> ReadInputs()
{
var root = new Border<IRootViewModel>
{
@@ -88,9 +149,20 @@ public class Dialogs
Background = SpecialColor.None,
Content = new Grid<IRootViewModel>
{
RowDefinitionsObject = "Auto Auto",
ChildInitializer =
{
ReadInputs()
ReadInputsList(),
new ItemsControl<IRootViewModel, IPreviewElement>
{
ItemTemplate = ReadInputPreviewItemTemplate
}
.Setup(i => i.Bind(
i,
dc => dc.DialogService.ReadInput.Value.Previews,
c => c.ItemsSource
))
.WithExtension(new GridPositionExtension(0, 1))
}
}
};
@@ -100,58 +172,9 @@ public class Dialogs
d => d.DialogService.ReadInput.Value != null,
v => v.IsVisible);
((INotifyPropertyChanged) _readInputs).PropertyChanged += (_, e) =>
{
if (e.PropertyName == nameof(ItemsControl<object, object>.Children))
{
_readInputChildHandlerUnSubscriber?.Invoke();
if (_readInputs.Children.Count > 0)
{
UpdateReadInputsFocus();
}
else
{
_inputElementToFocus = null;
}
if (_readInputs.Children is INotifyCollectionChanged notifyCollectionChanged)
{
notifyCollectionChanged.CollectionChanged += NotifyCollectionChangedEventHandler;
_readInputChildHandlerUnSubscriber = () => { notifyCollectionChanged.CollectionChanged -= NotifyCollectionChangedEventHandler; };
}
void NotifyCollectionChangedEventHandler(
object? sender,
NotifyCollectionChangedEventArgs e)
{
UpdateReadInputsFocus();
}
}
};
return root;
}
private IView<IRootViewModel> ReadInputs()
=> new Grid<IRootViewModel>
{
RowDefinitionsObject = "Auto Auto",
ChildInitializer =
{
ReadInputsList(),
new ItemsControl<IRootViewModel, IPreviewElement>
{
ItemTemplate = ReadInputPreviewItemTemplate
}
.Setup(i => i.Bind(
i,
dc => dc.DialogService.ReadInput.Value.Previews,
c => c.ItemsSource
))
.WithExtension(new GridPositionExtension(0, 1))
}
};
private IView<IPreviewElement> ReadInputPreviewItemTemplate()
{
var grid = new Grid<IPreviewElement>
@@ -367,6 +390,64 @@ public class Dialogs
_readInputs = readInputs;
((INotifyPropertyChanged) _readInputs).PropertyChanged += (_, e) =>
{
if (e.PropertyName == nameof(ItemsControl<object, object>.Children))
{
_readInputChildHandlerUnSubscriber?.Invoke();
if (_readInputs.Children.Count > 0)
{
UpdateReadInputsFocus();
}
else
{
_inputElementToFocus = null;
}
if (_readInputs.Children is INotifyCollectionChanged notifyCollectionChanged)
{
notifyCollectionChanged.CollectionChanged += NotifyCollectionChangedEventHandler;
_readInputChildHandlerUnSubscriber = () => { notifyCollectionChanged.CollectionChanged -= NotifyCollectionChangedEventHandler; };
}
void NotifyCollectionChangedEventHandler(
object? sender,
NotifyCollectionChangedEventArgs e)
{
UpdateReadInputsFocus();
}
}
};
return readInputs;
}
private void UpdateReadInputsFocus()
{
foreach (var readInputsChild in _readInputs.Children)
{
if (readInputsChild.DataContext == _inputElementToFocus)
{
if (FindFocusable(readInputsChild) is { } focusable)
{
focusable.Focus();
_inputElementToFocus = null;
break;
}
}
}
IFocusable? FindFocusable(IView view)
{
if (view is IFocusable focusable) return focusable;
foreach (var viewVisualChild in view.VisualChildren)
{
if (FindFocusable(viewVisualChild) is { } focusableChild)
return focusableChild;
}
return null;
}
}
}

View File

@@ -138,12 +138,22 @@ public class MainWindow
{
Margin = "2 0 0 0",
Extensions = {new GridPositionExtension(2, 0)},
Orientation = Orientation.Horizontal,
ChildInitializer =
{
new TextBlock<IRootViewModel>
{
Text = _consoleApplicationConfiguration.Value.AdminModeIcon ??
(_consoleApplicationConfiguration.Value.DisableUtf8 ? "A+ " : "\ud83d\udd11"),
AsciiOnly = false
}.Setup(t => t.Bind(
t,
dc => dc.AdminElevationManager.IsAdminInstanceRunning,
t => t.IsVisible)),
new TextBlock<IRootViewModel>
{
Text = _consoleApplicationConfiguration.Value.ClipboardSingleIcon ??
(_consoleApplicationConfiguration.Value.DisableUtf8 ? "C" : "\ud83d\udccb"),
(_consoleApplicationConfiguration.Value.DisableUtf8 ? "C " : "\ud83d\udccb"),
AsciiOnly = false
}.Setup(t => t.Bind(
t,
@@ -152,7 +162,7 @@ public class MainWindow
new TextBlock<IRootViewModel>
{
Text = _consoleApplicationConfiguration.Value.ClipboardMultipleIcon ??
(_consoleApplicationConfiguration.Value.DisableUtf8 ? "CC" : "\ud83d\udccb+"),
(_consoleApplicationConfiguration.Value.DisableUtf8 ? "CC " : "\ud83d\udccb+"),
AsciiOnly = false
}.Setup(t => t.Bind(
t,

View File

@@ -7,6 +7,7 @@ using FileTime.App.FrequencyNavigation.ViewModels;
using FileTime.ConsoleUI.App.Services;
using FileTime.Core.Interactions;
using FileTime.Core.Models;
using FileTime.Providers.LocalAdmin;
namespace FileTime.ConsoleUI.App;
@@ -20,6 +21,7 @@ public partial class RootViewModel : IRootViewModel
public IFrequencyNavigationViewModel FrequencyNavigation { get; }
public IItemPreviewService ItemPreviewService { get; }
public IClipboardService ClipboardService { get; }
public IAdminElevationManager AdminElevationManager { get; }
public IDialogService DialogService { get; }
public ITimelineViewModel TimelineViewModel { get; }
public IDeclarativeProperty<VolumeSizeInfo?> VolumeSizeInfo { get;}
@@ -34,7 +36,8 @@ public partial class RootViewModel : IRootViewModel
ITimelineViewModel timelineViewModel,
IFrequencyNavigationViewModel frequencyNavigation,
IItemPreviewService itemPreviewService,
IClipboardService clipboardService)
IClipboardService clipboardService,
IAdminElevationManager adminElevationManager)
{
AppState = appState;
PossibleCommands = possibleCommands;
@@ -44,6 +47,7 @@ public partial class RootViewModel : IRootViewModel
FrequencyNavigation = frequencyNavigation;
ItemPreviewService = itemPreviewService;
ClipboardService = clipboardService;
AdminElevationManager = adminElevationManager;
DialogService.ReadInput.PropertyChanged += (o, e) =>
{

View File

@@ -8,21 +8,27 @@ namespace FileTime.ConsoleUI.App.Services;
public class CustomLoggerSink : ILogEventSink
{
private readonly Lazy<IDialogService> _dialogService;
public CustomLoggerSink(IServiceProvider serviceProvider)
{
_dialogService = new Lazy<IDialogService>(() => serviceProvider.GetRequiredService<IDialogService>());
}
public void Emit(LogEvent logEvent)
{
if (logEvent.Level >= LogEventLevel.Error)
if (logEvent.Level >= LogEventLevel.Error
&& logEvent.Properties.TryGetValue("SourceContext", out var sourceContext))
{
var message = logEvent.RenderMessage();
if (logEvent.Exception is not null)
message += $" {logEvent.Exception.Message}";
Debug.WriteLine(message);
_dialogService.Value.ShowToastMessage(message);
var s = sourceContext.ToString();
if (s != "\"Microsoft.AspNetCore.SignalR.Client.HubConnection\"")
{
var message = logEvent.RenderMessage();
if (logEvent.Exception is not null)
message += $" {logEvent.Exception.Message}";
Debug.WriteLine(message);
_dialogService.Value.ShowToastMessage(message);
}
}
}
}