From e04e313fa38ab91e338ec2a95554dd2232c87a30 Mon Sep 17 00:00:00 2001 From: kitbyte Date: Sat, 29 Aug 2026 16:56:36 +0300 Subject: [PATCH] refactor(wpf): decouple the view model from the window and localize its output Introduce IShellView and IFileDialogs so MainWindowVm no longer holds the concrete window or reaches through MainWindow.Instance, and file pickers are injectable. Run Restore off the UI thread like Patch and gate both buttons on IsBusy. Gate the log commands on a non-empty log. Move runtime log messages into the locale dictionaries and add the 14 new keys to all 12 languages. Track the injected locale dictionary so switching language replaces it instead of appending a new one each time. Remove the unused InfoItem control, ToVisibilityInvertedConverter, mw_title and the popup placeholder title. --- WandEnhancer/App.xaml | 1 - .../Converters/BaseBooleanConverter.cs | 24 +- .../Converters/ToVisibilityConverter.cs | 6 - .../Core/Services/LocalizationManager.cs | 33 ++- WandEnhancer/Core/Services/SettingsManager.cs | 6 +- WandEnhancer/Locale/lang.de-DE.xaml | 19 +- WandEnhancer/Locale/lang.en-US.xaml | 19 +- WandEnhancer/Locale/lang.es-ES.xaml | 19 +- WandEnhancer/Locale/lang.fr-FR.xaml | 19 +- WandEnhancer/Locale/lang.it-IT.xaml | 19 +- WandEnhancer/Locale/lang.ja-JP.xaml | 19 +- WandEnhancer/Locale/lang.pl-PL.xaml | 19 +- WandEnhancer/Locale/lang.pt-BR.xaml | 19 +- WandEnhancer/Locale/lang.ru-RU.xaml | 19 +- WandEnhancer/Locale/lang.tr-TR.xaml | 19 +- WandEnhancer/Locale/lang.uk-UA.xaml | 19 +- WandEnhancer/Locale/lang.zh-CN.xaml | 19 +- .../ReactiveUICore/AsyncRelayCommand.cs | 47 ---- WandEnhancer/View/Controls/InfoItem.xaml | 20 -- WandEnhancer/View/Controls/InfoItem.xaml.cs | 42 --- WandEnhancer/View/Controls/PopupHost.xaml | 2 +- WandEnhancer/View/MainWindow/IShellView.cs | 26 ++ WandEnhancer/View/MainWindow/MainWindow.xaml | 5 +- .../View/MainWindow/MainWindow.xaml.cs | 24 +- WandEnhancer/View/MainWindow/MainWindowVm.cs | 239 +++++++++--------- .../View/MainWindow/WindowsFileDialogs.cs | 28 ++ .../View/Popups/PatchVectorsPopup.xaml | 9 +- .../View/Popups/PatchVectorsPopup.xaml.cs | 11 +- .../View/Popups/SettingsPopup.xaml.cs | 2 +- WandEnhancer/WandEnhancer.csproj | 44 ++-- 30 files changed, 467 insertions(+), 330 deletions(-) delete mode 100644 WandEnhancer/ReactiveUICore/AsyncRelayCommand.cs delete mode 100644 WandEnhancer/View/Controls/InfoItem.xaml delete mode 100644 WandEnhancer/View/Controls/InfoItem.xaml.cs create mode 100644 WandEnhancer/View/MainWindow/IShellView.cs create mode 100644 WandEnhancer/View/MainWindow/WindowsFileDialogs.cs diff --git a/WandEnhancer/App.xaml b/WandEnhancer/App.xaml index dafdfba..273e31e 100644 --- a/WandEnhancer/App.xaml +++ b/WandEnhancer/App.xaml @@ -15,7 +15,6 @@ pack://application:,,,/Style/#Inter 18pt 18pt - \ No newline at end of file diff --git a/WandEnhancer/Converters/BaseBooleanConverter.cs b/WandEnhancer/Converters/BaseBooleanConverter.cs index 501878b..6926580 100644 --- a/WandEnhancer/Converters/BaseBooleanConverter.cs +++ b/WandEnhancer/Converters/BaseBooleanConverter.cs @@ -18,29 +18,7 @@ namespace WandEnhancer.Converters public virtual object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - switch (value) - { - case null: - return False; - case bool booleanValue: - return booleanValue ? True : False; - } - - if (!(value is int intValue)) - { - return True; - } - - switch (parameter) - { - case null: - return intValue == 0 ? False : True; - case int param: - return intValue > param ? True : False; - default: - //Because object not null - return True; - } + return value is bool booleanValue && booleanValue ? True : False; } public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) diff --git a/WandEnhancer/Converters/ToVisibilityConverter.cs b/WandEnhancer/Converters/ToVisibilityConverter.cs index 66c7280..282762b 100644 --- a/WandEnhancer/Converters/ToVisibilityConverter.cs +++ b/WandEnhancer/Converters/ToVisibilityConverter.cs @@ -9,10 +9,4 @@ namespace WandEnhancer.Converters { } } - internal sealed class ToVisibilityInvertedConverter : BaseBooleanConverter - { - public ToVisibilityInvertedConverter() : - base(Visibility.Collapsed, Visibility.Visible) - { } - } } \ No newline at end of file diff --git a/WandEnhancer/Core/Services/LocalizationManager.cs b/WandEnhancer/Core/Services/LocalizationManager.cs index 254f125..c4a9b25 100644 --- a/WandEnhancer/Core/Services/LocalizationManager.cs +++ b/WandEnhancer/Core/Services/LocalizationManager.cs @@ -28,6 +28,22 @@ namespace WandEnhancer.Core.Services private static CultureInfo _currentLanguage; private static ResourceDictionary _englishBaseDictionary; + private static ResourceDictionary _activeLocaleDictionary; + + /// + /// Localized string for , falling back to the key itself so a + /// missing entry is visible rather than silently blank. + /// + public static string Get(string key) + { + return Application.Current?.TryFindResource(key) as string ?? key; + } + + /// Localized format string filled with . + public static string Format(string key, params object[] args) + { + return string.Format(Get(key), args); + } public static CultureInfo CurrentLanguage { @@ -104,20 +120,19 @@ namespace WandEnhancer.Core.Services localeDict[entry.Key] = targetDict[entry.Key]; } - // Find and replace the old locale dictionary - var oldDict = Application.Current.Resources.MergedDictionaries - .FirstOrDefault(d => d.Source != null && d.Source.OriginalString.StartsWith("Locale/lang.")); - - if (oldDict != null) + // Track the dictionary we injected: it is built by merging entries, so its Source is + // null and a Source-based lookup never finds it - every switch used to append another. + var merged = Application.Current.Resources.MergedDictionaries; + if (_activeLocaleDictionary != null && merged.Contains(_activeLocaleDictionary)) { - var index = Application.Current.Resources.MergedDictionaries.IndexOf(oldDict); - Application.Current.Resources.MergedDictionaries.Remove(oldDict); - Application.Current.Resources.MergedDictionaries.Insert(index, localeDict); + merged[merged.IndexOf(_activeLocaleDictionary)] = localeDict; } else { - Application.Current.Resources.MergedDictionaries.Add(localeDict); + merged.Add(localeDict); } + + _activeLocaleDictionary = localeDict; if (saveSettings) { diff --git a/WandEnhancer/Core/Services/SettingsManager.cs b/WandEnhancer/Core/Services/SettingsManager.cs index 33a9e73..03d7024 100644 --- a/WandEnhancer/Core/Services/SettingsManager.cs +++ b/WandEnhancer/Core/Services/SettingsManager.cs @@ -27,8 +27,7 @@ namespace WandEnhancer.Core.Services } catch (Exception) { - // Settings loading is non-critical - silently fall back to defaults - // This can fail due to file permissions, corrupted JSON, etc. + // Unreadable or corrupt settings must not block startup; defaults apply. } return null; } @@ -42,8 +41,7 @@ namespace WandEnhancer.Core.Services } catch (Exception) { - // Settings saving is non-critical - silently ignore errors - // This can fail due to file permissions or read-only directories + // A read-only install directory must not break the app; the choice is lost, not fatal. } } } diff --git a/WandEnhancer/Locale/lang.de-DE.xaml b/WandEnhancer/Locale/lang.de-DE.xaml index 6c2a737..b975833 100644 --- a/WandEnhancer/Locale/lang.de-DE.xaml +++ b/WandEnhancer/Locale/lang.de-DE.xaml @@ -7,7 +7,6 @@ - WandEnhancer Ordnerpfad Ordner nicht gefunden Anwenden @@ -35,7 +34,25 @@ Ausgewählte .js-Dateien werden in Wand gepackt und im Renderer geladen. Keine Skripte ausgewählt Starten + Nach Updates automatisch anwenden Was werden wir verbessern? + + WeMod-Verzeichnis unter {0} ({1}) gefunden + WeMod ist bereits gepatcht. Wenn Sie erneut patchen möchten, stellen Sie bitte zuerst das Backup wieder her. + Bereit zum Patchen. + WeMod-Verzeichnis nicht gefunden. + Vorgang nicht möglich. Bitte geben Sie zuerst das Verzeichnis an. + Der ausgewählte Ordner {0} ist kein gültiges WeMod-Verzeichnis. + Fehler beim Wiederherstellen des Backups: {0} + Fehler beim Patchen: {0} + Protokolle in die Zwischenablage kopiert. + Fehler beim Kopieren der Protokolle: {0} + Protokolle nach {0} exportiert. + Fehler beim Exportieren der Protokolle: {0} + {0} konnte nicht in einem Browser geöffnet werden. + Wählen Sie das WeMod-Verzeichnis aus + + diff --git a/WandEnhancer/Locale/lang.en-US.xaml b/WandEnhancer/Locale/lang.en-US.xaml index 9db07b4..216e2b3 100644 --- a/WandEnhancer/Locale/lang.en-US.xaml +++ b/WandEnhancer/Locale/lang.en-US.xaml @@ -7,7 +7,6 @@ - WandEnhancer Folder path Folder not found Enhance @@ -35,7 +34,25 @@ Selected .js files are packed into Wand and loaded in the renderer. No scripts selected Start + Auto-apply after updates What are we gonna enhance? + + WeMod directory found at {0} ({1}) + WeMod already patched. If you want to patch again, please restore the backup first. + Ready for patching. + WeMod directory not found. + Cant be done. Please specify the directory first. + The selected folder {0} is not a valid WeMod directory. + Failed to restore backup: {0} + Failed to patch: {0} + Logs copied to clipboard. + Failed to copy logs: {0} + Logs exported to {0}. + Failed to export logs: {0} + Could not open {0} in a browser. + Select the WeMod directory + + diff --git a/WandEnhancer/Locale/lang.es-ES.xaml b/WandEnhancer/Locale/lang.es-ES.xaml index 5390712..8a8893e 100644 --- a/WandEnhancer/Locale/lang.es-ES.xaml +++ b/WandEnhancer/Locale/lang.es-ES.xaml @@ -7,7 +7,6 @@ - WandEnhancer Ruta de la carpeta Carpeta no encontrada Aplicar @@ -35,7 +34,25 @@ Los archivos .js seleccionados se empaquetan en Wand y se cargan en el renderer. No hay scripts seleccionados Iniciar + Aplicar automáticamente tras actualizar ¿Qué vamos a mejorar? + + Directorio de WeMod encontrado en {0} ({1}) + WeMod ya está parcheado. Si quieres parchear de nuevo, restaura la copia de seguridad primero. + Listo para parchear. + Directorio de WeMod no encontrado. + No se puede realizar. Por favor, especifica el directorio primero. + La carpeta seleccionada {0} no es un directorio de WeMod válido. + Error al restaurar la copia de seguridad: {0} + Error al parchear: {0} + Registros copiados al portapapeles. + Error al copiar los registros: {0} + Registros exportados a {0}. + Error al exportar los registros: {0} + No se pudo abrir {0} en un navegador. + Selecciona el directorio de WeMod + + diff --git a/WandEnhancer/Locale/lang.fr-FR.xaml b/WandEnhancer/Locale/lang.fr-FR.xaml index 9f6f00f..0246c11 100644 --- a/WandEnhancer/Locale/lang.fr-FR.xaml +++ b/WandEnhancer/Locale/lang.fr-FR.xaml @@ -7,7 +7,6 @@ - WandEnhancer Chemin du dossier Dossier non trouvé Appliquer @@ -35,7 +34,25 @@ Les fichiers .js sélectionnés sont intégrés dans Wand et chargés dans le renderer. Aucun script sélectionné Démarrer + Appliquer automatiquement après les mises à jour Qu'allons-nous modifier ? + + Répertoire WeMod trouvé à {0} ({1}) + WeMod est déjà patché. Si vous souhaitez le patcher à nouveau, veuillez d'abord restaurer la sauvegarde. + Prêt pour le patch. + Répertoire WeMod introuvable. + Impossible. Veuillez d'abord spécifier le répertoire. + Le dossier sélectionné {0} n'est pas un répertoire WeMod valide. + Échec de la restauration de la sauvegarde : {0} + Échec du patch : {0} + Journaux copiés dans le presse-papiers. + Échec de la copie des journaux : {0} + Journaux exportés vers {0}. + Échec de l'exportation des journaux : {0} + Impossible d'ouvrir {0} dans un navigateur. + Sélectionnez le répertoire WeMod + + diff --git a/WandEnhancer/Locale/lang.it-IT.xaml b/WandEnhancer/Locale/lang.it-IT.xaml index 2ca0fb4..1a4914d 100644 --- a/WandEnhancer/Locale/lang.it-IT.xaml +++ b/WandEnhancer/Locale/lang.it-IT.xaml @@ -7,7 +7,6 @@ - WandEnhancer Percorso cartella Cartella non trovata Applica @@ -35,7 +34,25 @@ I file .js selezionati vengono inseriti in Wand e caricati nel renderer. Nessuno script selezionato Avvia + Applica automaticamente dopo gli aggiornamenti Cosa modificheremo? + + Directory di WeMod trovata in {0} ({1}) + WeMod è già stato patchato. Se vuoi patchare di nuovo, ripristina prima il backup. + Pronto per il patching. + Directory di WeMod non trovata. + Impossibile procedere. Specifica prima la directory. + La cartella selezionata {0} non è una directory valida di WeMod. + Impossibile ripristinare il backup: {0} + Impossibile eseguire il patch: {0} + Log copiati negli appunti. + Impossibile copiare i log: {0} + Log esportati in {0}. + Impossibile esportare i log: {0} + Impossibile aprire {0} in un browser. + Seleziona la directory di WeMod + + diff --git a/WandEnhancer/Locale/lang.ja-JP.xaml b/WandEnhancer/Locale/lang.ja-JP.xaml index 44e9f49..9088498 100644 --- a/WandEnhancer/Locale/lang.ja-JP.xaml +++ b/WandEnhancer/Locale/lang.ja-JP.xaml @@ -7,7 +7,6 @@ - WandEnhancer フォルダパス フォルダが見つかりません 適用 @@ -35,7 +34,25 @@ 選択した .js ファイルは Wand に組み込まれ、レンダラーで読み込まれます。 スクリプトが選択されていません 開始 + 更新後に自動適用 何を改善しますか? + + WeModディレクトリが {0} ({1}) に見つかりました + WeModは既にパッチが適用されています。もう一度パッチを適用する場合は、まずバックアップを復元してください。 + パッチ適用の準備ができました。 + WeModディレクトリが見つかりません。 + 実行できません。先にディレクトリを指定してください。 + 選択したフォルダ {0} は有効なWeModディレクトリではありません。 + バックアップの復元に失敗しました: {0} + パッチの適用に失敗しました: {0} + ログをクリップボードにコピーしました。 + ログのコピーに失敗しました: {0} + ログを {0} にエクスポートしました。 + ログのエクスポートに失敗しました: {0} + {0} をブラウザで開くことができませんでした。 + WeModディレクトリを選択してください + + diff --git a/WandEnhancer/Locale/lang.pl-PL.xaml b/WandEnhancer/Locale/lang.pl-PL.xaml index 37b1ade..bb77eda 100644 --- a/WandEnhancer/Locale/lang.pl-PL.xaml +++ b/WandEnhancer/Locale/lang.pl-PL.xaml @@ -7,7 +7,6 @@ - WandEnhancer Ścieżka folderu Folder nie znaleziony Zastosuj @@ -35,7 +34,25 @@ Wybrane pliki .js są pakowane do Wand i ładowane w rendererze. Nie wybrano skryptów Rozpocznij + Zastosuj automatycznie po aktualizacji Co będziemy ulepszać? + + Katalog WeMod znaleziony w {0} ({1}) + WeMod został już zaktualizowany. Jeśli chcesz zaktualizować ponownie, najpierw przywróć kopię zapasową. + Gotowy do aktualizacji (patchowania). + Nie znaleziono katalogu WeMod. + Nie można tego zrobić. Proszę najpierw określić katalog. + Wybrany folder {0} nie jest prawidłowym katalogiem WeMod. + Nie udało się przywrócić kopii zapasowej: {0} + Nie udało się zaktualizować: {0} + Logi skopiowane do schowka. + Nie udało się skopiować logów: {0} + Logi wyeksportowane do {0}. + Nie udało się wyeksportować logów: {0} + Nie można otworzyć {0} w przeglądarce. + Wybierz katalog WeMod + + diff --git a/WandEnhancer/Locale/lang.pt-BR.xaml b/WandEnhancer/Locale/lang.pt-BR.xaml index 6f26576..985142a 100644 --- a/WandEnhancer/Locale/lang.pt-BR.xaml +++ b/WandEnhancer/Locale/lang.pt-BR.xaml @@ -7,7 +7,6 @@ - WandEnhancer Caminho da pasta Pasta não encontrada Aplicar @@ -35,7 +34,25 @@ Os arquivos .js selecionados são empacotados no Wand e carregados no renderer. Nenhum script selecionado Iniciar + Aplicar automaticamente após atualizações O que vamos melhorar? + + Diretório do WeMod encontrado em {0} ({1}) + O WeMod já foi modificado. Se quiser modificar novamente, restaure o backup primeiro. + Pronto para modificar. + Diretório do WeMod não encontrado. + Não é possível fazer isso. Por favor, especifique o diretório primeiro. + A pasta selecionada {0} não é um diretório válido do WeMod. + Falha ao restaurar o backup: {0} + Falha ao modificar: {0} + Logs copiados para a área de transferência. + Falha ao copiar logs: {0} + Logs exportados para {0}. + Falha ao exportar logs: {0} + Não foi possível abrir {0} no navegador. + Selecione o diretório do WeMod + + diff --git a/WandEnhancer/Locale/lang.ru-RU.xaml b/WandEnhancer/Locale/lang.ru-RU.xaml index 1c24c50..fa470b5 100644 --- a/WandEnhancer/Locale/lang.ru-RU.xaml +++ b/WandEnhancer/Locale/lang.ru-RU.xaml @@ -7,7 +7,6 @@ - WandEnhancer Путь к папке Папка не найдена Применить @@ -35,7 +34,25 @@ Выбранные .js попадут в Wand и загрузятся в renderer. Скрипты не выбраны Начать + Авто-патч после обновлений Что будем улучшать? + + Директория WeMod найдена в {0} ({1}) + WeMod уже пропатчен. Если вы хотите пропатчить снова, сначала восстановите резервную копию. + Готово к патчингу. + Директория WeMod не найдена. + Невозможно выполнить. Пожалуйста, сначала укажите директорию. + Выбранная папка {0} не является допустимой директорией WeMod. + Не удалось восстановить резервную копию: {0} + Не удалось пропатчить: {0} + Логи скопированы в буфер обмена. + Не удалось скопировать логи: {0} + Логи экспортированы в {0}. + Не удалось экспортировать логи: {0} + Не удалось открыть {0} в браузере. + Выберите директорию WeMod + + diff --git a/WandEnhancer/Locale/lang.tr-TR.xaml b/WandEnhancer/Locale/lang.tr-TR.xaml index 30a4af6..6ebc108 100644 --- a/WandEnhancer/Locale/lang.tr-TR.xaml +++ b/WandEnhancer/Locale/lang.tr-TR.xaml @@ -7,7 +7,6 @@ - WandEnhancer Klasör yolu Klasör bulunamadı Uygula @@ -35,7 +34,25 @@ Seçilen .js dosyaları Wand içine paketlenir ve renderer'da yüklenir. Betik seçilmedi Başlat + Güncellemelerden sonra otomatik uygula Neyi geliştireceğiz? + + WeMod dizini {0} konumunda bulundu ({1}) + WeMod zaten yamanmış. Tekrar yamamak istiyorsanız, lütfen önce yedeği geri yükleyin. + Yama işlemi için hazır. + WeMod dizini bulunamadı. + İşlem yapılamıyor. Lütfen önce dizini belirtin. + Seçilen {0} klasörü geçerli bir WeMod dizini değil. + Yedek geri yüklenemedi: {0} + Yama yapılamadı: {0} + Günlükler panoya kopyalandı. + Günlükler kopyalanamadı: {0} + Günlükler {0} konumuna dışa aktarıldı. + Günlükler dışa aktarılamadı: {0} + {0} bir tarayıcıda açılamadı. + WeMod dizinini seçin + + diff --git a/WandEnhancer/Locale/lang.uk-UA.xaml b/WandEnhancer/Locale/lang.uk-UA.xaml index 47a77b1..6093129 100644 --- a/WandEnhancer/Locale/lang.uk-UA.xaml +++ b/WandEnhancer/Locale/lang.uk-UA.xaml @@ -7,7 +7,6 @@ - WandEnhancer Шлях до папки Папку не знайдено Застосувати @@ -35,7 +34,25 @@ Вибрані файли .js пакуються у Wand і завантажуються в рендерері. Скрипти не вибрано Почати + Автоматично застосовувати після оновлень Що будемо покращувати? + + Директорію WeMod знайдено в {0} ({1}) + WeMod вже пропатчено. Якщо ви хочете пропатчити знову, спершу відновіть резервну копію. + Готово до патчингу. + Директорію WeMod не знайдено. + Не вдається виконати. Будь ласка, спочатку вкажіть директорію. + Вибрана папка {0} не є дійсною директорією WeMod. + Не вдалося відновити резервну копію: {0} + Не вдалося пропатчити: {0} + Логи скопійовано в буфер обміну. + Не вдалося скопіювати логи: {0} + Логи експортовано до {0}. + Не вдалося експортувати логи: {0} + Не вдалося відкрити {0} у браузері. + Виберіть директорію WeMod + + diff --git a/WandEnhancer/Locale/lang.zh-CN.xaml b/WandEnhancer/Locale/lang.zh-CN.xaml index f0624f3..c4130b1 100644 --- a/WandEnhancer/Locale/lang.zh-CN.xaml +++ b/WandEnhancer/Locale/lang.zh-CN.xaml @@ -7,7 +7,6 @@ - WandEnhancer 文件夹路径 未找到文件夹 增强 @@ -35,7 +34,25 @@ 选中的 .js 文件会打包到 Wand 并在渲染器中加载。 未选择脚本 开始 + 更新后自动应用 我们要增强什么? + + 在 {0} ({1}) 找到 WeMod 目录 + WeMod 已经修补过。如果想再次修补,请先恢复备份。 + 准备修补。 + 未找到 WeMod 目录。 + 无法执行。请先指定目录。 + 选择的文件夹 {0} 不是有效的 WeMod 目录。 + 恢复备份失败: {0} + 修补失败: {0} + 日志已复制到剪贴板。 + 复制日志失败: {0} + 日志已导出至 {0}。 + 导出日志失败: {0} + 无法在浏览器中打开 {0}。 + 选择 WeMod 目录 + + diff --git a/WandEnhancer/ReactiveUICore/AsyncRelayCommand.cs b/WandEnhancer/ReactiveUICore/AsyncRelayCommand.cs deleted file mode 100644 index ebe4787..0000000 --- a/WandEnhancer/ReactiveUICore/AsyncRelayCommand.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Input; - -namespace WandEnhancer.ReactiveUICore -{ - public sealed class AsyncRelayCommand : ICommand - { - private readonly Func _execute; - private readonly Func _canExecute; - - private long _isExecuting; - - public AsyncRelayCommand(Func execute, Func canExecute = null) - { - this._execute = execute; - this._canExecute = canExecute ?? (o => true); - } - - public event EventHandler CanExecuteChanged - { - add => CommandManager.RequerySuggested += value; - remove => CommandManager.RequerySuggested -= value; - } - - private static void RaiseCanExecuteChanged() => CommandManager.InvalidateRequerySuggested(); - - public bool CanExecute(object parameter) => Interlocked.Read(ref _isExecuting) == 0 && _canExecute(parameter); - - public async void Execute(object parameter) - { - Interlocked.Exchange(ref _isExecuting, 1); - RaiseCanExecuteChanged(); - - try - { - await _execute(parameter); - } - finally - { - Interlocked.Exchange(ref _isExecuting, 0); - RaiseCanExecuteChanged(); - } - } - } -} \ No newline at end of file diff --git a/WandEnhancer/View/Controls/InfoItem.xaml b/WandEnhancer/View/Controls/InfoItem.xaml deleted file mode 100644 index f67623c..0000000 --- a/WandEnhancer/View/Controls/InfoItem.xaml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - diff --git a/WandEnhancer/View/Controls/InfoItem.xaml.cs b/WandEnhancer/View/Controls/InfoItem.xaml.cs deleted file mode 100644 index 4fba9cd..0000000 --- a/WandEnhancer/View/Controls/InfoItem.xaml.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; - -namespace WandEnhancer.View.Controls -{ - public partial class InfoItem : UserControl - { - public static readonly DependencyProperty IconDataProperty = - DependencyProperty.Register(nameof(IconData), typeof(Geometry), typeof(InfoItem)); - - public static readonly DependencyProperty IconColorProperty = - DependencyProperty.Register(nameof(IconColor), typeof(Brush), typeof(InfoItem)); - - public static readonly DependencyProperty TextProperty = - DependencyProperty.Register(nameof(Text), typeof(string), typeof(InfoItem)); - - public Geometry IconData - { - get => (Geometry)GetValue(IconDataProperty); - set => SetValue(IconDataProperty, value); - } - - public Brush IconColor - { - get => (Brush)GetValue(IconColorProperty); - set => SetValue(IconColorProperty, value); - } - - public string Text - { - get => (string)GetValue(TextProperty); - set => SetValue(TextProperty, value); - } - - public InfoItem() - { - InitializeComponent(); - this.DataContext = this; - } - } -} \ No newline at end of file diff --git a/WandEnhancer/View/Controls/PopupHost.xaml b/WandEnhancer/View/Controls/PopupHost.xaml index b6f3723..f63ede7 100644 --- a/WandEnhancer/View/Controls/PopupHost.xaml +++ b/WandEnhancer/View/Controls/PopupHost.xaml @@ -38,7 +38,7 @@ - diff --git a/WandEnhancer/View/MainWindow/IShellView.cs b/WandEnhancer/View/MainWindow/IShellView.cs new file mode 100644 index 0000000..4dbb7b0 --- /dev/null +++ b/WandEnhancer/View/MainWindow/IShellView.cs @@ -0,0 +1,26 @@ +using System.Windows; + +namespace WandEnhancer.View.MainWindow +{ + /// + /// What the view model needs from the shell window. Exists so the view model does not + /// hold the concrete window or reach through a static Instance, which made every command + /// untestable and crashed whenever the singleton was not set yet. + /// + public interface IShellView + { + void OpenPopup(FrameworkElement content, string title); + void ClosePopup(); + void ScrollLogIntoView(LogEntry entry); + } + + /// Modal file/folder pickers, kept behind a seam so commands stay headless-testable. + public interface IFileDialogs + { + /// Chosen folder, or null when cancelled. + string PickFolder(string description, string initialPath); + + /// Chosen file path, or null when cancelled. + string PickSaveFile(string filter, string suggestedFileName); + } +} diff --git a/WandEnhancer/View/MainWindow/MainWindow.xaml b/WandEnhancer/View/MainWindow/MainWindow.xaml index 5bc0fa9..e8b8c59 100644 --- a/WandEnhancer/View/MainWindow/MainWindow.xaml +++ b/WandEnhancer/View/MainWindow/MainWindow.xaml @@ -183,9 +183,10 @@ Content="{DynamicResource mw_patch}"/>