735 lines
28 KiB
C#
735 lines
28 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Documents;
|
|
using System.Windows.Input;
|
|
using System.Windows.Media;
|
|
using System.Windows.Media.Imaging;
|
|
using Kniip.Capture;
|
|
using Kniip.Editor;
|
|
using Kniip.Infrastructure;
|
|
using Kniip.Update;
|
|
using Kniip.Upload;
|
|
|
|
namespace Kniip.Settings;
|
|
|
|
public partial class SettingsWindow : Window
|
|
{
|
|
private const string HotkeyHintText =
|
|
"kniip vangt deze toetsen in alle programma's af; bij Print Screen opent het Windows-knipprogramma dan niet óók.";
|
|
|
|
private static readonly Dictionary<string, string> HotkeyNames = new()
|
|
{
|
|
["Snip"] = "rechthoek knippen",
|
|
["Window"] = "venster knippen",
|
|
["Record"] = "screencast (MP4)",
|
|
["Gif"] = "screencast (GIF)",
|
|
["Clipboard"] = "bewerken vanaf klembord",
|
|
};
|
|
|
|
private readonly AppSettings _settings;
|
|
private readonly Dictionary<string, string> _hotkeys;
|
|
private readonly Dictionary<string, Button> _hotkeyButtons;
|
|
private string? _listeningFor;
|
|
private string? _snipFolder;
|
|
private string? _videoFolder;
|
|
private UploaderConfig? _uploader;
|
|
private bool _resetEditor;
|
|
private bool _updateChecked;
|
|
private ReleaseInfo? _update;
|
|
private System.Threading.CancellationTokenSource? _updateCts;
|
|
|
|
public SettingsWindow(AppSettings settings)
|
|
{
|
|
InitializeComponent();
|
|
ThemeManager.Attach(this);
|
|
_settings = settings;
|
|
Title = $"{AppIdentity.DisplayName} instellingen";
|
|
|
|
FolderText.Text = CaptureCoordinator.ScreenshotsFolder ?? "Map Schermafbeeldingen niet gevonden.";
|
|
AutostartBox.IsChecked = ShellIntegration.IsAutostartEnabled();
|
|
OpenWithBox.IsChecked = ShellIntegration.IsOpenWithRegistered();
|
|
|
|
WatchClipboardBox.Checked += (_, _) => OnlySnippingToolBox.IsEnabled = true;
|
|
WatchClipboardBox.Unchecked += (_, _) => OnlySnippingToolBox.IsEnabled = false;
|
|
|
|
_uploader = settings.Uploader;
|
|
ShowUploader();
|
|
|
|
_hotkeys = new Dictionary<string, string>();
|
|
_hotkeyButtons = new Dictionary<string, Button>
|
|
{
|
|
["Snip"] = SnipHotkeyButton,
|
|
["Window"] = WindowHotkeyButton,
|
|
["Record"] = RecordHotkeyButton,
|
|
["Gif"] = GifHotkeyButton,
|
|
["Clipboard"] = ClipboardHotkeyButton,
|
|
};
|
|
|
|
HotkeyHint.Text = App.Instance.HotkeyHook?.IsActive == true
|
|
? HotkeyHintText
|
|
: "De toetsenbordhaak kon niet worden gestart; de sneltoetsen werken nu niet.";
|
|
Deactivated += (_, _) => StopListening();
|
|
App.Instance.Updates.AvailabilityChanged += OnUpdateAvailabilityChanged;
|
|
Closed += (_, _) =>
|
|
{
|
|
StopListening();
|
|
_updateCts?.Cancel();
|
|
App.Instance.Updates.AvailabilityChanged -= OnUpdateAvailabilityChanged;
|
|
};
|
|
ShowUpdateBadge();
|
|
|
|
CurrentVersionText.Text = $"Geïnstalleerde versie: {UpdateChecker.CurrentVersion}";
|
|
LoadFrom(settings);
|
|
|
|
MaxHeight = SystemParameters.WorkArea.Height;
|
|
}
|
|
|
|
/// <summary>Vult het formulier; de uploader en de Windows-integratie blijven ongemoeid.</summary>
|
|
private void LoadFrom(AppSettings settings)
|
|
{
|
|
WatchClipboardBox.IsChecked = settings.WatchClipboard;
|
|
OnlySnippingToolBox.IsChecked = settings.OnlyFromSnippingTool;
|
|
OnlySnippingToolBox.IsEnabled = settings.WatchClipboard;
|
|
WatchFolderBox.IsChecked = settings.WatchScreenshotsFolder;
|
|
ActionNotifyRadio.IsChecked = settings.Action == CaptureAction.Notify;
|
|
ActionOpenRadio.IsChecked = settings.Action == CaptureAction.OpenEditor;
|
|
ActionNothingRadio.IsChecked = settings.Action == CaptureAction.Nothing;
|
|
StraightHighlightBox.IsChecked = settings.StraightHighlight;
|
|
ColorModeLightRadio.IsChecked = settings.ColorMode == ColorMode.Light;
|
|
ColorModeDarkRadio.IsChecked = settings.ColorMode == ColorMode.Dark;
|
|
ColorModeSystemRadio.IsChecked = settings.ColorMode == ColorMode.System;
|
|
LayoutSplitRadio.IsChecked = settings.EditorLayout == EditorLayout.Split;
|
|
LayoutThreeSplitRadio.IsChecked = settings.EditorLayout == EditorLayout.ThreeSplit;
|
|
LayoutSingleRadio.IsChecked = settings.EditorLayout == EditorLayout.Single;
|
|
bool docked = !settings.CaptureBarFloating;
|
|
CaptureBarLeftRadio.IsChecked = docked && settings.CaptureBarPosition == Dock.Left;
|
|
CaptureBarRightRadio.IsChecked = docked && settings.CaptureBarPosition == Dock.Right;
|
|
CaptureBarTopRadio.IsChecked = docked && settings.CaptureBarPosition == Dock.Top;
|
|
CaptureBarBottomRadio.IsChecked = docked && settings.CaptureBarPosition == Dock.Bottom;
|
|
CaptureBarFloatRadio.IsChecked = settings.CaptureBarFloating;
|
|
AutoUpdateCheckBox.IsChecked = settings.CheckForUpdates;
|
|
MagnifierBox.IsChecked = settings.ShowMagnifier;
|
|
|
|
_snipFolder = settings.SnipSaveFolder;
|
|
_videoFolder = settings.VideoSaveFolder;
|
|
ShowSaveFolders();
|
|
SnipTemplateBox.Text = settings.SnipFileNameTemplate ?? string.Empty;
|
|
VideoTemplateBox.Text = settings.VideoFileNameTemplate ?? string.Empty;
|
|
ShowTemplatePreviews();
|
|
SaveAndCopyRadio.IsChecked = settings.SaveButton == SaveButtonChoice.SaveAndCopy;
|
|
SaveOnlyRadio.IsChecked = settings.SaveButton != SaveButtonChoice.SaveAndCopy;
|
|
|
|
_hotkeys["Snip"] = settings.SnipHotkey;
|
|
_hotkeys["Window"] = settings.WindowHotkey;
|
|
_hotkeys["Record"] = settings.RecordHotkey;
|
|
_hotkeys["Gif"] = settings.GifHotkey;
|
|
_hotkeys["Clipboard"] = settings.ClipboardHotkey;
|
|
foreach (string id in _hotkeys.Keys)
|
|
{
|
|
ShowHotkey(id);
|
|
}
|
|
|
|
SystemAudioBox.IsChecked = settings.RecordSystemAudio;
|
|
MicrophoneBox.IsChecked = settings.RecordMicrophone;
|
|
ShowCursorBox.IsChecked = settings.RecordShowCursor;
|
|
HighlightClicksBox.IsChecked = settings.RecordHighlightClicks;
|
|
FillChoices(VideoFpsCombo, new[] { 15, 30, 60 }, settings.RecordFps, fps => $"{fps} beelden/s");
|
|
FillChoices(GifFpsCombo, new[] { 5, 10, 15, 20, 25 }, settings.GifFps, fps => $"{fps} beelden/s");
|
|
FillChoices(GifWidthCombo, new[] { 0, 1920, 1280, 960, 800, 640, 480 }, settings.GifMaxWidth,
|
|
width => width == 0 ? "Originele breedte" : $"max. {width} px breed");
|
|
}
|
|
|
|
private void ResetDefaults_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
StopListening();
|
|
LoadFrom(new AppSettings());
|
|
_resetEditor = true;
|
|
ResetStatus.Visibility = Visibility.Visible;
|
|
}
|
|
|
|
private static void FillChoices(ComboBox combo, int[] values, int current, Func<int, string> label)
|
|
{
|
|
combo.Items.Clear();
|
|
foreach (int value in values.Contains(current) ? values : values.Append(current).ToArray())
|
|
{
|
|
var item = new ComboBoxItem { Content = label(value), Tag = value };
|
|
combo.Items.Add(item);
|
|
if (value == current)
|
|
{
|
|
combo.SelectedItem = item;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static int SelectedValue(ComboBox combo, int fallback) =>
|
|
combo.SelectedItem is ComboBoxItem { Tag: int value } ? value : fallback;
|
|
|
|
private void ShowHotkey(string id) =>
|
|
_hotkeyButtons[id].Content = HotkeyGesture.TryParse(_hotkeys[id], out HotkeyGesture gesture) ? gesture.DisplayText : "(geen)";
|
|
|
|
private void HotkeyButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
GlobalHotkeyHook? hook = App.Instance.HotkeyHook;
|
|
if (hook is not { IsActive: true } || sender is not FrameworkElement { Tag: string id })
|
|
{
|
|
return;
|
|
}
|
|
|
|
StopListening();
|
|
// Via de haak, niet via WPF: Print Screen komt nooit als KeyDown bij een venster aan.
|
|
_listeningFor = id;
|
|
hook.Capture = OnHotkeyPressed;
|
|
_hotkeyButtons[id].Content = "Druk op een toets...";
|
|
HotkeyHint.Text = "Esc = annuleren · Delete = geen sneltoets";
|
|
}
|
|
|
|
private void OnHotkeyPressed(HotkeyGesture pressed)
|
|
{
|
|
if (_listeningFor is not string id)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (pressed.Modifiers == ModifierKeys.None && pressed.Key == Key.Escape)
|
|
{
|
|
StopListening();
|
|
return;
|
|
}
|
|
|
|
if (pressed.Modifiers == ModifierKeys.None && pressed.Key is Key.Delete or Key.Back)
|
|
{
|
|
_hotkeys[id] = string.Empty;
|
|
StopListening();
|
|
return;
|
|
}
|
|
|
|
if (!pressed.IsAllowed)
|
|
{
|
|
HotkeyHint.Text = $"{pressed.DisplayText} gebruik je om te typen. Kies Print Screen, Pause, een F-toets of een combinatie met Ctrl, Alt of Win.";
|
|
return;
|
|
}
|
|
|
|
foreach ((string other, string hotkey) in _hotkeys)
|
|
{
|
|
if (other != id && HotkeyGesture.TryParse(hotkey, out HotkeyGesture taken) && taken == pressed)
|
|
{
|
|
HotkeyHint.Text = $"{pressed.DisplayText} is al de sneltoets voor {HotkeyNames[other]}; kies een andere.";
|
|
return;
|
|
}
|
|
}
|
|
|
|
_hotkeys[id] = pressed.ToString();
|
|
StopListening();
|
|
}
|
|
|
|
private void StopListening()
|
|
{
|
|
if (_listeningFor is not string id)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_listeningFor = null;
|
|
if (App.Instance.HotkeyHook is { } hook)
|
|
{
|
|
hook.Capture = null;
|
|
}
|
|
|
|
ShowHotkey(id);
|
|
HotkeyHint.Text = HotkeyHintText;
|
|
}
|
|
|
|
private void ClearHotkey_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (sender is not FrameworkElement { Tag: string id })
|
|
{
|
|
return;
|
|
}
|
|
|
|
StopListening();
|
|
_hotkeys[id] = string.Empty;
|
|
ShowHotkey(id);
|
|
}
|
|
|
|
private void ShowSaveFolders()
|
|
{
|
|
ShowSaveFolder(SnipFolderText, _snipFolder);
|
|
ShowSaveFolder(VideoFolderText, _videoFolder);
|
|
}
|
|
|
|
private static void ShowSaveFolder(TextBlock text, string? folder)
|
|
{
|
|
text.Text = string.IsNullOrEmpty(folder) ? "Elke keer vragen" : folder;
|
|
text.ToolTip = folder;
|
|
text.SetResourceReference(TextBlock.ForegroundProperty, string.IsNullOrEmpty(folder) ? "SubtleTextBrush" : "InkBrush");
|
|
}
|
|
|
|
private void Template_TextChanged(object sender, TextChangedEventArgs e) => ShowTemplatePreviews();
|
|
|
|
private void ShowTemplatePreviews()
|
|
{
|
|
TemplateHelp.Text = FileNameTemplate.Help;
|
|
SnipTemplatePreview.Text = "Voorbeeld: " + FileNameTemplate.Preview(NullIfBlank(SnipTemplateBox.Text), "Cursor",
|
|
$"Knipsel {DateTime.Now:yyyy-MM-dd HHmmss}", ".png");
|
|
VideoTemplatePreview.Text = "Voorbeeld: " + FileNameTemplate.Preview(NullIfBlank(VideoTemplateBox.Text), "Cursor",
|
|
$"Screencast {DateTime.Now:yyyy-MM-dd HHmmss}", ".mp4");
|
|
}
|
|
|
|
private static string? NullIfBlank(string text) => string.IsNullOrWhiteSpace(text) ? null : text.Trim();
|
|
|
|
private void BrowseSaveFolder_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
bool snip = sender is FrameworkElement { Tag: "Snip" };
|
|
string? current = snip ? _snipFolder : _videoFolder;
|
|
var dialog = new Microsoft.Win32.OpenFolderDialog
|
|
{
|
|
Title = snip ? "Map voor knipsels kiezen" : "Map voor screencasts kiezen",
|
|
InitialDirectory = current is { Length: > 0 } && System.IO.Directory.Exists(current)
|
|
? current
|
|
: Environment.GetFolderPath(snip ? Environment.SpecialFolder.MyPictures : Environment.SpecialFolder.MyVideos)
|
|
};
|
|
if (dialog.ShowDialog(this) != true)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (snip)
|
|
{
|
|
_snipFolder = dialog.FolderName;
|
|
}
|
|
else
|
|
{
|
|
_videoFolder = dialog.FolderName;
|
|
}
|
|
|
|
ShowSaveFolders();
|
|
}
|
|
|
|
private void ClearSaveFolder_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (sender is FrameworkElement { Tag: "Snip" })
|
|
{
|
|
_snipFolder = null;
|
|
}
|
|
else
|
|
{
|
|
_videoFolder = null;
|
|
}
|
|
|
|
ShowSaveFolders();
|
|
}
|
|
|
|
private void ShowUploader()
|
|
{
|
|
bool configured = _uploader is { IsConfigured: true };
|
|
UploaderText.Text = configured ? _uploader!.DisplayName : "Niet ingesteld";
|
|
UploaderText.ToolTip = configured ? _uploader!.RequestUrl : null;
|
|
UploaderText.SetResourceReference(TextBlock.ForegroundProperty, configured ? "InkBrush" : "SubtleTextBrush");
|
|
TestUploaderButton.IsEnabled = configured;
|
|
RemoveUploaderButton.IsEnabled = configured;
|
|
}
|
|
|
|
private void ShowUploaderStatus(string? message, string? url = null, string? suffix = null)
|
|
{
|
|
UploaderStatus.Inlines.Clear();
|
|
UploaderStatus.Inlines.Add(new Run(message ?? string.Empty));
|
|
if (url != null)
|
|
{
|
|
var link = new Hyperlink(new Run(url)) { ToolTip = "Openen in de browser" };
|
|
link.Click += (_, _) => OpenUrl(url);
|
|
UploaderStatus.Inlines.Add(link);
|
|
UploaderStatus.Inlines.Add(new Run(suffix ?? string.Empty));
|
|
}
|
|
|
|
UploaderStatus.Visibility = string.IsNullOrEmpty(message) && url == null ? Visibility.Collapsed : Visibility.Visible;
|
|
}
|
|
|
|
private static void OpenUrl(string url)
|
|
{
|
|
try
|
|
{
|
|
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(url) { UseShellExecute = true });
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// De link staat ook op het klembord.
|
|
}
|
|
}
|
|
|
|
private void ImportUploader_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
var dialog = new Microsoft.Win32.OpenFileDialog
|
|
{
|
|
Title = "Zipline-uploader importeren",
|
|
Filter = "Zipline-uploader (*.sxcu;*.sh)|*.sxcu;*.sh|ShareX-uploader (*.sxcu)|*.sxcu|Shell script (*.sh)|*.sh|Alle bestanden (*.*)|*.*",
|
|
InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) is { } home
|
|
&& System.IO.Directory.Exists(System.IO.Path.Combine(home, "Downloads"))
|
|
? System.IO.Path.Combine(home, "Downloads")
|
|
: string.Empty
|
|
};
|
|
if (dialog.ShowDialog(this) != true)
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
_uploader = UploaderImporter.FromFile(dialog.FileName);
|
|
ShowUploader();
|
|
ShowUploaderStatus($"Geïmporteerd: {_uploader.Name}. Klik op Opslaan om dit te bewaren.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show(this, $"Dit bestand kan niet worden gebruikt:\n{dialog.FileName}\n\n{ex.Message}", "kniip",
|
|
MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
}
|
|
}
|
|
|
|
private async void TestUploader_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (_uploader is not { IsConfigured: true } config)
|
|
{
|
|
return;
|
|
}
|
|
|
|
TestUploaderButton.IsEnabled = false;
|
|
ShowUploaderStatus("Testplaatje uploaden...");
|
|
try
|
|
{
|
|
using System.IO.MemoryStream png = ImageExporter.EncodePng(CreateTestImage());
|
|
string url = await ZiplineUploader.UploadAsync(config, png, "kniip-test.png", "image/png");
|
|
bool copied = ClipboardWriter.SetText(url);
|
|
ShowUploaderStatus("Gelukt: ", url, copied ? " (gekopieerd)" : null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ShowUploaderStatus(null);
|
|
MessageBox.Show(this, $"De test-upload is mislukt.\n\n{ex.Message}", "kniip", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
}
|
|
finally
|
|
{
|
|
TestUploaderButton.IsEnabled = _uploader is { IsConfigured: true };
|
|
}
|
|
}
|
|
|
|
private static BitmapSource CreateTestImage()
|
|
{
|
|
const int size = 64;
|
|
Color accent = Application.Current.Resources["AccentBrush"] is SolidColorBrush brush ? brush.Color : Colors.SteelBlue;
|
|
var pixels = new byte[size * size * 4];
|
|
for (int i = 0; i < pixels.Length; i += 4)
|
|
{
|
|
pixels[i] = accent.B;
|
|
pixels[i + 1] = accent.G;
|
|
pixels[i + 2] = accent.R;
|
|
pixels[i + 3] = 255;
|
|
}
|
|
|
|
return BitmapSource.Create(size, size, 96, 96, PixelFormats.Bgra32, null, pixels, size * 4);
|
|
}
|
|
|
|
private void RemoveUploader_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
_uploader = null;
|
|
ShowUploader();
|
|
ShowUploaderStatus(null);
|
|
}
|
|
|
|
private void Save_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
_settings.Uploader = _uploader;
|
|
_settings.SnipSaveFolder = _snipFolder;
|
|
_settings.VideoSaveFolder = _videoFolder;
|
|
_settings.SnipFileNameTemplate = NullIfBlank(SnipTemplateBox.Text);
|
|
_settings.VideoFileNameTemplate = NullIfBlank(VideoTemplateBox.Text);
|
|
_settings.SaveButton = SaveAndCopyRadio.IsChecked == true
|
|
? SaveButtonChoice.SaveAndCopy
|
|
: SaveButtonChoice.SaveOnly;
|
|
_settings.WatchClipboard = WatchClipboardBox.IsChecked == true;
|
|
_settings.OnlyFromSnippingTool = OnlySnippingToolBox.IsChecked == true;
|
|
_settings.WatchScreenshotsFolder = WatchFolderBox.IsChecked == true;
|
|
_settings.Action = ActionOpenRadio.IsChecked == true ? CaptureAction.OpenEditor
|
|
: ActionNothingRadio.IsChecked == true ? CaptureAction.Nothing
|
|
: CaptureAction.Notify;
|
|
_settings.StraightHighlight = StraightHighlightBox.IsChecked == true;
|
|
_settings.ColorMode = ColorModeDarkRadio.IsChecked == true ? ColorMode.Dark
|
|
: ColorModeSystemRadio.IsChecked == true ? ColorMode.System
|
|
: ColorMode.Light;
|
|
_settings.EditorLayout = LayoutSplitRadio.IsChecked == true ? EditorLayout.Split
|
|
: LayoutThreeSplitRadio.IsChecked == true ? EditorLayout.ThreeSplit
|
|
: EditorLayout.Single;
|
|
_settings.CaptureBarFloating = CaptureBarFloatRadio.IsChecked == true;
|
|
if (!_settings.CaptureBarFloating)
|
|
{
|
|
_settings.CaptureBarPosition = CaptureBarRightRadio.IsChecked == true ? Dock.Right
|
|
: CaptureBarTopRadio.IsChecked == true ? Dock.Top
|
|
: CaptureBarBottomRadio.IsChecked == true ? Dock.Bottom
|
|
: Dock.Left;
|
|
}
|
|
_settings.CheckForUpdates = AutoUpdateCheckBox.IsChecked == true;
|
|
_settings.ShowMagnifier = MagnifierBox.IsChecked == true;
|
|
StopListening();
|
|
_settings.SnipHotkey = _hotkeys["Snip"];
|
|
_settings.WindowHotkey = _hotkeys["Window"];
|
|
_settings.RecordHotkey = _hotkeys["Record"];
|
|
_settings.GifHotkey = _hotkeys["Gif"];
|
|
_settings.ClipboardHotkey = _hotkeys["Clipboard"];
|
|
_settings.RecordSystemAudio = SystemAudioBox.IsChecked == true;
|
|
_settings.RecordMicrophone = MicrophoneBox.IsChecked == true;
|
|
_settings.RecordShowCursor = ShowCursorBox.IsChecked == true;
|
|
_settings.RecordHighlightClicks = HighlightClicksBox.IsChecked == true;
|
|
_settings.RecordFps = SelectedValue(VideoFpsCombo, 30);
|
|
_settings.GifFps = SelectedValue(GifFpsCombo, 10);
|
|
_settings.GifMaxWidth = SelectedValue(GifWidthCombo, 800);
|
|
|
|
if (_resetEditor)
|
|
{
|
|
var defaults = new AppSettings();
|
|
_settings.ToolStyles = defaults.ToolStyles;
|
|
_settings.LastTool = defaults.LastTool;
|
|
_settings.LastSaveFolder = defaults.LastSaveFolder;
|
|
_settings.LastVideoFolder = defaults.LastVideoFolder;
|
|
_settings.ToolbarPosition = defaults.ToolbarPosition;
|
|
_settings.ToolbarLocked = defaults.ToolbarLocked;
|
|
_settings.ToolbarOrder = defaults.ToolbarOrder;
|
|
_settings.SplitToolbarOrder = defaults.SplitToolbarOrder;
|
|
_settings.ToolbarHidden = defaults.ToolbarHidden;
|
|
}
|
|
|
|
try
|
|
{
|
|
ShellIntegration.SetAutostart(AutostartBox.IsChecked == true);
|
|
|
|
bool openWith = OpenWithBox.IsChecked == true;
|
|
if (openWith && !ShellIntegration.IsOpenWithRegistered())
|
|
{
|
|
ShellIntegration.RegisterOpenWith();
|
|
}
|
|
else if (!openWith && ShellIntegration.IsOpenWithRegistered())
|
|
{
|
|
ShellIntegration.UnregisterOpenWith();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show(this, $"Windows-integratie kon niet worden bijgewerkt:\n\n{ex.Message}", "kniip",
|
|
MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
}
|
|
|
|
App.Instance.SaveSettings();
|
|
Close();
|
|
}
|
|
|
|
private void Cancel_Click(object sender, RoutedEventArgs e) => Close();
|
|
|
|
private void Tabs_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
{
|
|
// ComboBox-keuzes bubbelen dezelfde gebeurtenis; alleen een echt tabblad telt.
|
|
if (e.OriginalSource is TabControl)
|
|
{
|
|
StopListening();
|
|
if (UpdateTab.IsSelected && !_updateChecked)
|
|
{
|
|
_ = CheckForUpdatesAsync();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CheckUpdate_Click(object sender, RoutedEventArgs e) => _ = CheckForUpdatesAsync();
|
|
|
|
private void OnUpdateAvailabilityChanged(object? sender, EventArgs e) => ShowUpdateBadge();
|
|
|
|
private void ShowUpdateBadge() =>
|
|
UpdateTabBadge.Visibility = App.Instance.Updates.IsUpdateAvailable ? Visibility.Visible : Visibility.Collapsed;
|
|
|
|
private void ReleasePage_Click(object sender, RoutedEventArgs e) => OpenUrl(UpdateChecker.ReleasesPage);
|
|
|
|
private async System.Threading.Tasks.Task CheckForUpdatesAsync()
|
|
{
|
|
_updateChecked = true;
|
|
_updateCts?.Cancel();
|
|
var cts = new System.Threading.CancellationTokenSource();
|
|
_updateCts = cts;
|
|
|
|
_update = null;
|
|
UpdateButton.Visibility = Visibility.Collapsed;
|
|
CheckUpdateButton.IsEnabled = false;
|
|
UpdateStatus.Text = "Controleren op updates...";
|
|
try
|
|
{
|
|
IReadOnlyList<ReleaseInfo> releases = await UpdateChecker.GetReleasesAsync(cts.Token);
|
|
ShowReleases(releases);
|
|
}
|
|
catch (UpdateException ex)
|
|
{
|
|
UpdateStatus.Text = ex.Message;
|
|
ShowChangelog(Array.Empty<ReleaseInfo>(), "Geen changelog beschikbaar.");
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
return;
|
|
}
|
|
finally
|
|
{
|
|
if (_updateCts == cts)
|
|
{
|
|
_updateCts = null;
|
|
CheckUpdateButton.IsEnabled = true;
|
|
}
|
|
|
|
cts.Dispose();
|
|
}
|
|
}
|
|
|
|
private void ShowReleases(IReadOnlyList<ReleaseInfo> releases)
|
|
{
|
|
Version current = UpdateChecker.CurrentVersion;
|
|
List<ReleaseInfo> newer = releases.Where(r => r.Version > current).ToList();
|
|
App.Instance.Updates.Report(newer.FirstOrDefault());
|
|
if (newer.Count == 0)
|
|
{
|
|
UpdateStatus.Text = releases.Count == 0
|
|
? "Er zijn nog geen releases gepubliceerd."
|
|
: $"Je gebruikt de nieuwste versie ({current}).";
|
|
ReleaseInfo? notes = releases.FirstOrDefault(r => r.Version == current) ?? releases.FirstOrDefault();
|
|
ShowChangelog(notes == null ? Array.Empty<ReleaseInfo>() : new[] { notes }, "Geen changelog beschikbaar.");
|
|
return;
|
|
}
|
|
|
|
if (AppIdentity.IsTest)
|
|
{
|
|
UpdateStatus.Text = $"Versie {newer[0].Version} is beschikbaar. Deze testversie werkt zichzelf niet bij; " +
|
|
"de installer zou de gewone kniip overschrijven.";
|
|
ShowChangelog(newer, null);
|
|
return;
|
|
}
|
|
|
|
_update = newer.FirstOrDefault(r => r.InstallerUrl != null);
|
|
if (_update != null)
|
|
{
|
|
UpdateStatus.Text = $"Versie {_update.Version} is beschikbaar.";
|
|
UpdateButton.Content = $"Updaten naar {_update.Version}";
|
|
UpdateButton.Visibility = Visibility.Visible;
|
|
}
|
|
else
|
|
{
|
|
UpdateStatus.Text = $"Versie {newer[0].Version} is beschikbaar, maar zonder installer. Download die via de releasepagina.";
|
|
}
|
|
|
|
ShowChangelog(newer, null);
|
|
}
|
|
|
|
private void ShowChangelog(IReadOnlyList<ReleaseInfo> releases, string? emptyText)
|
|
{
|
|
FlowDocument document = MarkdownRenderer.CreateDocument();
|
|
var culture = System.Globalization.CultureInfo.GetCultureInfo("nl-NL");
|
|
var baseUri = new Uri(UpdateChecker.RepositoryUrl);
|
|
foreach (ReleaseInfo release in releases)
|
|
{
|
|
Paragraph heading = MarkdownRenderer.Heading($"Versie {release.Version}", 17,
|
|
new Thickness(0, document.Blocks.Count == 0 ? 0 : 14, 0, 0));
|
|
document.Blocks.Add(heading);
|
|
if (release.Date is DateTimeOffset date)
|
|
{
|
|
document.Blocks.Add(new Paragraph(new Run(date.ToLocalTime().ToString("d MMMM yyyy", culture)))
|
|
{
|
|
Foreground = (Brush)Application.Current.Resources["SubtleTextBrush"],
|
|
FontSize = 12,
|
|
Margin = new Thickness(0, 0, 0, 8),
|
|
});
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(release.Body))
|
|
{
|
|
document.Blocks.Add(new Paragraph(new Run("Geen beschrijving."))
|
|
{
|
|
Foreground = (Brush)Application.Current.Resources["SubtleTextBrush"],
|
|
});
|
|
}
|
|
else
|
|
{
|
|
MarkdownRenderer.Append(document, release.Body, baseUri);
|
|
}
|
|
}
|
|
|
|
if (releases.Count == 0 && emptyText != null)
|
|
{
|
|
document.Blocks.Add(new Paragraph(new Run(emptyText))
|
|
{
|
|
Foreground = (Brush)Application.Current.Resources["SubtleTextBrush"],
|
|
});
|
|
}
|
|
|
|
ChangelogViewer.Document = document;
|
|
}
|
|
|
|
private async void Update_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (_update is not { } release)
|
|
{
|
|
return;
|
|
}
|
|
|
|
string installFolder = System.IO.Path.Combine(
|
|
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Programs", "Kniip");
|
|
bool installed = Environment.ProcessPath is { } exe
|
|
&& string.Equals(System.IO.Path.GetDirectoryName(exe), installFolder, StringComparison.OrdinalIgnoreCase);
|
|
string message = $"kniip wordt afgesloten, bijgewerkt naar versie {release.Version} en daarna opnieuw gestart. " +
|
|
"Open editors en screencasts worden eerst gesloten.";
|
|
if (!installed)
|
|
{
|
|
message += $"\n\nDeze kniip is niet via de installer gestart; de nieuwe versie wordt geïnstalleerd in {installFolder}.";
|
|
}
|
|
|
|
if (MessageBox.Show(this, message, "kniip bijwerken", MessageBoxButton.OKCancel, MessageBoxImage.Information) != MessageBoxResult.OK)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var cts = new System.Threading.CancellationTokenSource();
|
|
_updateCts = cts;
|
|
UpdateButton.IsEnabled = false;
|
|
CheckUpdateButton.IsEnabled = false;
|
|
DownloadProgress.Value = 0;
|
|
DownloadProgress.Visibility = Visibility.Visible;
|
|
UpdateStatus.Text = $"Versie {release.Version} downloaden...";
|
|
string path;
|
|
try
|
|
{
|
|
path = await UpdateInstaller.DownloadAsync(release, new Progress<double>(p => DownloadProgress.Value = p), cts.Token);
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
return;
|
|
}
|
|
catch (Exception ex) when (ex is UpdateException or System.IO.IOException or UnauthorizedAccessException)
|
|
{
|
|
UpdateStatus.Text = $"Versie {release.Version} is beschikbaar.";
|
|
MessageBox.Show(this, $"De update kon niet worden gedownload.\n\n{ex.Message}", "kniip",
|
|
MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
return;
|
|
}
|
|
finally
|
|
{
|
|
if (_updateCts == cts)
|
|
{
|
|
_updateCts = null;
|
|
}
|
|
|
|
cts.Dispose();
|
|
if (IsLoaded)
|
|
{
|
|
DownloadProgress.Visibility = Visibility.Collapsed;
|
|
UpdateButton.IsEnabled = true;
|
|
CheckUpdateButton.IsEnabled = true;
|
|
}
|
|
}
|
|
|
|
UpdateStatus.Text = "Installer starten...";
|
|
App.Instance.InstallUpdate(path);
|
|
}
|
|
}
|