From 2b4c2466bb55624dacb1ffcc3ab40f9b7c94584d Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Sat, 28 Jun 2025 21:22:57 -0400 Subject: [PATCH 01/40] Fix license section in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 50852ee..e289881 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ For documentation contributions: ## License -This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details. +This project is licensed under the Eclipse Public License 2.0 - see the [LICENSE](LICENSE) file for details. ## Contact From cca65b55d992b2fb2dbf42ddfc29b59d0eea5944 Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Sun, 29 Jun 2025 11:09:40 -0400 Subject: [PATCH 02/40] Fix license badge --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index e289881..2a35fe7 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,7 @@ A professional tool for configuring and troubleshooting OSDP devices. [![.NET](https://img.shields.io/badge/.NET-8.0-blue)](https://dotnet.microsoft.com/) -[![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)](LICENSE) -[![Platform](https://img.shields.io/badge/Platform-Windows-lightgrey)](https://docs.microsoft.com/en-us/windows/) +[![License](https://img.shields.io/badge/License-Eclipse%202.0-green.svg)](LICENSE) ## About From f21dcbe5f41e8c0ed55f3450aedd7162f76844fd Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Sun, 29 Jun 2025 11:25:53 -0400 Subject: [PATCH 03/40] Add app store badges --- README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2a35fe7..3ced26c 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,20 @@ Core functionality is under an open source license to help increase the adoption - **Multi-language Support** - Available in multiple languages - **Cross-platform** - Built on .NET 8.0 for modern compatibility +## Get OSDP Bench + +### Download the App + +OSDP Bench is available for purchase on multiple platforms: + + + Get it from Microsoft Store + + + + Get it on Google Play + + ## Getting Started ### Prerequisites @@ -28,7 +42,7 @@ Core functionality is under an open source license to help increase the adoption - Windows 10/11 (for WinUI version) - Serial port access for device communication -### Installation +### Building from Source 1. Clone the repository: ```bash From 1780d79c1cc6e6ca39215cba3ca56bcf3a61a82d Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Sun, 29 Jun 2025 11:32:14 -0400 Subject: [PATCH 04/40] Side by side --- README.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/README.md b/README.md index 3ced26c..dc3b7ca 100644 --- a/README.md +++ b/README.md @@ -26,13 +26,7 @@ Core functionality is under an open source license to help increase the adoption OSDP Bench is available for purchase on multiple platforms: - - Get it from Microsoft Store - - - - Get it on Google Play - +Microsoft Store Google Play ## Getting Started From 4d01b71306fc07c12e4b37fc4d4384c0e045b868 Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Sun, 29 Jun 2025 11:34:40 -0400 Subject: [PATCH 05/40] Align badges --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dc3b7ca..dbddbb7 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Core functionality is under an open source license to help increase the adoption OSDP Bench is available for purchase on multiple platforms: -Microsoft Store Google Play +Microsoft Store Google Play ## Getting Started From d69d98cd20342de63c8887f84cd1a35355c50655 Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Sun, 29 Jun 2025 11:55:13 -0400 Subject: [PATCH 06/40] Fix store badges --- README.md | 3 ++- src/Assets/google-play.svg | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 src/Assets/google-play.svg diff --git a/README.md b/README.md index dbddbb7..d1c277a 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,8 @@ Core functionality is under an open source license to help increase the adoption OSDP Bench is available for purchase on multiple platforms: -Microsoft Store Google Play +[![Microsoft Store](https://get.microsoft.com/images/en-us%20dark.svg)](ms-windows-store://pdp/?productid=9N3W7QR3R5S7&cid=&mode=mini) +[![Google Play](src/Assets/google-play.svg)](https://play.google.com/store/apps/details?id=com.z_bitco.com.osdpbenchmobile) ## Getting Started diff --git a/src/Assets/google-play.svg b/src/Assets/google-play.svg new file mode 100644 index 0000000..223ebd2 --- /dev/null +++ b/src/Assets/google-play.svg @@ -0,0 +1 @@ + \ No newline at end of file From 6bb4c19df0944a37e678a02d55f1b55a30bd0106 Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Mon, 30 Jun 2025 21:59:57 -0400 Subject: [PATCH 07/40] Choose a matching language when starting the app --- docs/CLAUDE.md | 1 + docs/SYSTEM_LANGUAGE_CHECK.md | 149 ++++++++++++++++++ src/Core/Resources/Resources.resx | 8 + src/Core/Services/ILanguageMismatchService.cs | 14 ++ src/Core/Services/ILocalizationService.cs | 19 +++ src/Core/Services/LanguageMismatchService.cs | 94 +++++++++++ src/Core/Services/LocalizationService.cs | 36 +++++ src/UI/Windows/App.xaml.cs | 18 +++ src/UI/Windows/Views/Pages/ConnectPage.xaml | 62 ++++---- .../Windows/Views/Pages/ConnectPage.xaml.cs | 65 ++++++-- 10 files changed, 426 insertions(+), 40 deletions(-) create mode 100644 docs/SYSTEM_LANGUAGE_CHECK.md create mode 100644 src/Core/Services/ILanguageMismatchService.cs create mode 100644 src/Core/Services/LanguageMismatchService.cs diff --git a/docs/CLAUDE.md b/docs/CLAUDE.md index b66db58..aa0655d 100644 --- a/docs/CLAUDE.md +++ b/docs/CLAUDE.md @@ -35,5 +35,6 @@ - **Follow the style hierarchy** - Check ComponentStyles.xaml and LayoutTemplates.xaml before creating custom styles - **Update existing code** - When modifying files, replace inline styling with standard styles - **Create reusable patterns** - If you find yourself repeating XAML structures, consider adding a new style or template +- **Use WrapPanel for responsive layouts** - When controls should be horizontal on wide screens but wrap to vertical on narrow screens, use WrapPanel instead of fixed Grid layouts For detailed UI styling guidelines and examples, see: `src/UI/Windows/Styles/StyleGuide.md` diff --git a/docs/SYSTEM_LANGUAGE_CHECK.md b/docs/SYSTEM_LANGUAGE_CHECK.md new file mode 100644 index 0000000..1de7226 --- /dev/null +++ b/docs/SYSTEM_LANGUAGE_CHECK.md @@ -0,0 +1,149 @@ +# System Language Matching + +This document describes the system language matching functionality added to OSDP-Bench. + +## Overview + +The localization service now provides methods to check if the application's current language matches the system language. This can be useful for: +- Notifying users when their app language differs from the system +- Providing an option to sync with system language +- Analytics to understand user language preferences + +## New API Methods + +### `IsSystemLanguageMatch()` +Checks if the current application language matches the system language. + +```csharp +bool isMatch = _localizationService.IsSystemLanguageMatch(); +``` + +Returns `true` if: +- The system language is not supported by the application (no mismatch to report) +- The culture names are exactly the same (e.g., "en-US" == "en-US") +- The base languages match (e.g., "en-US" matches "en-GB") + +### `GetSystemCulture()` +Gets the current system UI culture. + +```csharp +CultureInfo systemCulture = _localizationService.GetSystemCulture(); +``` + +### `IsCultureSupported(CultureInfo culture)` +Checks if a specific culture is supported by the application. + +```csharp +bool isSupported = _localizationService.IsCultureSupported(systemCulture); +``` + +Returns `true` if the culture or its base language is supported by the application. + +## Usage Examples + +### Example 1: Display System Language Mismatch Indicator +```csharp +public class LanguageStatusViewModel : ObservableObject +{ + private readonly ILocalizationService _localizationService; + + public bool IsSystemLanguageMismatch => !_localizationService.IsSystemLanguageMatch(); + + public string SystemLanguageName => _localizationService.GetSystemCulture().NativeName; + + public LanguageStatusViewModel(ILocalizationService localizationService) + { + _localizationService = localizationService; + _localizationService.CultureChanged += (s, e) => OnPropertyChanged(nameof(IsSystemLanguageMismatch)); + } +} +``` + +### Example 2: Prompt User on Language Mismatch +```csharp +public async Task CheckLanguageOnStartupAsync() +{ + if (!_localizationService.IsSystemLanguageMatch()) + { + var systemCulture = _localizationService.GetSystemCulture(); + var result = await _dialogService.ShowMessageAsync( + $"Your system language is {systemCulture.NativeName}. " + + "Would you like to switch the application to match?", + "Language Mismatch", + DialogButtons.YesNo); + + if (result == DialogResult.Yes) + { + _localizationService.ChangeCulture(systemCulture); + } + } +} +``` + +### Example 3: Add "Use System Language" Option +```csharp +public class LanguageSelectionViewModel : ObservableObject +{ + [RelayCommand] + private void UseSystemLanguage() + { + var systemCulture = _localizationService.GetSystemCulture(); + _localizationService.ChangeCulture(systemCulture); + } + + public bool IsUsingSystemLanguage => _localizationService.IsSystemLanguageMatch(); +} +``` + +## Implementation Notes + +1. **System Culture Detection**: Uses `CultureInfo.InstalledUICulture` which represents the OS display language +2. **Flexible Matching**: Considers both exact matches and base language matches +3. **Real-time Updates**: The `IsSystemLanguageMatch()` method always checks against the current system state + +## UI Integration + +The system language prompt has been integrated into the application startup process. Here's how it works: + +### Automatic Detection +- When the application starts, it automatically checks if the system language matches the current app language +- The check only runs for users who have previously set a language preference (not first-time users) +- If the system language is not supported by the app, no prompt is shown + +### User Experience +1. **Language Mismatch Detected**: A dialog appears with the title "System Language Detected" +2. **Informative Message**: Shows "Your system language is [Language Name]. Would you like to switch the application to match your system language?" +3. **User Choice**: User can choose "OK" to switch or "Cancel" to keep current language +4. **Automatic Switching**: If user chooses "OK", the app immediately switches to the best matching supported language + +### Implementation Details +- **Service**: `LanguageMismatchService` handles all the logic +- **Timing**: Check runs 500ms after startup to ensure UI is fully loaded +- **Language Matching**: Uses exact match first, then falls back to base language match (e.g., "en-GB" → "en-US") +- **Persistence**: Language choice is automatically saved to user settings + +## Testing + +To test the system language prompt: + +### Test Case 1: Language Mismatch +1. Set Windows display language to Spanish (Settings > Time & Language > Language) +2. Set OSDP-Bench to English in the Info page +3. Close and relaunch the application +4. You should see the system language prompt asking to switch to Spanish + +### Test Case 2: No Prompt for Unsupported Language +1. Set Windows display language to Italian (not supported by the app) +2. Set OSDP-Bench to English +3. Close and relaunch the application +4. No prompt should appear (Italian is not supported) + +### Test Case 3: First-Time User +1. Delete the settings file (`%APPDATA%\OSDPBench\settings.json`) +2. Launch the application +3. No prompt should appear (first-time users get system language by default) + +### Test Case 4: Languages Already Match +1. Set both Windows and OSDP-Bench to the same language +2. Relaunch the application +3. No prompt should appear (languages already match) \ No newline at end of file diff --git a/src/Core/Resources/Resources.resx b/src/Core/Resources/Resources.resx index 38473df..20a6425 100644 --- a/src/Core/Resources/Resources.resx +++ b/src/Core/Resources/Resources.resx @@ -581,4 +581,12 @@ Language changed successfully Confirmation message when language is changed + + System Language Detected + Title for system language mismatch dialog + + + Your system language is {0}. Would you like to switch the application to match your system language? + Message asking user if they want to switch to system language. {0} is the system language name. + \ No newline at end of file diff --git a/src/Core/Services/ILanguageMismatchService.cs b/src/Core/Services/ILanguageMismatchService.cs new file mode 100644 index 0000000..1cd21e6 --- /dev/null +++ b/src/Core/Services/ILanguageMismatchService.cs @@ -0,0 +1,14 @@ +using System.Globalization; + +namespace OSDPBench.Core.Services; + +/// +/// Service for handling system language mismatch detection and user prompts +/// +public interface ILanguageMismatchService +{ + /// + /// Checks for system language mismatch and prompts the user if needed + /// + Task CheckAndPromptForLanguageMismatchAsync(); +} \ No newline at end of file diff --git a/src/Core/Services/ILocalizationService.cs b/src/Core/Services/ILocalizationService.cs index 5daffba..31cc258 100644 --- a/src/Core/Services/ILocalizationService.cs +++ b/src/Core/Services/ILocalizationService.cs @@ -55,4 +55,23 @@ public interface ILocalizationService /// The culture to get the display name for /// The localized display name string GetCultureDisplayName(CultureInfo culture); + + /// + /// Checks if the current application language matches the system language + /// + /// True if the languages match, false otherwise + bool IsSystemLanguageMatch(); + + /// + /// Gets the current system language + /// + /// The system's current UI culture + CultureInfo GetSystemCulture(); + + /// + /// Checks if a specific culture is supported by the application + /// + /// The culture to check + /// True if the culture or its base language is supported + bool IsCultureSupported(CultureInfo culture); } \ No newline at end of file diff --git a/src/Core/Services/LanguageMismatchService.cs b/src/Core/Services/LanguageMismatchService.cs new file mode 100644 index 0000000..612b024 --- /dev/null +++ b/src/Core/Services/LanguageMismatchService.cs @@ -0,0 +1,94 @@ +using System.Globalization; + +namespace OSDPBench.Core.Services; + +/// +/// Service for handling system language mismatch detection and user prompts +/// +public class LanguageMismatchService : ILanguageMismatchService +{ + private readonly ILocalizationService _localizationService; + private readonly IDialogService _dialogService; + private readonly IUserSettingsService _userSettingsService; + + /// + /// Initializes a new instance of the LanguageMismatchService + /// + /// The localization service + /// The dialog service + /// The user settings service + public LanguageMismatchService( + ILocalizationService localizationService, + IDialogService dialogService, + IUserSettingsService userSettingsService) + { + _localizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService)); + _dialogService = dialogService ?? throw new ArgumentNullException(nameof(dialogService)); + _userSettingsService = userSettingsService ?? throw new ArgumentNullException(nameof(userSettingsService)); + } + + /// + public async Task CheckAndPromptForLanguageMismatchAsync() + { + // Only check if this is not the user's first time setting a language + // (i.e., they have a saved preference) + if (string.IsNullOrEmpty(_userSettingsService.Settings.PreferredCulture)) + { + // First time user - don't prompt, just use system language + return; + } + + // Check if there's a mismatch + if (_localizationService.IsSystemLanguageMatch()) + { + // Languages match or system language not supported - no action needed + return; + } + + var systemCulture = _localizationService.GetSystemCulture(); + + // Get the display name of the system language + var systemLanguageName = systemCulture.NativeName; + + // Get localized strings for the dialog + var title = _localizationService.GetString("Language_SystemMismatchTitle"); + var message = _localizationService.GetString("Language_SystemMismatchMessage", systemLanguageName); + + // Show confirmation dialog + var userWantsToSwitch = await _dialogService.ShowConfirmationDialog( + title, + message, + MessageIcon.Information); + + if (userWantsToSwitch) + { + // Find the best supported culture that matches the system language + var supportedCulture = FindBestMatchingCulture(systemCulture); + if (supportedCulture != null) + { + _localizationService.ChangeCulture(supportedCulture); + } + } + } + + /// + /// Finds the best matching supported culture for the given system culture + /// + /// The system culture to match + /// The best matching supported culture, or null if none found + private CultureInfo? FindBestMatchingCulture(CultureInfo systemCulture) + { + var supportedCultures = _localizationService.SupportedCultures; + + // First try exact match + var exactMatch = supportedCultures.FirstOrDefault(c => c.Name == systemCulture.Name); + if (exactMatch != null) + return exactMatch; + + // Then try base language match + var baseLanguageMatch = supportedCultures.FirstOrDefault(c => + c.TwoLetterISOLanguageName == systemCulture.TwoLetterISOLanguageName); + + return baseLanguageMatch; + } +} \ No newline at end of file diff --git a/src/Core/Services/LocalizationService.cs b/src/Core/Services/LocalizationService.cs index aad0743..e1c8468 100644 --- a/src/Core/Services/LocalizationService.cs +++ b/src/Core/Services/LocalizationService.cs @@ -138,4 +138,40 @@ public string GetCultureDisplayName(CultureInfo culture) // Return the native name of the culture return culture.NativeName; } + + /// + public bool IsSystemLanguageMatch() + { + var systemCulture = GetSystemCulture(); + + // If system language is not supported, consider it a match (no need to prompt) + if (!IsCultureSupported(systemCulture)) + return true; + + // Check if cultures are exactly the same + if (_currentCulture.Name == systemCulture.Name) + return true; + + // Check if the base languages match (e.g., "en-US" matches "en-GB") + if (_currentCulture.TwoLetterISOLanguageName == systemCulture.TwoLetterISOLanguageName) + return true; + + return false; + } + + /// + public CultureInfo GetSystemCulture() + { + // Get the current system UI culture + // This represents the OS display language + return CultureInfo.InstalledUICulture; + } + + /// + public bool IsCultureSupported(CultureInfo culture) + { + return SupportedCultures.Any(c => + c.Name == culture.Name || + c.TwoLetterISOLanguageName == culture.TwoLetterISOLanguageName); + } } \ No newline at end of file diff --git a/src/UI/Windows/App.xaml.cs b/src/UI/Windows/App.xaml.cs index 124a9e2..d4201fa 100644 --- a/src/UI/Windows/App.xaml.cs +++ b/src/UI/Windows/App.xaml.cs @@ -57,6 +57,7 @@ public partial class App services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); }).Build(); /// @@ -100,6 +101,23 @@ private async void OnStartup(object sender, StartupEventArgs e) Host.Services.GetService(); Host.Services.GetService(); + + // Check for language mismatch after UI is initialized + _ = Task.Run(async () => + { + // Small delay to ensure UI is fully loaded + await Task.Delay(500); + + // Run on UI thread to ensure proper dialog display and culture updates + await Application.Current.Dispatcher.InvokeAsync(async () => + { + var languageMismatchService = Host.Services.GetService(); + if (languageMismatchService != null) + { + await languageMismatchService.CheckAndPromptForLanguageMismatchAsync(); + } + }); + }); } /// diff --git a/src/UI/Windows/Views/Pages/ConnectPage.xaml b/src/UI/Windows/Views/Pages/ConnectPage.xaml index 4ea914c..c384d62 100644 --- a/src/UI/Windows/Views/Pages/ConnectPage.xaml +++ b/src/UI/Windows/Views/Pages/ConnectPage.xaml @@ -60,39 +60,32 @@ - + - - + + + - - + + - + - - - - - - - - - - + + + + VerticalAlignment="Center" + HorizontalAlignment="Right" + Margin="0,0,0,10"> - + + + + + + + + + + + diff --git a/src/UI/Windows/Views/Pages/ConnectPage.xaml.cs b/src/UI/Windows/Views/Pages/ConnectPage.xaml.cs index d9c98a3..b54a7d0 100644 --- a/src/UI/Windows/Views/Pages/ConnectPage.xaml.cs +++ b/src/UI/Windows/Views/Pages/ConnectPage.xaml.cs @@ -1,6 +1,8 @@ using System.Windows.Controls; using System.ComponentModel; using System.Windows; +using System.Windows.Data; +using System.Windows.Media; using OSDPBench.Core.ViewModels.Pages; using Wpf.Ui.Abstractions.Controls; using Wpf.Ui.Controls; @@ -17,6 +19,10 @@ public ConnectPage(ConnectViewModel viewModel) ViewModel = viewModel; DataContext = this; + // Initialize connection types + _connectionTypes = new System.Collections.ObjectModel.ObservableCollection(); + UpdateConnectionTypes(); + // Subscribe to culture changes Core.Resources.Resources.PropertyChanged += OnResourcesPropertyChanged; @@ -31,11 +37,20 @@ public ConnectPage(ConnectViewModel viewModel) public ConnectViewModel ViewModel { get; } - public IEnumerable ConnectionTypes => - [ - Core.Resources.Resources.GetString("ConnectionType_Discover"), - Core.Resources.Resources.GetString("ConnectionType_Manual") - ]; + private readonly System.Collections.ObjectModel.ObservableCollection _connectionTypes; + public System.Collections.ObjectModel.ObservableCollection ConnectionTypes => _connectionTypes; + + private void UpdateConnectionTypes() + { + int previousSelectedConnectionTypeIndex = SelectedConnectionTypeIndex; + + _connectionTypes.Clear(); + + _connectionTypes.Add(Core.Resources.Resources.GetString("ConnectionType_Discover")); + _connectionTypes.Add(Core.Resources.Resources.GetString("ConnectionType_Manual")); + + SelectedConnectionTypeIndex = previousSelectedConnectionTypeIndex; + } private int _selectedConnectionTypeIndex = -1; // Start with -1 to ensure property change fires @@ -92,13 +107,12 @@ private Visibility CalculateCancelDiscoveryVisibility() private void OnResourcesPropertyChanged(object? sender, PropertyChangedEventArgs e) { - // When culture changes, notify that ConnectionTypes has changed - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ConnectionTypes))); - - // Force the ComboBox to refresh its selection - var currentIndex = SelectedConnectionTypeIndex; - SelectedConnectionTypeIndex = -1; - SelectedConnectionTypeIndex = currentIndex; + // When culture changes, update the connection types with new localized strings + // Since we're updating in place, the selection should be maintained + UpdateConnectionTypes(); + + // Ensure the UI updates properly + UpdateButtonVisibility(); } private void OnViewModelPropertyChanged(object? sender, PropertyChangedEventArgs e) @@ -137,4 +151,31 @@ private void AddressNumberBox_OnValueChanged(object sender, NumberBoxValueChange { ViewModel.SelectedAddress = (byte)(AddressNumberBox.Value ?? 0); } + + private void OnConnectionGridSizeChanged(object sender, SizeChangedEventArgs e) + { + // Check if we have enough width for side-by-side layout + // Threshold of 500 pixels seems reasonable for this layout + const double WidthThreshold = 500; + + if (ButtonPanel != null) + { + if (e.NewSize.Width < WidthThreshold) + { + // Narrow: Move buttons to second row, left aligned + Grid.SetRow(ButtonPanel, 1); + Grid.SetColumn(ButtonPanel, 0); + Grid.SetColumnSpan(ButtonPanel, 2); + ButtonPanel.HorizontalAlignment = HorizontalAlignment.Left; + } + else + { + // Wide: Buttons on same row as title, right aligned + Grid.SetRow(ButtonPanel, 0); + Grid.SetColumn(ButtonPanel, 1); + Grid.SetColumnSpan(ButtonPanel, 1); + ButtonPanel.HorizontalAlignment = HorizontalAlignment.Right; + } + } + } } \ No newline at end of file From 3e7484f7486020d5457f4a003ba92757c7d73837 Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Mon, 30 Jun 2025 22:11:45 -0400 Subject: [PATCH 08/40] New translations resources.resx (French) --- src/Core/Resources/Resources.fr.resx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Core/Resources/Resources.fr.resx b/src/Core/Resources/Resources.fr.resx index fbc0ba0..5ca1865 100644 --- a/src/Core/Resources/Resources.fr.resx +++ b/src/Core/Resources/Resources.fr.resx @@ -561,4 +561,12 @@ Changement de langue réussi Confirmation message when language is changed + + System Language Detected + Title for system language mismatch dialog + + + Your system language is {0}. Would you like to switch the application to match your system language? + Message asking user if they want to switch to system language. {0} is the system language name. + \ No newline at end of file From 99cef7a8cf33fdfadd6438c5d77fefaeb5edc5dd Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Mon, 30 Jun 2025 22:11:46 -0400 Subject: [PATCH 09/40] New translations resources.resx (Spanish) --- src/Core/Resources/Resources.es.resx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Core/Resources/Resources.es.resx b/src/Core/Resources/Resources.es.resx index f53280d..2fbc144 100644 --- a/src/Core/Resources/Resources.es.resx +++ b/src/Core/Resources/Resources.es.resx @@ -561,4 +561,12 @@ El lenguaje cambió con éxito Confirmation message when language is changed + + System Language Detected + Title for system language mismatch dialog + + + Your system language is {0}. Would you like to switch the application to match your system language? + Message asking user if they want to switch to system language. {0} is the system language name. + \ No newline at end of file From ade8cba5f0c2628fa16c4aab633e5f47bd0221ba Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Mon, 30 Jun 2025 22:11:47 -0400 Subject: [PATCH 10/40] New translations resources.resx (German) --- src/Core/Resources/Resources.de.resx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Core/Resources/Resources.de.resx b/src/Core/Resources/Resources.de.resx index 5776725..1e90846 100644 --- a/src/Core/Resources/Resources.de.resx +++ b/src/Core/Resources/Resources.de.resx @@ -561,4 +561,12 @@ Sprache erfolgreich geändert Confirmation message when language is changed + + System Language Detected + Title for system language mismatch dialog + + + Your system language is {0}. Would you like to switch the application to match your system language? + Message asking user if they want to switch to system language. {0} is the system language name. + \ No newline at end of file From c6fdedab5c45c812c4b69670efc263953d08cee7 Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Mon, 30 Jun 2025 22:11:48 -0400 Subject: [PATCH 11/40] New translations resources.resx (Japanese) --- src/Core/Resources/Resources.ja.resx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Core/Resources/Resources.ja.resx b/src/Core/Resources/Resources.ja.resx index f4a2f6d..5fa0e68 100644 --- a/src/Core/Resources/Resources.ja.resx +++ b/src/Core/Resources/Resources.ja.resx @@ -561,4 +561,12 @@ 言語が正常に変更されました Confirmation message when language is changed + + System Language Detected + Title for system language mismatch dialog + + + Your system language is {0}. Would you like to switch the application to match your system language? + Message asking user if they want to switch to system language. {0} is the system language name. + \ No newline at end of file From 1b0e00b8bca7efb992806f6430f56425b3d4d15f Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Mon, 30 Jun 2025 22:11:49 -0400 Subject: [PATCH 12/40] New translations resources.resx (Chinese Simplified) --- src/Core/Resources/Resources.zh.resx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Core/Resources/Resources.zh.resx b/src/Core/Resources/Resources.zh.resx index b7df891..9f17aaa 100644 --- a/src/Core/Resources/Resources.zh.resx +++ b/src/Core/Resources/Resources.zh.resx @@ -561,4 +561,12 @@ 语言更改成功 Confirmation message when language is changed + + System Language Detected + Title for system language mismatch dialog + + + Your system language is {0}. Would you like to switch the application to match your system language? + Message asking user if they want to switch to system language. {0} is the system language name. + \ No newline at end of file From 16eeaa931155be4b84df7c64179e63408c5cd9ec Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Tue, 1 Jul 2025 08:30:47 -0400 Subject: [PATCH 13/40] Match system language with app --- src/Core/Models/UserSettings.cs | 5 + src/Core/Resources/Resources.resx | 12 ++ src/Core/Services/ILanguageMismatchService.cs | 7 + src/Core/Services/LanguageMismatchService.cs | 41 +++-- .../LanguageMismatchDialogViewModel.cs | 41 +++++ .../ViewModels/Windows/MainWindowViewModel.cs | 2 +- src/UI/Windows/App.xaml.cs | 4 +- .../WindowsLanguageMismatchService.cs | 156 ++++++++++++++++++ .../Services/WindowsUserSettingsService.cs} | 12 +- .../Views/Dialogs/LanguageMismatchDialog.xaml | 55 ++++++ .../Dialogs/LanguageMismatchDialog.xaml.cs | 14 ++ 11 files changed, 331 insertions(+), 18 deletions(-) create mode 100644 src/Core/ViewModels/Dialogs/LanguageMismatchDialogViewModel.cs create mode 100644 src/UI/Windows/Services/WindowsLanguageMismatchService.cs rename src/{Core/Services/UserSettingsService.cs => UI/Windows/Services/WindowsUserSettingsService.cs} (86%) create mode 100644 src/UI/Windows/Views/Dialogs/LanguageMismatchDialog.xaml create mode 100644 src/UI/Windows/Views/Dialogs/LanguageMismatchDialog.xaml.cs diff --git a/src/Core/Models/UserSettings.cs b/src/Core/Models/UserSettings.cs index a096732..0d06af7 100644 --- a/src/Core/Models/UserSettings.cs +++ b/src/Core/Models/UserSettings.cs @@ -24,4 +24,9 @@ public class UserSettings /// Gets or sets whether the window is maximized /// public bool IsMaximized { get; set; } = false; + + /// + /// Gets or sets whether to skip language mismatch checking + /// + public bool SkipLanguageMismatchCheck { get; set; } = false; } \ No newline at end of file diff --git a/src/Core/Resources/Resources.resx b/src/Core/Resources/Resources.resx index 20a6425..b60bee2 100644 --- a/src/Core/Resources/Resources.resx +++ b/src/Core/Resources/Resources.resx @@ -589,4 +589,16 @@ Your system language is {0}. Would you like to switch the application to match your system language? Message asking user if they want to switch to system language. {0} is the system language name. + + Don't ask me again + Checkbox label to prevent future language mismatch prompts + + + Yes + Common Yes button text + + + No + Common No button text + \ No newline at end of file diff --git a/src/Core/Services/ILanguageMismatchService.cs b/src/Core/Services/ILanguageMismatchService.cs index 1cd21e6..dff0449 100644 --- a/src/Core/Services/ILanguageMismatchService.cs +++ b/src/Core/Services/ILanguageMismatchService.cs @@ -11,4 +11,11 @@ public interface ILanguageMismatchService /// Checks for system language mismatch and prompts the user if needed /// Task CheckAndPromptForLanguageMismatchAsync(); + + /// + /// Shows the language mismatch dialog with custom UI + /// + /// The name of the system language + /// A tuple containing (userWantsToSwitch, dontAskAgain) + Task<(bool userWantsToSwitch, bool dontAskAgain)> ShowLanguageMismatchDialogAsync(string systemLanguageName); } \ No newline at end of file diff --git a/src/Core/Services/LanguageMismatchService.cs b/src/Core/Services/LanguageMismatchService.cs index 612b024..c94630d 100644 --- a/src/Core/Services/LanguageMismatchService.cs +++ b/src/Core/Services/LanguageMismatchService.cs @@ -38,6 +38,13 @@ public async Task CheckAndPromptForLanguageMismatchAsync() return; } + // Check if user has disabled language mismatch checking + if (_userSettingsService.Settings.SkipLanguageMismatchCheck) + { + // User has opted out of language mismatch checks + return; + } + // Check if there's a mismatch if (_localizationService.IsSystemLanguageMatch()) { @@ -46,19 +53,17 @@ public async Task CheckAndPromptForLanguageMismatchAsync() } var systemCulture = _localizationService.GetSystemCulture(); - - // Get the display name of the system language var systemLanguageName = systemCulture.NativeName; - // Get localized strings for the dialog - var title = _localizationService.GetString("Language_SystemMismatchTitle"); - var message = _localizationService.GetString("Language_SystemMismatchMessage", systemLanguageName); + // Show custom dialog + var (userWantsToSwitch, dontAskAgain) = await ShowLanguageMismatchDialogAsync(systemLanguageName); - // Show confirmation dialog - var userWantsToSwitch = await _dialogService.ShowConfirmationDialog( - title, - message, - MessageIcon.Information); + // Save the "don't ask again" preference + if (dontAskAgain) + { + await _userSettingsService.UpdateSettingsAsync(settings => + settings.SkipLanguageMismatchCheck = true); + } if (userWantsToSwitch) { @@ -70,6 +75,22 @@ public async Task CheckAndPromptForLanguageMismatchAsync() } } } + + /// + public async Task<(bool userWantsToSwitch, bool dontAskAgain)> ShowLanguageMismatchDialogAsync(string systemLanguageName) + { + // This method will be implemented in the Windows-specific service + // For now, fall back to the simple dialog + var title = _localizationService.GetString("Language_SystemMismatchTitle"); + var message = _localizationService.GetString("Language_SystemMismatchMessage", systemLanguageName); + + var userWantsToSwitch = await _dialogService.ShowConfirmationDialog( + title, + message, + MessageIcon.Information); + + return (userWantsToSwitch, false); // No "don't ask again" option in fallback + } /// /// Finds the best matching supported culture for the given system culture diff --git a/src/Core/ViewModels/Dialogs/LanguageMismatchDialogViewModel.cs b/src/Core/ViewModels/Dialogs/LanguageMismatchDialogViewModel.cs new file mode 100644 index 0000000..765f2cc --- /dev/null +++ b/src/Core/ViewModels/Dialogs/LanguageMismatchDialogViewModel.cs @@ -0,0 +1,41 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; + +namespace OSDPBench.Core.ViewModels.Dialogs; + +/// +/// ViewModel for the language mismatch dialog +/// +public partial class LanguageMismatchDialogViewModel : ObservableObject +{ + private readonly Action _closeCallback; + + [ObservableProperty] + private string _message; + + [ObservableProperty] + private bool _dontAskAgain; + + /// + /// Initializes a new instance of the LanguageMismatchDialogViewModel + /// + /// The message to display + /// Callback when dialog closes (userChoice, dontAskAgain) + public LanguageMismatchDialogViewModel(string message, Action closeCallback) + { + _message = message; + _closeCallback = closeCallback ?? throw new ArgumentNullException(nameof(closeCallback)); + } + + [RelayCommand] + private void Yes() + { + _closeCallback(true, DontAskAgain); + } + + [RelayCommand] + private void No() + { + _closeCallback(false, DontAskAgain); + } +} \ No newline at end of file diff --git a/src/Core/ViewModels/Windows/MainWindowViewModel.cs b/src/Core/ViewModels/Windows/MainWindowViewModel.cs index e701e51..d747feb 100644 --- a/src/Core/ViewModels/Windows/MainWindowViewModel.cs +++ b/src/Core/ViewModels/Windows/MainWindowViewModel.cs @@ -6,7 +6,7 @@ namespace OSDPBench.Core.ViewModels.Windows; /// /// Represents the view model for the main window of the application. /// -public partial class MainWindowViewModel : ObservableObject +public class MainWindowViewModel : ObservableObject { /// /// Gets the language selection view model diff --git a/src/UI/Windows/App.xaml.cs b/src/UI/Windows/App.xaml.cs index d4201fa..d2b34ea 100644 --- a/src/UI/Windows/App.xaml.cs +++ b/src/UI/Windows/App.xaml.cs @@ -55,9 +55,9 @@ public partial class App services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); }).Build(); /// diff --git a/src/UI/Windows/Services/WindowsLanguageMismatchService.cs b/src/UI/Windows/Services/WindowsLanguageMismatchService.cs new file mode 100644 index 0000000..64cab26 --- /dev/null +++ b/src/UI/Windows/Services/WindowsLanguageMismatchService.cs @@ -0,0 +1,156 @@ +using System.Globalization; +using System.Windows; +using OSDPBench.Core.Services; +using OSDPBench.Core.ViewModels.Dialogs; +using OSDPBench.Windows.Views.Dialogs; + +namespace OSDPBench.Windows.Services; + +/// +/// Windows-specific implementation of language mismatch service with custom dialog support +/// +public class WindowsLanguageMismatchService : ILanguageMismatchService +{ + private readonly ILocalizationService _localizationService; + private readonly IDialogService _dialogService; + private readonly IUserSettingsService _userSettingsService; + + /// + /// Initializes a new instance of the WindowsLanguageMismatchService + /// + /// The localization service + /// The dialog service + /// The user settings service + public WindowsLanguageMismatchService( + ILocalizationService localizationService, + IDialogService dialogService, + IUserSettingsService userSettingsService) + { + _localizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService)); + _dialogService = dialogService ?? throw new ArgumentNullException(nameof(dialogService)); + _userSettingsService = userSettingsService ?? throw new ArgumentNullException(nameof(userSettingsService)); + } + + /// + public async Task CheckAndPromptForLanguageMismatchAsync() + { + System.Diagnostics.Debug.WriteLine("LanguageMismatchService: Starting check..."); + + // Only check if this is not the user's first time setting a language + if (string.IsNullOrEmpty(_userSettingsService.Settings.PreferredCulture)) + { + System.Diagnostics.Debug.WriteLine("LanguageMismatchService: First time user - skipping"); + return; + } + + System.Diagnostics.Debug.WriteLine($"LanguageMismatchService: User has preferred culture: {_userSettingsService.Settings.PreferredCulture}"); + + // Check if user has disabled language mismatch checking + if (_userSettingsService.Settings.SkipLanguageMismatchCheck) + { + System.Diagnostics.Debug.WriteLine("LanguageMismatchService: User has disabled checks - skipping"); + return; + } + + // Check if there's a mismatch + var systemCulture = _localizationService.GetSystemCulture(); + var currentCulture = _localizationService.CurrentCulture; + var isMatch = _localizationService.IsSystemLanguageMatch(); + + System.Diagnostics.Debug.WriteLine($"LanguageMismatchService: System culture: {systemCulture.Name} ({systemCulture.NativeName})"); + System.Diagnostics.Debug.WriteLine($"LanguageMismatchService: Current culture: {currentCulture.Name}"); + System.Diagnostics.Debug.WriteLine($"LanguageMismatchService: Is match: {isMatch}"); + + if (isMatch) + { + System.Diagnostics.Debug.WriteLine("LanguageMismatchService: Languages match - no action needed"); + return; + } + + System.Diagnostics.Debug.WriteLine("LanguageMismatchService: Language mismatch detected - showing dialog"); + var systemLanguageName = systemCulture.NativeName; + + // Show custom dialog + var (userWantsToSwitch, dontAskAgain) = await ShowLanguageMismatchDialogAsync(systemLanguageName); + + System.Diagnostics.Debug.WriteLine($"LanguageMismatchService: Dialog result - Switch: {userWantsToSwitch}, DontAsk: {dontAskAgain}"); + + // Save the "don't ask again" preference + if (dontAskAgain) + { + await _userSettingsService.UpdateSettingsAsync(settings => + settings.SkipLanguageMismatchCheck = true); + } + + if (userWantsToSwitch) + { + // Find the best supported culture that matches the system language + var supportedCulture = FindBestMatchingCulture(systemCulture); + if (supportedCulture != null) + { + _localizationService.ChangeCulture(supportedCulture); + } + } + } + + /// + public async Task<(bool userWantsToSwitch, bool dontAskAgain)> ShowLanguageMismatchDialogAsync(string systemLanguageName) + { + var tcs = new TaskCompletionSource<(bool, bool)>(); + + await Application.Current.Dispatcher.InvokeAsync(() => + { + // Create the dialog content + var message = _localizationService.GetString("Language_SystemMismatchMessage", systemLanguageName); + + Window? dialogWindow = null; + var viewModel = new LanguageMismatchDialogViewModel(message, (userChoice, dontAsk) => + { + tcs.SetResult((userChoice, dontAsk)); + dialogWindow?.Close(); + }); + + var dialogContent = new LanguageMismatchDialog + { + DataContext = viewModel + }; + + // Create and show the dialog window + dialogWindow = new Window + { + Title = _localizationService.GetString("Language_SystemMismatchTitle"), + Content = dialogContent, + SizeToContent = SizeToContent.WidthAndHeight, + ResizeMode = ResizeMode.NoResize, + WindowStartupLocation = WindowStartupLocation.CenterOwner, + Owner = Application.Current.MainWindow, + ShowInTaskbar = false + }; + + dialogWindow.ShowDialog(); + }); + + return await tcs.Task; + } + + /// + /// Finds the best matching supported culture for the given system culture + /// + /// The system culture to match + /// The best matching supported culture, or null if none found + private CultureInfo? FindBestMatchingCulture(CultureInfo systemCulture) + { + var supportedCultures = _localizationService.SupportedCultures; + + // First try exact match + var exactMatch = supportedCultures.FirstOrDefault(c => c.Name == systemCulture.Name); + if (exactMatch != null) + return exactMatch; + + // Then try base language match + var baseLanguageMatch = supportedCultures.FirstOrDefault(c => + c.TwoLetterISOLanguageName == systemCulture.TwoLetterISOLanguageName); + + return baseLanguageMatch; + } +} \ No newline at end of file diff --git a/src/Core/Services/UserSettingsService.cs b/src/UI/Windows/Services/WindowsUserSettingsService.cs similarity index 86% rename from src/Core/Services/UserSettingsService.cs rename to src/UI/Windows/Services/WindowsUserSettingsService.cs index 874e5dd..a48a8cc 100644 --- a/src/Core/Services/UserSettingsService.cs +++ b/src/UI/Windows/Services/WindowsUserSettingsService.cs @@ -1,20 +1,22 @@ +using System.IO; using System.Text.Json; using OSDPBench.Core.Models; +using OSDPBench.Core.Services; -namespace OSDPBench.Core.Services; +namespace OSDPBench.Windows.Services; /// -/// Implementation of user settings service using JSON file storage +/// Windows implementation of a user settings service using JSON file storage /// -public class UserSettingsService : IUserSettingsService +public class WindowsUserSettingsService : IUserSettingsService { private readonly string _settingsFilePath; private UserSettings _settings; /// - /// Initializes a new instance of the UserSettingsService + /// Initializes a new instance of the WindowsUserSettingsService /// - public UserSettingsService() + public WindowsUserSettingsService() { var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); var appFolderPath = Path.Combine(appDataPath, "OSDPBench"); diff --git a/src/UI/Windows/Views/Dialogs/LanguageMismatchDialog.xaml b/src/UI/Windows/Views/Dialogs/LanguageMismatchDialog.xaml new file mode 100644 index 0000000..a0abbcf --- /dev/null +++ b/src/UI/Windows/Views/Dialogs/LanguageMismatchDialog.xaml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/UI/Windows/Views/Dialogs/LanguageMismatchDialog.xaml.cs b/src/UI/Windows/Views/Dialogs/LanguageMismatchDialog.xaml.cs new file mode 100644 index 0000000..dd4cf3e --- /dev/null +++ b/src/UI/Windows/Views/Dialogs/LanguageMismatchDialog.xaml.cs @@ -0,0 +1,14 @@ +using System.Windows.Controls; + +namespace OSDPBench.Windows.Views.Dialogs; + +/// +/// Interaction logic for LanguageMismatchDialog.xaml +/// +public partial class LanguageMismatchDialog : UserControl +{ + public LanguageMismatchDialog() + { + InitializeComponent(); + } +} \ No newline at end of file From 8d7de956b3c00374f47294021ad2b5cd365ca898 Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Tue, 1 Jul 2025 08:54:03 -0400 Subject: [PATCH 14/40] New translations resources.resx (French) --- src/Core/Resources/Resources.fr.resx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Core/Resources/Resources.fr.resx b/src/Core/Resources/Resources.fr.resx index 5ca1865..2f1a7bb 100644 --- a/src/Core/Resources/Resources.fr.resx +++ b/src/Core/Resources/Resources.fr.resx @@ -569,4 +569,16 @@ Your system language is {0}. Would you like to switch the application to match your system language? Message asking user if they want to switch to system language. {0} is the system language name. + + Don't ask me again + Checkbox label to prevent future language mismatch prompts + + + Yes + Common Yes button text + + + No + Common No button text + \ No newline at end of file From 4d89e1ead396f3f92285dbc38b9e9bba1d33e6c8 Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Tue, 1 Jul 2025 08:54:04 -0400 Subject: [PATCH 15/40] New translations resources.resx (Spanish) --- src/Core/Resources/Resources.es.resx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Core/Resources/Resources.es.resx b/src/Core/Resources/Resources.es.resx index 2fbc144..abe53e6 100644 --- a/src/Core/Resources/Resources.es.resx +++ b/src/Core/Resources/Resources.es.resx @@ -569,4 +569,16 @@ Your system language is {0}. Would you like to switch the application to match your system language? Message asking user if they want to switch to system language. {0} is the system language name. + + Don't ask me again + Checkbox label to prevent future language mismatch prompts + + + Yes + Common Yes button text + + + No + Common No button text + \ No newline at end of file From bcfca8e20bd9edc0d51f90cfc17be13ab670f410 Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Tue, 1 Jul 2025 08:54:05 -0400 Subject: [PATCH 16/40] New translations resources.resx (German) --- src/Core/Resources/Resources.de.resx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Core/Resources/Resources.de.resx b/src/Core/Resources/Resources.de.resx index 1e90846..fc10b6e 100644 --- a/src/Core/Resources/Resources.de.resx +++ b/src/Core/Resources/Resources.de.resx @@ -569,4 +569,16 @@ Your system language is {0}. Would you like to switch the application to match your system language? Message asking user if they want to switch to system language. {0} is the system language name. + + Don't ask me again + Checkbox label to prevent future language mismatch prompts + + + Yes + Common Yes button text + + + No + Common No button text + \ No newline at end of file From 9f0d5d21dbfc703435d669c10145c7bd5dbc56fd Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Tue, 1 Jul 2025 08:54:06 -0400 Subject: [PATCH 17/40] New translations resources.resx (Japanese) --- src/Core/Resources/Resources.ja.resx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Core/Resources/Resources.ja.resx b/src/Core/Resources/Resources.ja.resx index 5fa0e68..540caf6 100644 --- a/src/Core/Resources/Resources.ja.resx +++ b/src/Core/Resources/Resources.ja.resx @@ -569,4 +569,16 @@ Your system language is {0}. Would you like to switch the application to match your system language? Message asking user if they want to switch to system language. {0} is the system language name. + + Don't ask me again + Checkbox label to prevent future language mismatch prompts + + + Yes + Common Yes button text + + + No + Common No button text + \ No newline at end of file From e484f22f898e91b9478ba2a7957b09bf75b27f67 Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Tue, 1 Jul 2025 08:54:09 -0400 Subject: [PATCH 18/40] New translations resources.resx (Chinese Simplified) --- src/Core/Resources/Resources.zh.resx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Core/Resources/Resources.zh.resx b/src/Core/Resources/Resources.zh.resx index 9f17aaa..0b50d90 100644 --- a/src/Core/Resources/Resources.zh.resx +++ b/src/Core/Resources/Resources.zh.resx @@ -569,4 +569,16 @@ Your system language is {0}. Would you like to switch the application to match your system language? Message asking user if they want to switch to system language. {0} is the system language name. + + Don't ask me again + Checkbox label to prevent future language mismatch prompts + + + Yes + Common Yes button text + + + No + Common No button text + \ No newline at end of file From 6d00a03f031d66f0b445b76fd66ffdb051b32190 Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Tue, 1 Jul 2025 09:03:01 -0400 Subject: [PATCH 19/40] Fix code inspection issues --- OSDP-Bench.sln.DotSettings | 1 + src/Core/Actions/FileTransferAction.cs | 2 +- src/Core/Actions/ResetCypressDeviceAction.cs | 2 +- src/Core/Actions/SetCommunicationAction.cs | 2 +- src/Core/Models/UserSettings.cs | 8 +- src/Core/Services/DeviceManagementService.cs | 15 +- src/Core/Services/DeviceStateService.cs | 12 +- src/Core/Services/ILanguageMismatchService.cs | 2 - src/Core/Services/IUsbDeviceMonitorService.cs | 2 - src/Core/Services/LocalizationService.cs | 8 +- .../ViewModels/LanguageSelectionViewModel.cs | 1 - src/Core/ViewModels/Pages/ConnectViewModel.cs | 49 +++--- src/Core/ViewModels/Pages/ManageViewModel.cs | 29 ++- src/UI/Windows/App.xaml.cs | 2 +- src/UI/Windows/Helpers/CopyTextBoxHelper.cs | 27 ++- src/UI/Windows/Markup/LocalizeExtension.cs | 1 - .../Windows/Markup/LocalizedStringBinding.cs | 8 +- .../Windows/Services/WindowsDialogService.cs | 2 - .../WindowsLanguageMismatchService.cs | 27 +-- .../WindowsUsbDeviceMonitorService.cs | 165 +++++++----------- src/UI/Windows/Styles/ComponentStyles.xaml | 2 + src/UI/Windows/Styles/DesignTokens.xaml | 1 - src/UI/Windows/Styles/LayoutTemplates.xaml | 6 +- .../Controls/FileTransferControl.xaml.cs | 1 - .../Views/Controls/SetReaderLedControl.xaml | 1 - .../Dialogs/LanguageMismatchDialog.xaml.cs | 6 +- .../Windows/Views/Pages/ConnectPage.xaml.cs | 12 +- src/UI/Windows/Views/Pages/InvertEffect.cs | 2 +- src/UI/Windows/Views/Pages/ManagePage.xaml.cs | 5 +- .../Windows/Views/Pages/MonitorPage.xaml.cs | 3 +- .../ViewModels/UsbMonitoringTests.cs | 15 +- 31 files changed, 166 insertions(+), 253 deletions(-) diff --git a/OSDP-Bench.sln.DotSettings b/OSDP-Bench.sln.DotSettings index a7fc0a9..ec3bac6 100644 --- a/OSDP-Bench.sln.DotSettings +++ b/OSDP-Bench.sln.DotSettings @@ -1,4 +1,5 @@  CRC + .XX True True \ No newline at end of file diff --git a/src/Core/Actions/FileTransferAction.cs b/src/Core/Actions/FileTransferAction.cs index 9ef4750..24439f9 100644 --- a/src/Core/Actions/FileTransferAction.cs +++ b/src/Core/Actions/FileTransferAction.cs @@ -20,7 +20,7 @@ public async Task PerformAction(ControlPanel panel, Guid connectionId, b { if (parameter is not FileTransferParameters transferParams) { - throw new ArgumentException("Invalid parameter type for file transfer", nameof(parameter)); + throw new ArgumentException(@"Invalid parameter type for file transfer", nameof(parameter)); } if (string.IsNullOrEmpty(transferParams.FilePath)) diff --git a/src/Core/Actions/ResetCypressDeviceAction.cs b/src/Core/Actions/ResetCypressDeviceAction.cs index 7ace2f4..5ef4be5 100644 --- a/src/Core/Actions/ResetCypressDeviceAction.cs +++ b/src/Core/Actions/ResetCypressDeviceAction.cs @@ -21,7 +21,7 @@ public async Task PerformAction(ControlPanel panel, Guid connectionId, b await panel.Shutdown(); var connectionService = parameter as IOsdpConnection ?? - throw new ArgumentException("Invalid type", nameof(parameter)); + throw new ArgumentException(@"Invalid type", nameof(parameter)); connectionId = panel.StartConnection(connectionService, TimeSpan.Zero); diff --git a/src/Core/Actions/SetCommunicationAction.cs b/src/Core/Actions/SetCommunicationAction.cs index 26bcc8e..408e0a1 100644 --- a/src/Core/Actions/SetCommunicationAction.cs +++ b/src/Core/Actions/SetCommunicationAction.cs @@ -20,7 +20,7 @@ public async Task PerformAction(ControlPanel panel, Guid connectionId, b object? parameter) { var communicationParameters = parameter as CommunicationParameters ?? - throw new ArgumentException("Invalid type", nameof(parameter)); + throw new ArgumentException(@"Invalid type", nameof(parameter)); var result = await panel.CommunicationConfiguration(connectionId, address, new CommunicationConfiguration(communicationParameters.Address, diff --git a/src/Core/Models/UserSettings.cs b/src/Core/Models/UserSettings.cs index 0d06af7..e6fd223 100644 --- a/src/Core/Models/UserSettings.cs +++ b/src/Core/Models/UserSettings.cs @@ -13,20 +13,20 @@ public class UserSettings /// /// Gets or sets the window width /// - public double WindowWidth { get; set; } = 800; + public double WindowWidth { get; init; } = 800; /// /// Gets or sets the window height /// - public double WindowHeight { get; set; } = 600; + public double WindowHeight { get; init; } = 600; /// /// Gets or sets whether the window is maximized /// - public bool IsMaximized { get; set; } = false; + public bool IsMaximized { get; init; } /// /// Gets or sets whether to skip language mismatch checking /// - public bool SkipLanguageMismatchCheck { get; set; } = false; + public bool SkipLanguageMismatchCheck { get; set; } } \ No newline at end of file diff --git a/src/Core/Services/DeviceManagementService.cs b/src/Core/Services/DeviceManagementService.cs index 46fe062..75f9821 100644 --- a/src/Core/Services/DeviceManagementService.cs +++ b/src/Core/Services/DeviceManagementService.cs @@ -222,20 +222,7 @@ public async Task Shutdown() await _panel.Shutdown(); - try - { - await WaitUntilDeviceIsOffline(); - } - catch (TimeoutException ex) - { - // Log or handle the timeout exception - Console.WriteLine($"Warning: {ex.Message}"); - } - catch (Exception ex) - { - // Log unexpected exceptions during shutdown - Console.WriteLine($"Error during device shutdown: {ex.Message}"); - } + await WaitUntilDeviceIsOffline(); } private async Task WaitUntilDeviceIsOffline() diff --git a/src/Core/Services/DeviceStateService.cs b/src/Core/Services/DeviceStateService.cs index 1aaaab5..7eb215c 100644 --- a/src/Core/Services/DeviceStateService.cs +++ b/src/Core/Services/DeviceStateService.cs @@ -22,22 +22,22 @@ public DeviceStateService(IDeviceManagementService deviceManagementService) throw new ArgumentNullException(nameof(deviceManagementService)); // Forward events from the device management service - _deviceManagementService.ConnectionStatusChange += (sender, args) => + _deviceManagementService.ConnectionStatusChange += (_, args) => ConnectionStatusChange?.Invoke(this, args); - _deviceManagementService.KeypadReadReceived += (sender, args) => + _deviceManagementService.KeypadReadReceived += (_, args) => KeypadReadReceived?.Invoke(this, args); - _deviceManagementService.CardReadReceived += (sender, args) => + _deviceManagementService.CardReadReceived += (_, args) => CardReadReceived?.Invoke(this, args); - _deviceManagementService.TraceEntryReceived += (sender, args) => + _deviceManagementService.TraceEntryReceived += (_, args) => TraceEntryReceived?.Invoke(this, args); - _deviceManagementService.NakReplyReceived += (sender, args) => + _deviceManagementService.NakReplyReceived += (_, args) => NakReplyReceived?.Invoke(this, args); - _deviceManagementService.DeviceLookupsChanged += (sender, args) => + _deviceManagementService.DeviceLookupsChanged += (_, args) => DeviceLookupsChanged?.Invoke(this, args); } diff --git a/src/Core/Services/ILanguageMismatchService.cs b/src/Core/Services/ILanguageMismatchService.cs index dff0449..b3a47d5 100644 --- a/src/Core/Services/ILanguageMismatchService.cs +++ b/src/Core/Services/ILanguageMismatchService.cs @@ -1,5 +1,3 @@ -using System.Globalization; - namespace OSDPBench.Core.Services; /// diff --git a/src/Core/Services/IUsbDeviceMonitorService.cs b/src/Core/Services/IUsbDeviceMonitorService.cs index 3d93ccd..9a199bf 100644 --- a/src/Core/Services/IUsbDeviceMonitorService.cs +++ b/src/Core/Services/IUsbDeviceMonitorService.cs @@ -1,5 +1,3 @@ -using System; - namespace OSDPBench.Core.Services; /// diff --git a/src/Core/Services/LocalizationService.cs b/src/Core/Services/LocalizationService.cs index e1c8468..088c570 100644 --- a/src/Core/Services/LocalizationService.cs +++ b/src/Core/Services/LocalizationService.cs @@ -1,6 +1,4 @@ using System.Globalization; -using System.Resources; -using OSDPBench.Core.Resources; namespace OSDPBench.Core.Services; @@ -9,7 +7,6 @@ namespace OSDPBench.Core.Services; /// public class LocalizationService : ILocalizationService { - private readonly ResourceManager _resourceManager; private readonly IUserSettingsService? _userSettingsService; private CultureInfo _currentCulture; @@ -19,7 +16,6 @@ public class LocalizationService : ILocalizationService /// Optional user settings service for persistence public LocalizationService(IUserSettingsService? userSettingsService) { - _resourceManager = new ResourceManager("OSDPBench.Core.Resources.Resources", typeof(LocalizationService).Assembly); _userSettingsService = userSettingsService; // Initialize culture from settings or system default @@ -72,7 +68,7 @@ public CultureInfo CurrentCulture /// public string GetString(string key) { - return OSDPBench.Core.Resources.Resources.GetString(key); + return Resources.Resources.GetString(key); } /// @@ -101,7 +97,7 @@ public void ChangeCulture(CultureInfo culture) CultureInfo.CurrentCulture = culture; // Update the Resources class culture (this will trigger PropertyChanged) - OSDPBench.Core.Resources.Resources.ChangeCulture(culture); + Resources.Resources.ChangeCulture(culture); // Save preference to settings if (_userSettingsService != null) diff --git a/src/Core/ViewModels/LanguageSelectionViewModel.cs b/src/Core/ViewModels/LanguageSelectionViewModel.cs index 9ca5548..816eba6 100644 --- a/src/Core/ViewModels/LanguageSelectionViewModel.cs +++ b/src/Core/ViewModels/LanguageSelectionViewModel.cs @@ -3,7 +3,6 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using OSDPBench.Core.Services; -using OSDPBench.Core.Resources; namespace OSDPBench.Core.ViewModels; diff --git a/src/Core/ViewModels/Pages/ConnectViewModel.cs b/src/Core/ViewModels/Pages/ConnectViewModel.cs index 1ee8cdb..dee0424 100644 --- a/src/Core/ViewModels/Pages/ConnectViewModel.cs +++ b/src/Core/ViewModels/Pages/ConnectViewModel.cs @@ -5,7 +5,6 @@ using OSDP.Net.Tracing; using OSDPBench.Core.Models; using OSDPBench.Core.Services; -using OSDPBench.Core.Resources; namespace OSDPBench.Core.ViewModels.Pages; @@ -102,23 +101,23 @@ private void DeviceManagementServiceOnConnectionStatusChange(object? sender, Con { if (connectionStatus == ConnectionStatus.Connected) { - StatusText = OSDPBench.Core.Resources.Resources.GetString("Status_Connected"); + StatusText = Resources.Resources.GetString("Status_Connected"); NakText = string.Empty; StatusLevel = StatusLevel.Connected; } else if (StatusLevel == StatusLevel.Discovered) { - StatusText = OSDPBench.Core.Resources.Resources.GetString("Status_AttemptingToConnect"); + StatusText = Resources.Resources.GetString("Status_AttemptingToConnect"); StatusLevel = StatusLevel.Connecting; } else if (connectionStatus == ConnectionStatus.InvalidSecurityKey) { - StatusText = OSDPBench.Core.Resources.Resources.GetString("Status_InvalidSecurityKey"); + StatusText = Resources.Resources.GetString("Status_InvalidSecurityKey"); StatusLevel = StatusLevel.Error; } else { - StatusText = OSDPBench.Core.Resources.Resources.GetString("Status_Disconnected"); + StatusText = Resources.Resources.GetString("Status_Disconnected"); StatusLevel = StatusLevel.Disconnected; } } @@ -188,7 +187,7 @@ private async Task InitializeSerialPorts() } catch (Exception ex) { - Console.WriteLine(OSDPBench.Core.Resources.Resources.GetString("Error_InitializingSerialPorts").Replace("{0}", ex.Message)); + Console.WriteLine(Resources.Resources.GetString("Error_InitializingSerialPorts").Replace("{0}", ex.Message)); StatusLevel = StatusLevel.NotReady; _initializationComplete.SetException(ex); } @@ -230,27 +229,27 @@ private void UpdateDiscoveryStatus(DiscoveryResult current) switch (current.Status) { case DiscoveryStatus.Started: - StatusText = OSDPBench.Core.Resources.Resources.GetString("Status_AttemptingToDiscover"); + StatusText = Resources.Resources.GetString("Status_AttemptingToDiscover"); break; case DiscoveryStatus.LookingForDeviceOnConnection: - StatusText = OSDPBench.Core.Resources.Resources.GetString("Status_AttemptingToDiscoverAtBaudRate").Replace("{0}", current.Connection.BaudRate.ToString()); + StatusText = Resources.Resources.GetString("Status_AttemptingToDiscoverAtBaudRate").Replace("{0}", current.Connection.BaudRate.ToString()); break; case DiscoveryStatus.ConnectionWithDeviceFound: - StatusText = OSDPBench.Core.Resources.Resources.GetString("Status_FoundDeviceAtBaudRate").Replace("{0}", current.Connection.BaudRate.ToString()); + StatusText = Resources.Resources.GetString("Status_FoundDeviceAtBaudRate").Replace("{0}", current.Connection.BaudRate.ToString()); break; case DiscoveryStatus.LookingForDeviceAtAddress: - StatusText = OSDPBench.Core.Resources.Resources.GetString("Status_AttemptingToDetermineDevice").Replace("{0}", current.Connection.BaudRate.ToString()).Replace("{1}", current.Address.ToString()); + StatusText = Resources.Resources.GetString("Status_AttemptingToDetermineDevice").Replace("{0}", current.Connection.BaudRate.ToString()).Replace("{1}", current.Address.ToString()); break; case DiscoveryStatus.DeviceIdentified: - StatusText = OSDPBench.Core.Resources.Resources.GetString("Status_AttemptingToIdentifyDevice").Replace("{0}", current.Connection.BaudRate.ToString()).Replace("{1}", current.Address.ToString()); + StatusText = Resources.Resources.GetString("Status_AttemptingToIdentifyDevice").Replace("{0}", current.Connection.BaudRate.ToString()).Replace("{1}", current.Address.ToString()); break; case DiscoveryStatus.CapabilitiesDiscovered: - StatusText = OSDPBench.Core.Resources.Resources.GetString("Status_AttemptingToGetCapabilities").Replace("{0}", current.Connection.BaudRate.ToString()).Replace("{1}", current.Address.ToString()); + StatusText = Resources.Resources.GetString("Status_AttemptingToGetCapabilities").Replace("{0}", current.Connection.BaudRate.ToString()).Replace("{1}", current.Address.ToString()); break; case DiscoveryStatus.Succeeded: @@ -258,18 +257,18 @@ private void UpdateDiscoveryStatus(DiscoveryResult current) break; case DiscoveryStatus.DeviceNotFound: - StatusText = OSDPBench.Core.Resources.Resources.GetString("Status_FailedToConnect"); + StatusText = Resources.Resources.GetString("Status_FailedToConnect"); StatusLevel = StatusLevel.Error; break; case DiscoveryStatus.Error: - StatusText = OSDPBench.Core.Resources.Resources.GetString("Status_ErrorWhileDiscovering"); + StatusText = Resources.Resources.GetString("Status_ErrorWhileDiscovering"); StatusLevel = StatusLevel.Error; break; case DiscoveryStatus.Cancelled: StatusLevel = StatusLevel.Error; - StatusText = OSDPBench.Core.Resources.Resources.GetString("Status_CancelledDiscovery"); + StatusText = Resources.Resources.GetString("Status_CancelledDiscovery"); break; default: @@ -279,7 +278,7 @@ private void UpdateDiscoveryStatus(DiscoveryResult current) private void HandleSuccessfulDiscovery(DiscoveryResult result) { - StatusText = OSDPBench.Core.Resources.Resources.GetString("Status_SuccessfullyDiscovered").Replace("{0}", result.Connection.BaudRate.ToString()).Replace("{1}", result.Address.ToString()); + StatusText = Resources.Resources.GetString("Status_SuccessfullyDiscovered").Replace("{0}", result.Connection.BaudRate.ToString()).Replace("{1}", result.Address.ToString()); StatusLevel = StatusLevel.Discovered; if (result.Connection is ISerialPortConnectionService service) @@ -298,7 +297,7 @@ private async Task ConnectDevice() string serialPortName = SelectedSerialPort?.Name ?? string.Empty; StatusLevel = StatusLevel.ConnectingManually; - StatusText = OSDPBench.Core.Resources.Resources.GetString("Status_AttemptingToConnectManually"); + StatusText = Resources.Resources.GetString("Status_AttemptingToConnectManually"); byte[]? securityKey = await GetSecurityKey(); if (securityKey == null && !UseDefaultKey) return; @@ -317,8 +316,8 @@ private async Task ConnectDevice() catch (Exception exception) { await _dialogService.ShowMessageDialog( - OSDPBench.Core.Resources.Resources.GetString("Dialog_Connect_Title"), - OSDPBench.Core.Resources.Resources.GetString("Dialog_InvalidSecurityKeyMessage").Replace("{0}", exception.Message), + Resources.Resources.GetString("Dialog_Connect_Title"), + Resources.Resources.GetString("Dialog_InvalidSecurityKeyMessage").Replace("{0}", exception.Message), MessageIcon.Error); return null; } @@ -343,7 +342,7 @@ await _deviceManagementService.Connect( private async Task DisconnectDevice() { await _deviceManagementService.Shutdown(); - StatusText = OSDPBench.Core.Resources.Resources.GetString("Status_Disconnected"); + StatusText = Resources.Resources.GetString("Status_Disconnected"); StatusLevel = StatusLevel.Disconnected; NakText = string.Empty; _lastPacketEntry = null; @@ -399,23 +398,23 @@ private async void OnUsbDeviceChanged(object? sender, UsbDeviceChangedEventArgs // Show notification based on change type if (e.ChangeType == UsbDeviceChangeType.Connected) { - UsbStatusText = OSDPBench.Core.Resources.Resources.GetString("USB_DeviceConnected"); + UsbStatusText = Resources.Resources.GetString("USB_DeviceConnected"); } else if (e.ChangeType == UsbDeviceChangeType.Disconnected) { - UsbStatusText = OSDPBench.Core.Resources.Resources.GetString("USB_DeviceDisconnected"); + UsbStatusText = Resources.Resources.GetString("USB_DeviceDisconnected"); // If we were connected and the device was removed, update status if (StatusLevel == StatusLevel.Connected && !e.AvailablePorts.Contains(_deviceManagementService.PortName ?? "")) { await _deviceManagementService.Shutdown(); StatusLevel = StatusLevel.Disconnected; - StatusText = OSDPBench.Core.Resources.Resources.GetString("Status_DeviceDisconnectedUSBRemoved"); + StatusText = Resources.Resources.GetString("Status_DeviceDisconnectedUSBRemoved"); } } else { - UsbStatusText = OSDPBench.Core.Resources.Resources.GetString("USB_PortsChanged"); + UsbStatusText = Resources.Resources.GetString("USB_PortsChanged"); } // Clear USB status after 3 seconds @@ -424,7 +423,7 @@ private async void OnUsbDeviceChanged(object? sender, UsbDeviceChangedEventArgs } catch (Exception ex) { - Console.WriteLine(OSDPBench.Core.Resources.Resources.GetString("Error_HandlingUSBDeviceChange").Replace("{0}", ex.Message)); + Console.WriteLine(Resources.Resources.GetString("Error_HandlingUSBDeviceChange").Replace("{0}", ex.Message)); } } diff --git a/src/Core/ViewModels/Pages/ManageViewModel.cs b/src/Core/ViewModels/Pages/ManageViewModel.cs index 3148582..79b230f 100644 --- a/src/Core/ViewModels/Pages/ManageViewModel.cs +++ b/src/Core/ViewModels/Pages/ManageViewModel.cs @@ -5,7 +5,6 @@ using OSDPBench.Core.Actions; using OSDPBench.Core.Models; using OSDPBench.Core.Services; -using OSDPBench.Core.Resources; namespace OSDPBench.Core.ViewModels.Pages; @@ -52,7 +51,7 @@ private async Task ExecuteDeviceAction() { if (SelectedDeviceAction == null) return; - await ExceptionHelper.ExecuteSafelyAsync(_dialogService, OSDPBench.Core.Resources.Resources.GetString("Dialog_PerformingAction_Title"), async () => + await ExceptionHelper.ExecuteSafelyAsync(_dialogService, Resources.Resources.GetString("Dialog_PerformingAction_Title"), async () => { if (SelectedDeviceAction is ResetCypressDeviceAction) { @@ -72,7 +71,7 @@ await ExceptionHelper.ExecuteSafelyAsync(_dialogService, OSDPBench.Core.Resource { return await ExceptionHelper.ExecuteSafelyAsync( _dialogService, - OSDPBench.Core.Resources.Resources.GetString("Dialog_PerformingAction_Title"), + Resources.Resources.GetString("Dialog_PerformingAction_Title"), async () => await _deviceManagementService.ExecuteDeviceAction(SelectedDeviceAction!, DeviceActionParameter), null); } @@ -87,13 +86,13 @@ private async Task HandleSetCommunicationAction(object result) if (!parametersChanged) { - await _dialogService.ShowMessageDialog(OSDPBench.Core.Resources.Resources.GetString("Dialog_UpdateCommunications_Title"), - OSDPBench.Core.Resources.Resources.GetString("Dialog_UpdateCommunications_NoChange"), MessageIcon.Warning); + await _dialogService.ShowMessageDialog(Resources.Resources.GetString("Dialog_UpdateCommunications_Title"), + Resources.Resources.GetString("Dialog_UpdateCommunications_NoChange"), MessageIcon.Warning); return; } - await _dialogService.ShowMessageDialog(OSDPBench.Core.Resources.Resources.GetString("Dialog_UpdateCommunications_Title"), - OSDPBench.Core.Resources.Resources.GetString("Dialog_UpdateCommunications_Success"), MessageIcon.Information); + await _dialogService.ShowMessageDialog(Resources.Resources.GetString("Dialog_UpdateCommunications_Title"), + Resources.Resources.GetString("Dialog_UpdateCommunications_Success"), MessageIcon.Information); if (_deviceManagementService.PortName != null) { await _deviceManagementService.Reconnect(_serialPortConnectionService.GetConnection( @@ -109,7 +108,7 @@ private async Task HandleResetCypressDeviceAction() if (!IdentityLookup.CanSendResetCommand) { await _dialogService.ShowMessageDialog( - OSDPBench.Core.Resources.Resources.GetString("Dialog_ResetDevice_Title"), + Resources.Resources.GetString("Dialog_ResetDevice_Title"), IdentityLookup.ResetInstructions, MessageIcon.Information); return; @@ -118,8 +117,8 @@ await _dialogService.ShowMessageDialog( await _deviceManagementService.Shutdown(); bool userConfirmed = await _dialogService.ShowConfirmationDialog( - OSDPBench.Core.Resources.Resources.GetString("Dialog_ResetDevice_Title"), - OSDPBench.Core.Resources.Resources.GetString("Dialog_ResetDevice_Confirmation"), + Resources.Resources.GetString("Dialog_ResetDevice_Title"), + Resources.Resources.GetString("Dialog_ResetDevice_Confirmation"), MessageIcon.Warning); if (!userConfirmed) @@ -134,7 +133,7 @@ await _deviceManagementService.Reconnect(_serialPortConnectionService.GetConnect return; } - bool success = await ExceptionHelper.ExecuteSafelyAsync(_dialogService, OSDPBench.Core.Resources.Resources.GetString("Dialog_ResetDevice_Title"), async () => + bool success = await ExceptionHelper.ExecuteSafelyAsync(_dialogService, Resources.Resources.GetString("Dialog_ResetDevice_Title"), async () => { if (_deviceManagementService.PortName != null) { @@ -149,15 +148,15 @@ await _deviceManagementService.ExecuteDeviceAction( if (success) { await _dialogService.ShowMessageDialog( - OSDPBench.Core.Resources.Resources.GetString("Dialog_ResetDevice_Title"), - OSDPBench.Core.Resources.Resources.GetString("Dialog_ResetDevice_Success"), + Resources.Resources.GetString("Dialog_ResetDevice_Title"), + Resources.Resources.GetString("Dialog_ResetDevice_Success"), MessageIcon.Information); } else { await _dialogService.ShowMessageDialog( - OSDPBench.Core.Resources.Resources.GetString("Dialog_ResetDevice_Title"), - OSDPBench.Core.Resources.Resources.GetString("Dialog_ResetDevice_Failed"), + Resources.Resources.GetString("Dialog_ResetDevice_Title"), + Resources.Resources.GetString("Dialog_ResetDevice_Failed"), MessageIcon.Error); } } diff --git a/src/UI/Windows/App.xaml.cs b/src/UI/Windows/App.xaml.cs index d2b34ea..37d36be 100644 --- a/src/UI/Windows/App.xaml.cs +++ b/src/UI/Windows/App.xaml.cs @@ -109,7 +109,7 @@ private async void OnStartup(object sender, StartupEventArgs e) await Task.Delay(500); // Run on UI thread to ensure proper dialog display and culture updates - await Application.Current.Dispatcher.InvokeAsync(async () => + await Current.Dispatcher.InvokeAsync(async () => { var languageMismatchService = Host.Services.GetService(); if (languageMismatchService != null) diff --git a/src/UI/Windows/Helpers/CopyTextBoxHelper.cs b/src/UI/Windows/Helpers/CopyTextBoxHelper.cs index 79920ee..6b0479f 100644 --- a/src/UI/Windows/Helpers/CopyTextBoxHelper.cs +++ b/src/UI/Windows/Helpers/CopyTextBoxHelper.cs @@ -1,4 +1,3 @@ -using System; using System.Windows; using System.Windows.Controls; using System.Windows.Input; @@ -42,30 +41,24 @@ public static void SetCopyCommand(DependencyObject obj, ICommand value) }); } -public class RelayCommand : ICommand +public class RelayCommand(Action execute, Func? canExecute = null) + : ICommand { - private readonly Action _execute; - private readonly Func _canExecute; + private readonly Action _execute = execute ?? throw new ArgumentNullException(nameof(execute)); - public RelayCommand(Action execute, Func canExecute = null) + public event EventHandler? CanExecuteChanged { - _execute = execute ?? throw new ArgumentNullException(nameof(execute)); - _canExecute = canExecute; + add => CommandManager.RequerySuggested += value; + remove => CommandManager.RequerySuggested -= value; } - public event EventHandler CanExecuteChanged + public bool CanExecute(object? parameter) { - add { CommandManager.RequerySuggested += value; } - remove { CommandManager.RequerySuggested -= value; } + return parameter != null && (canExecute?.Invoke(parameter) ?? true); } - public bool CanExecute(object parameter) + public void Execute(object? parameter) { - return _canExecute?.Invoke(parameter) ?? true; - } - - public void Execute(object parameter) - { - _execute(parameter); + if (parameter != null) _execute(parameter); } } \ No newline at end of file diff --git a/src/UI/Windows/Markup/LocalizeExtension.cs b/src/UI/Windows/Markup/LocalizeExtension.cs index 4270f54..84c3227 100644 --- a/src/UI/Windows/Markup/LocalizeExtension.cs +++ b/src/UI/Windows/Markup/LocalizeExtension.cs @@ -1,4 +1,3 @@ -using System.Globalization; using System.Windows.Markup; using System.Windows.Data; using OSDPBench.Core.Resources; diff --git a/src/UI/Windows/Markup/LocalizedStringBinding.cs b/src/UI/Windows/Markup/LocalizedStringBinding.cs index 97cba19..59074f4 100644 --- a/src/UI/Windows/Markup/LocalizedStringBinding.cs +++ b/src/UI/Windows/Markup/LocalizedStringBinding.cs @@ -1,6 +1,4 @@ using System.ComponentModel; -using System.Windows; -using System.Windows.Data; namespace OSDPBench.Windows.Markup; @@ -16,10 +14,10 @@ public LocalizedStringBinding(string key) _key = key; // Subscribe to culture changes - OSDPBench.Core.Resources.Resources.PropertyChanged += OnResourcesPropertyChanged; + Core.Resources.Resources.PropertyChanged += OnResourcesPropertyChanged; } - public string Value => OSDPBench.Core.Resources.Resources.GetString(_key); + public string Value => Core.Resources.Resources.GetString(_key); private void OnResourcesPropertyChanged(object? sender, PropertyChangedEventArgs e) { @@ -31,6 +29,6 @@ private void OnResourcesPropertyChanged(object? sender, PropertyChangedEventArgs ~LocalizedStringBinding() { - OSDPBench.Core.Resources.Resources.PropertyChanged -= OnResourcesPropertyChanged; + Core.Resources.Resources.PropertyChanged -= OnResourcesPropertyChanged; } } \ No newline at end of file diff --git a/src/UI/Windows/Services/WindowsDialogService.cs b/src/UI/Windows/Services/WindowsDialogService.cs index b6418d8..3e7fe9b 100644 --- a/src/UI/Windows/Services/WindowsDialogService.cs +++ b/src/UI/Windows/Services/WindowsDialogService.cs @@ -45,8 +45,6 @@ public Task ShowExceptionDialog(string title, Exception exception) private static string FormatExceptionMessage(Exception exception) { - if (exception == null) return "Unknown error occurred."; - return $"{exception.Message}\n\nDetails: {exception.GetType().Name}"; } } \ No newline at end of file diff --git a/src/UI/Windows/Services/WindowsLanguageMismatchService.cs b/src/UI/Windows/Services/WindowsLanguageMismatchService.cs index 64cab26..7bbd450 100644 --- a/src/UI/Windows/Services/WindowsLanguageMismatchService.cs +++ b/src/UI/Windows/Services/WindowsLanguageMismatchService.cs @@ -7,27 +7,23 @@ namespace OSDPBench.Windows.Services; /// -/// Windows-specific implementation of language mismatch service with custom dialog support +/// Windows-specific implementation of the language mismatch service with custom dialog support /// public class WindowsLanguageMismatchService : ILanguageMismatchService { private readonly ILocalizationService _localizationService; - private readonly IDialogService _dialogService; private readonly IUserSettingsService _userSettingsService; /// /// Initializes a new instance of the WindowsLanguageMismatchService /// /// The localization service - /// The dialog service /// The user settings service public WindowsLanguageMismatchService( ILocalizationService localizationService, - IDialogService dialogService, IUserSettingsService userSettingsService) { _localizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService)); - _dialogService = dialogService ?? throw new ArgumentNullException(nameof(dialogService)); _userSettingsService = userSettingsService ?? throw new ArgumentNullException(nameof(userSettingsService)); } @@ -43,38 +39,26 @@ public async Task CheckAndPromptForLanguageMismatchAsync() return; } - System.Diagnostics.Debug.WriteLine($"LanguageMismatchService: User has preferred culture: {_userSettingsService.Settings.PreferredCulture}"); - - // Check if user has disabled language mismatch checking + // Check if the user has disabled language mismatch checking if (_userSettingsService.Settings.SkipLanguageMismatchCheck) { - System.Diagnostics.Debug.WriteLine("LanguageMismatchService: User has disabled checks - skipping"); return; } // Check if there's a mismatch var systemCulture = _localizationService.GetSystemCulture(); - var currentCulture = _localizationService.CurrentCulture; var isMatch = _localizationService.IsSystemLanguageMatch(); - System.Diagnostics.Debug.WriteLine($"LanguageMismatchService: System culture: {systemCulture.Name} ({systemCulture.NativeName})"); - System.Diagnostics.Debug.WriteLine($"LanguageMismatchService: Current culture: {currentCulture.Name}"); - System.Diagnostics.Debug.WriteLine($"LanguageMismatchService: Is match: {isMatch}"); - if (isMatch) { - System.Diagnostics.Debug.WriteLine("LanguageMismatchService: Languages match - no action needed"); return; } - System.Diagnostics.Debug.WriteLine("LanguageMismatchService: Language mismatch detected - showing dialog"); var systemLanguageName = systemCulture.NativeName; // Show custom dialog var (userWantsToSwitch, dontAskAgain) = await ShowLanguageMismatchDialogAsync(systemLanguageName); - - System.Diagnostics.Debug.WriteLine($"LanguageMismatchService: Dialog result - Switch: {userWantsToSwitch}, DontAsk: {dontAskAgain}"); - + // Save the "don't ask again" preference if (dontAskAgain) { @@ -104,10 +88,11 @@ await Application.Current.Dispatcher.InvokeAsync(() => var message = _localizationService.GetString("Language_SystemMismatchMessage", systemLanguageName); Window? dialogWindow = null; + var window = dialogWindow; var viewModel = new LanguageMismatchDialogViewModel(message, (userChoice, dontAsk) => { tcs.SetResult((userChoice, dontAsk)); - dialogWindow?.Close(); + window?.Close(); }); var dialogContent = new LanguageMismatchDialog @@ -142,7 +127,7 @@ await Application.Current.Dispatcher.InvokeAsync(() => { var supportedCultures = _localizationService.SupportedCultures; - // First try exact match + // First try the exact match var exactMatch = supportedCultures.FirstOrDefault(c => c.Name == systemCulture.Name); if (exactMatch != null) return exactMatch; diff --git a/src/UI/Windows/Services/WindowsUsbDeviceMonitorService.cs b/src/UI/Windows/Services/WindowsUsbDeviceMonitorService.cs index 76e4dfc..5d9d2e4 100644 --- a/src/UI/Windows/Services/WindowsUsbDeviceMonitorService.cs +++ b/src/UI/Windows/Services/WindowsUsbDeviceMonitorService.cs @@ -1,24 +1,19 @@ -using System; -using System.Collections.Generic; using System.IO.Ports; -using System.Linq; using System.Management; -using System.Threading; -using System.Threading.Tasks; using OSDPBench.Core.Services; namespace OSDPBench.Windows.Services; /// -/// Windows implementation of USB device monitoring service using WMI events and polling. +/// Windows implementation of the USB device monitoring service using WMI events and polling. /// -public class WindowsUsbDeviceMonitorService : IUsbDeviceMonitorService +public sealed class WindowsUsbDeviceMonitorService : IUsbDeviceMonitorService { private readonly SynchronizationContext? _synchronizationContext; private ManagementEventWatcher? _deviceInsertWatcher; private ManagementEventWatcher? _deviceRemoveWatcher; private Timer? _pollingTimer; - private HashSet _previousPorts = new(); + private HashSet _previousPorts; private bool _isDisposed; private readonly object _lock = new(); @@ -54,15 +49,9 @@ public void StartMonitoring() IsMonitoring = true; } - catch (Exception ex) + catch (Exception) { - // If WMI fails, continue with polling only - Console.WriteLine($"WMI monitoring failed to start: {ex.Message}. Falling back to polling only."); - - if (_pollingTimer == null) - { - _pollingTimer = new Timer(OnPollingTimerElapsed, null, TimeSpan.Zero, TimeSpan.FromSeconds(2)); - } + _pollingTimer ??= new Timer(OnPollingTimerElapsed, null, TimeSpan.Zero, TimeSpan.FromSeconds(2)); IsMonitoring = true; } @@ -84,54 +73,39 @@ public void StopMonitoring() IsMonitoring = false; } } - + private void StartWmiMonitoring() { - try - { - // Query for USB serial port device insertion - var insertQuery = new WqlEventQuery("SELECT * FROM __InstanceCreationEvent WITHIN 2 " + - "WHERE TargetInstance ISA 'Win32_PnPEntity' " + - "AND (TargetInstance.PNPClass = 'Ports' OR TargetInstance.PNPClass = 'USB')"); - - _deviceInsertWatcher = new ManagementEventWatcher(insertQuery); - _deviceInsertWatcher.EventArrived += OnDeviceInserted; - _deviceInsertWatcher.Start(); - - // Query for USB serial port device removal - var removeQuery = new WqlEventQuery("SELECT * FROM __InstanceDeletionEvent WITHIN 2 " + - "WHERE TargetInstance ISA 'Win32_PnPEntity' " + - "AND (TargetInstance.PNPClass = 'Ports' OR TargetInstance.PNPClass = 'USB')"); - - _deviceRemoveWatcher = new ManagementEventWatcher(removeQuery); - _deviceRemoveWatcher.EventArrived += OnDeviceRemoved; - _deviceRemoveWatcher.Start(); - } - catch (Exception ex) - { - Console.WriteLine($"Failed to start WMI monitoring: {ex.Message}"); - throw; - } + // Query for USB serial port device insertion + var insertQuery = new WqlEventQuery("SELECT * FROM __InstanceCreationEvent WITHIN 2 " + + "WHERE TargetInstance ISA 'Win32_PnPEntity' " + + "AND (TargetInstance.PNPClass = 'Ports' OR TargetInstance.PNPClass = 'USB')"); + + _deviceInsertWatcher = new ManagementEventWatcher(insertQuery); + _deviceInsertWatcher.EventArrived += OnDeviceInserted; + _deviceInsertWatcher.Start(); + + // Query for USB serial port device removal + var removeQuery = new WqlEventQuery("SELECT * FROM __InstanceDeletionEvent WITHIN 2 " + + "WHERE TargetInstance ISA 'Win32_PnPEntity' " + + "AND (TargetInstance.PNPClass = 'Ports' OR TargetInstance.PNPClass = 'USB')"); + + _deviceRemoveWatcher = new ManagementEventWatcher(removeQuery); + _deviceRemoveWatcher.EventArrived += OnDeviceRemoved; + _deviceRemoveWatcher.Start(); } - + private void StopWmiMonitoring() { - try - { - _deviceInsertWatcher?.Stop(); - _deviceInsertWatcher?.Dispose(); - _deviceInsertWatcher = null; - - _deviceRemoveWatcher?.Stop(); - _deviceRemoveWatcher?.Dispose(); - _deviceRemoveWatcher = null; - } - catch (Exception ex) - { - Console.WriteLine($"Error stopping WMI monitoring: {ex.Message}"); - } + _deviceInsertWatcher?.Stop(); + _deviceInsertWatcher?.Dispose(); + _deviceInsertWatcher = null; + + _deviceRemoveWatcher?.Stop(); + _deviceRemoveWatcher?.Dispose(); + _deviceRemoveWatcher = null; } - + private void OnDeviceInserted(object sender, EventArrivedEventArgs e) { Task.Run(() => CheckForPortChanges(UsbDeviceChangeType.Connected)); @@ -146,53 +120,45 @@ private void OnPollingTimerElapsed(object? state) { CheckForPortChanges(UsbDeviceChangeType.Unknown); } - + private void CheckForPortChanges(UsbDeviceChangeType suggestedChangeType) { - try + var currentPorts = new HashSet(SerialPort.GetPortNames()); + + lock (_lock) { - var currentPorts = new HashSet(SerialPort.GetPortNames()); - - lock (_lock) + // Check if there are any changes + var addedPorts = currentPorts.Except(_previousPorts).ToArray(); + var removedPorts = _previousPorts.Except(currentPorts).ToArray(); + + if (addedPorts.Any() && removedPorts.Any()) return; + + // Determine the actual change type + UsbDeviceChangeType actualChangeType; + if (addedPorts.Any() && !removedPorts.Any()) { - // Check if there are any changes - var addedPorts = currentPorts.Except(_previousPorts).ToList(); - var removedPorts = _previousPorts.Except(currentPorts).ToList(); - - if (addedPorts.Any() || removedPorts.Any()) - { - // Determine the actual change type - UsbDeviceChangeType actualChangeType; - if (addedPorts.Any() && !removedPorts.Any()) - { - actualChangeType = UsbDeviceChangeType.Connected; - } - else if (removedPorts.Any() && !addedPorts.Any()) - { - actualChangeType = UsbDeviceChangeType.Disconnected; - } - else - { - // Both added and removed - use suggested or Unknown - actualChangeType = suggestedChangeType != UsbDeviceChangeType.Unknown - ? suggestedChangeType - : UsbDeviceChangeType.Unknown; - } - - _previousPorts = currentPorts; - - // Raise event on the UI thread if possible - var eventArgs = new UsbDeviceChangedEventArgs(actualChangeType, currentPorts.ToList()); - RaiseUsbDeviceChanged(eventArgs); - } + actualChangeType = UsbDeviceChangeType.Connected; } - } - catch (Exception ex) - { - Console.WriteLine($"Error checking for port changes: {ex.Message}"); + else if (removedPorts.Any() && !addedPorts.Any()) + { + actualChangeType = UsbDeviceChangeType.Disconnected; + } + else + { + // Both added and removed - use suggested or Unknown + actualChangeType = suggestedChangeType != UsbDeviceChangeType.Unknown + ? suggestedChangeType + : UsbDeviceChangeType.Unknown; + } + + _previousPorts = currentPorts; + + // Raise event on the UI thread if possible + var eventArgs = new UsbDeviceChangedEventArgs(actualChangeType, currentPorts.ToList()); + RaiseUsbDeviceChanged(eventArgs); } } - + private void RaiseUsbDeviceChanged(UsbDeviceChangedEventArgs e) { if (_synchronizationContext != null) @@ -209,13 +175,12 @@ private void RaiseUsbDeviceChanged(UsbDeviceChangedEventArgs e) public void Dispose() { Dispose(true); - GC.SuppressFinalize(this); } /// /// Releases unmanaged and - optionally - managed resources. /// - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (_isDisposed) return; diff --git a/src/UI/Windows/Styles/ComponentStyles.xaml b/src/UI/Windows/Styles/ComponentStyles.xaml index 811d27a..c16cca4 100644 --- a/src/UI/Windows/Styles/ComponentStyles.xaml +++ b/src/UI/Windows/Styles/ComponentStyles.xaml @@ -165,6 +165,7 @@ + + + + @@ -112,17 +116,17 @@ - + - @@ -197,11 +201,11 @@ diff --git a/src/UI/Windows/Styles/DesignTokens.xaml b/src/UI/Windows/Styles/DesignTokens.xaml index 8788d7b..8c2be05 100644 --- a/src/UI/Windows/Styles/DesignTokens.xaml +++ b/src/UI/Windows/Styles/DesignTokens.xaml @@ -37,12 +37,17 @@ 32 36 - + + + + + + diff --git a/src/UI/Windows/Styles/LayoutTemplates.xaml b/src/UI/Windows/Styles/LayoutTemplates.xaml index ad7fd65..0bdfce1 100644 --- a/src/UI/Windows/Styles/LayoutTemplates.xaml +++ b/src/UI/Windows/Styles/LayoutTemplates.xaml @@ -62,16 +62,16 @@ diff --git a/src/UI/Windows/Styles/ThemeSemanticColors.xaml b/src/UI/Windows/Styles/ThemeSemanticColors.xaml new file mode 100644 index 0000000..196a4ee --- /dev/null +++ b/src/UI/Windows/Styles/ThemeSemanticColors.xaml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/UI/Windows/Views/Controls/LedControl.xaml b/src/UI/Windows/Views/Controls/LedControl.xaml index 3295eca..28be798 100644 --- a/src/UI/Windows/Views/Controls/LedControl.xaml +++ b/src/UI/Windows/Views/Controls/LedControl.xaml @@ -9,9 +9,9 @@ + Fill="{DynamicResource SemanticErrorBrush}"> - + diff --git a/src/UI/Windows/Views/Pages/ConnectPage.xaml b/src/UI/Windows/Views/Pages/ConnectPage.xaml index c384d62..fc075a8 100644 --- a/src/UI/Windows/Views/Pages/ConnectPage.xaml +++ b/src/UI/Windows/Views/Pages/ConnectPage.xaml @@ -25,7 +25,7 @@ Template="{StaticResource Template.PageHeader}"/> - @@ -73,7 +73,7 @@ - + @@ -186,11 +183,8 @@ Padding="16" Margin="0,0,0,16"> - + Date: Wed, 2 Jul 2025 15:02:52 -0400 Subject: [PATCH 23/40] Move connection status next to the LED indicators --- src/UI/Windows/Styles/LayoutTemplates.xaml | 94 +++++++++++++++------ src/UI/Windows/Views/Pages/ConnectPage.xaml | 13 --- 2 files changed, 69 insertions(+), 38 deletions(-) diff --git a/src/UI/Windows/Styles/LayoutTemplates.xaml b/src/UI/Windows/Styles/LayoutTemplates.xaml index 0bdfce1..cfcfcd1 100644 --- a/src/UI/Windows/Styles/LayoutTemplates.xaml +++ b/src/UI/Windows/Styles/LayoutTemplates.xaml @@ -11,34 +11,78 @@ + + + - - - - - - - - - + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UI/Windows/Views/Pages/ConnectPage.xaml b/src/UI/Windows/Views/Pages/ConnectPage.xaml index fc075a8..226814b 100644 --- a/src/UI/Windows/Views/Pages/ConnectPage.xaml +++ b/src/UI/Windows/Views/Pages/ConnectPage.xaml @@ -115,19 +115,6 @@ ItemsSource="{Binding ConnectionTypes}" SelectedIndex="{Binding SelectedConnectionTypeIndex, Mode=TwoWay}"/> - - - - - - - - - - From 2b713f1826a012c9156787961a56dde4a5b9f1e6 Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Wed, 2 Jul 2025 15:14:52 -0400 Subject: [PATCH 24/40] New translations resources.resx (French) --- src/Core/Resources/Resources.fr.resx | 36 ---------------------------- 1 file changed, 36 deletions(-) diff --git a/src/Core/Resources/Resources.fr.resx b/src/Core/Resources/Resources.fr.resx index 2f1a7bb..6821d4a 100644 --- a/src/Core/Resources/Resources.fr.resx +++ b/src/Core/Resources/Resources.fr.resx @@ -122,36 +122,12 @@ Coupé Device connection status when not connected - - Découvrir - Device connection status during discovery process - Erreur Device connection status when an error occurred - - Périphérique USB inséré - Message shown when a USB device is detected - - - Périphérique USB supprimé - Message shown when a USB device is disconnected - - - Échec de la connexion - Generic connection failure message - - - Appareil introuvable - Error when device cannot be found during discovery - - - Adresse invalide - Error when the entered address is invalid - N° de série - @@ -314,10 +290,6 @@ Type Column header for type in monitoring grid - - Détails - Column header for details in monitoring grid - Développer Button text to expand row details @@ -472,10 +444,6 @@ Périphérique USB déconnecté Message when USB device is disconnected - - Ports USB modifiés - Message when USB ports have changed - Relier @@ -557,10 +525,6 @@ Sélectionner une langue Tooltip for language selection - - Changement de langue réussi - Confirmation message when language is changed - System Language Detected Title for system language mismatch dialog From 6e04687fe551359de2a466544603f584102f2b2c Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Wed, 2 Jul 2025 15:14:53 -0400 Subject: [PATCH 25/40] New translations resources.resx (Spanish) --- src/Core/Resources/Resources.es.resx | 36 ---------------------------- 1 file changed, 36 deletions(-) diff --git a/src/Core/Resources/Resources.es.resx b/src/Core/Resources/Resources.es.resx index abe53e6..0adb3ed 100644 --- a/src/Core/Resources/Resources.es.resx +++ b/src/Core/Resources/Resources.es.resx @@ -122,36 +122,12 @@ Desconectar Device connection status when not connected - - Descubriendo - Device connection status during discovery process - Error Device connection status when an error occurred - - Dispositivo USB conectado - Message shown when a USB device is detected - - - Dispositivo USB extraído - Message shown when a USB device is disconnected - - - Error de conexión - Generic connection failure message - - - Dispositivo no encontrado - Error when device cannot be found during discovery - - - Dirección no válida - Error when the entered address is invalid - S/N - @@ -314,10 +290,6 @@ Tipo Column header for type in monitoring grid - - Detalles - Column header for details in monitoring grid - Expandir Button text to expand row details @@ -472,10 +444,6 @@ Dispositivo USB desconectado Message when USB device is disconnected - - Puertos USB cambiados - Message when USB ports have changed - Conectar @@ -557,10 +525,6 @@ Seleccionar idioma Tooltip for language selection - - El lenguaje cambió con éxito - Confirmation message when language is changed - System Language Detected Title for system language mismatch dialog From 20ce5bae4a3344489575138cca7b573572b0b0a3 Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Wed, 2 Jul 2025 15:14:54 -0400 Subject: [PATCH 26/40] New translations resources.resx (German) --- src/Core/Resources/Resources.de.resx | 36 ---------------------------- 1 file changed, 36 deletions(-) diff --git a/src/Core/Resources/Resources.de.resx b/src/Core/Resources/Resources.de.resx index fc10b6e..b9ff0ce 100644 --- a/src/Core/Resources/Resources.de.resx +++ b/src/Core/Resources/Resources.de.resx @@ -122,36 +122,12 @@ Entfernt Device connection status when not connected - - Entdeckend - Device connection status during discovery process - Fehler Device connection status when an error occurred - - USB-Gerät eingesteckt - Message shown when a USB device is detected - - - USB-Gerät entfernt - Message shown when a USB device is disconnected - - - Verbindung fehlgeschlagen - Generic connection failure message - - - Gerät nicht gefunden - Error when device cannot be found during discovery - - - Ungültige Adresse - Error when the entered address is invalid - S/N - @@ -314,10 +290,6 @@ Art Column header for type in monitoring grid - - Details - Column header for details in monitoring grid - Erweitern Button text to expand row details @@ -472,10 +444,6 @@ USB-Gerät getrennt Message when USB device is disconnected - - USB-Anschlüsse geändert - Message when USB ports have changed - Verbinden @@ -557,10 +525,6 @@ Sprache auswählen Tooltip for language selection - - Sprache erfolgreich geändert - Confirmation message when language is changed - System Language Detected Title for system language mismatch dialog From bfccb9606365d6279ec4eb16967f1a7164c1fd07 Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Wed, 2 Jul 2025 15:14:55 -0400 Subject: [PATCH 27/40] New translations resources.resx (Japanese) --- src/Core/Resources/Resources.ja.resx | 36 ---------------------------- 1 file changed, 36 deletions(-) diff --git a/src/Core/Resources/Resources.ja.resx b/src/Core/Resources/Resources.ja.resx index 540caf6..d12a49b 100644 --- a/src/Core/Resources/Resources.ja.resx +++ b/src/Core/Resources/Resources.ja.resx @@ -122,36 +122,12 @@ 途切れ途切れ Device connection status when not connected - - 発見 - Device connection status during discovery process - エラー Device connection status when an error occurred - - USBデバイスが挿入されています - Message shown when a USB device is detected - - - USBデバイスを取り外しました - Message shown when a USB device is disconnected - - - 接続に失敗しました - Generic connection failure message - - - デバイスが見つかりません - Error when device cannot be found during discovery - - - 無効なアドレス - Error when the entered address is invalid - S/N - @@ -314,10 +290,6 @@ 種類 Column header for type in monitoring grid - - 細部 - Column header for details in monitoring grid - 膨らむ Button text to expand row details @@ -472,10 +444,6 @@ USBデバイスが切断されました Message when USB device is disconnected - - USBポートの変更 - Message when USB ports have changed - 繋ぐ @@ -557,10 +525,6 @@ 言語の選択 Tooltip for language selection - - 言語が正常に変更されました - Confirmation message when language is changed - System Language Detected Title for system language mismatch dialog From d6d9ae3bad53d3f8e72e4863d9f31b3e17624260 Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Wed, 2 Jul 2025 15:14:57 -0400 Subject: [PATCH 28/40] New translations resources.resx (Chinese Simplified) --- src/Core/Resources/Resources.zh.resx | 36 ---------------------------- 1 file changed, 36 deletions(-) diff --git a/src/Core/Resources/Resources.zh.resx b/src/Core/Resources/Resources.zh.resx index 0b50d90..ef69365 100644 --- a/src/Core/Resources/Resources.zh.resx +++ b/src/Core/Resources/Resources.zh.resx @@ -122,36 +122,12 @@ 断开 Device connection status when not connected - - 发现 - Device connection status during discovery process - 错误 Device connection status when an error occurred - - 已插入 USB 设备 - Message shown when a USB device is detected - - - 已删除 USB 设备 - Message shown when a USB device is disconnected - - - 连接失败 - Generic connection failure message - - - 未找到设备 - Error when device cannot be found during discovery - - - 地址无效 - Error when the entered address is invalid - 序列号 - @@ -314,10 +290,6 @@ 类型 Column header for type in monitoring grid - - - Column header for details in monitoring grid - 扩大 Button text to expand row details @@ -472,10 +444,6 @@ USB 设备已断开连接 Message when USB device is disconnected - - USB 端口已更改 - Message when USB ports have changed - 连接 @@ -557,10 +525,6 @@ 选择语言 Tooltip for language selection - - 语言更改成功 - Confirmation message when language is changed - System Language Detected Title for system language mismatch dialog From ee59e86696e2e73a9ce54870d4dd1a816a635f99 Mon Sep 17 00:00:00 2001 From: Jonathan Horvath Date: Fri, 4 Jul 2025 18:34:55 -0400 Subject: [PATCH 29/40] Move the connection info next to the activity LEDs --- src/Core/Resources/Resources.de.resx | 6 +- src/Core/Resources/Resources.es.resx | 6 +- src/Core/Resources/Resources.fr.resx | 6 +- src/Core/Resources/Resources.ja.resx | 6 +- src/Core/Resources/Resources.resx | 6 +- src/Core/Resources/Resources.zh.resx | 6 +- src/UI/UsbSerialForAndroid/.gitattributes | 63 -- src/UI/UsbSerialForAndroid/.gitignore | 248 ------- src/UI/UsbSerialForAndroid/LICENSE.txt | 22 - src/UI/UsbSerialForAndroid/README.md | 107 --- .../Assets/AboutAssets.txt | 19 - .../GettingStarted.Xamarin | 4 - .../UsbSerialExampleApp/MainActivity.cs | 222 ------ .../Properties/AndroidManifest.xml | 5 - .../Properties/AssemblyInfo.cs | 30 - .../Resources/AboutResources.txt | 44 -- .../Resources/Resource.Designer.cs | 169 ----- .../Resources/drawable/Icon.png | Bin 4147 -> 0 bytes .../Resources/layout/Main.axml | 35 - .../Resources/layout/serial_console.axml | 44 -- .../Resources/values/Strings.xml | 7 - .../Resources/xml/device_filter.xml | 33 - .../SerialConsoleActivity.cs | 179 ----- .../UsbSerialExampleApp.csproj | 99 --- .../UsbSerialForAndroid.sln | 30 - .../Extensions/AsyncExtensions.cs | 28 - .../Extensions/BufferExtensions.cs | 58 -- .../Extensions/EventHandlerExtensions.cs | 25 - .../Extensions/SerialDataReceivedArgs.cs | 21 - .../Extensions/SerialInputOutputManager.cs | 166 ----- .../Extensions/UsbManagerExtensions.cs | 58 -- .../Extensions/UsbSerialPortInfo.cs | 86 --- .../Properties/AssemblyInfo.cs | 28 - .../Resources/AboutResources.txt | 44 -- .../Resources/Resource.Designer.cs | 59 -- .../Resources/Values/Strings.xml | 5 - .../UsbSerialForAndroid.csproj | 87 --- .../UsbSerialForAndroid/Util/HexDump.cs | 146 ---- .../driver/CdcAcmSerialDriver.cs | 509 -------------- .../driver/Ch34xSerialDriver.cs | 379 ---------- .../driver/CommonUsbSerialPort.cs | 139 ---- .../driver/Cp21xxSerialDriver.cs | 373 ---------- .../driver/FtdiSerialDriver.cs | 489 ------------- .../UsbSerialForAndroid/driver/Parity.cs | 26 - .../UsbSerialForAndroid/driver/ProbeTable.cs | 79 --- .../driver/ProlificSerialDriver.cs | 659 ------------------ .../driver/STM32SerialDriver.cs | 309 -------- .../UsbSerialForAndroid/driver/UsbId.cs | 88 --- .../driver/UsbSerialDriver.cs | 43 -- .../driver/UsbSerialPort.cs | 209 ------ .../driver/UsbSerialProber.cs | 103 --- .../driver/UsbSerialRuntimeException.cs | 36 - .../UsbSerialForAndroid/driver/UsbSupport.cs | 43 -- .../UsbSerialForAndroid/azure-pipelines.yml | 27 - src/UI/Windows/Views/Pages/InfoPage.xaml | 12 +- src/UI/Windows/Views/Pages/ManagePage.xaml | 48 +- src/UI/Windows/Views/Pages/MonitorPage.xaml | 32 +- 57 files changed, 35 insertions(+), 5775 deletions(-) delete mode 100644 src/UI/UsbSerialForAndroid/.gitattributes delete mode 100644 src/UI/UsbSerialForAndroid/.gitignore delete mode 100644 src/UI/UsbSerialForAndroid/LICENSE.txt delete mode 100644 src/UI/UsbSerialForAndroid/README.md delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Assets/AboutAssets.txt delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialExampleApp/GettingStarted.Xamarin delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialExampleApp/MainActivity.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Properties/AndroidManifest.xml delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Properties/AssemblyInfo.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/AboutResources.txt delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/Resource.Designer.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/drawable/Icon.png delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/layout/Main.axml delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/layout/serial_console.axml delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/values/Strings.xml delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/xml/device_filter.xml delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialExampleApp/SerialConsoleActivity.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialExampleApp/UsbSerialExampleApp.csproj delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid.sln delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/Extensions/AsyncExtensions.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/Extensions/BufferExtensions.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/Extensions/EventHandlerExtensions.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/Extensions/SerialDataReceivedArgs.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/Extensions/SerialInputOutputManager.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/Extensions/UsbManagerExtensions.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/Extensions/UsbSerialPortInfo.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/Properties/AssemblyInfo.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/Resources/AboutResources.txt delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/Resources/Resource.Designer.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/Resources/Values/Strings.xml delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/UsbSerialForAndroid.csproj delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/Util/HexDump.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/driver/CdcAcmSerialDriver.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/driver/Ch34xSerialDriver.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/driver/CommonUsbSerialPort.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/driver/Cp21xxSerialDriver.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/driver/FtdiSerialDriver.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/driver/Parity.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/driver/ProbeTable.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/driver/ProlificSerialDriver.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/driver/STM32SerialDriver.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/driver/UsbId.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/driver/UsbSerialDriver.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/driver/UsbSerialPort.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/driver/UsbSerialProber.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/driver/UsbSerialRuntimeException.cs delete mode 100644 src/UI/UsbSerialForAndroid/UsbSerialForAndroid/driver/UsbSupport.cs delete mode 100644 src/UI/UsbSerialForAndroid/azure-pipelines.yml diff --git a/src/Core/Resources/Resources.de.resx b/src/Core/Resources/Resources.de.resx index 7e1061e..9619b4f 100644 --- a/src/Core/Resources/Resources.de.resx +++ b/src/Core/Resources/Resources.de.resx @@ -134,9 +134,9 @@ Prefix for device serial number display - - Gerät, das an der Adresse verbunden ist {0} mit einer Baudrate von {1} - Format string for displaying connection details. {0} = address, {1} = baud rate + + Adresse {0} bei {1} + Brief connection status format. {0} = address, {1} = baud rate diff --git a/src/Core/Resources/Resources.es.resx b/src/Core/Resources/Resources.es.resx index a0c34b1..d530a3f 100644 --- a/src/Core/Resources/Resources.es.resx +++ b/src/Core/Resources/Resources.es.resx @@ -134,9 +134,9 @@ Prefix for device serial number display - - Dispositivo conectado a la dirección {0} funcionando a una velocidad de transmisión de {1} - Format string for displaying connection details. {0} = address, {1} = baud rate + + Dirección {0} a {1} + Brief connection status format. {0} = address, {1} = baud rate diff --git a/src/Core/Resources/Resources.fr.resx b/src/Core/Resources/Resources.fr.resx index 8bdac57..051f266 100644 --- a/src/Core/Resources/Resources.fr.resx +++ b/src/Core/Resources/Resources.fr.resx @@ -134,9 +134,9 @@ Prefix for device serial number display - - Appareil connecté à l’adresse {0} fonctionnant à une vitesse de transmission de {1} - Format string for displaying connection details. {0} = address, {1} = baud rate + + Adresse {0} à {1} + Brief connection status format. {0} = address, {1} = baud rate diff --git a/src/Core/Resources/Resources.ja.resx b/src/Core/Resources/Resources.ja.resx index 34e2433..f2bfe1e 100644 --- a/src/Core/Resources/Resources.ja.resx +++ b/src/Core/Resources/Resources.ja.resx @@ -134,9 +134,9 @@ Prefix for device serial number display - - アドレスで接続されたデバイス {0} ボーレート {1} - Format string for displaying connection details. {0} = address, {1} = baud rate + + アドレス {0} - {1} + Brief connection status format. {0} = address, {1} = baud rate diff --git a/src/Core/Resources/Resources.resx b/src/Core/Resources/Resources.resx index e610fe8..cf8218c 100644 --- a/src/Core/Resources/Resources.resx +++ b/src/Core/Resources/Resources.resx @@ -139,9 +139,9 @@ - - Device connected at address {0} running at a baud rate of {1} - Format string for displaying connection details. {0} = address, {1} = baud rate + + Address {0} at {1} + Brief connection status format. {0} = address, {1} = baud rate diff --git a/src/Core/Resources/Resources.zh.resx b/src/Core/Resources/Resources.zh.resx index ac0011d..edfd4f2 100644 --- a/src/Core/Resources/Resources.zh.resx +++ b/src/Core/Resources/Resources.zh.resx @@ -134,9 +134,9 @@ Prefix for device serial number display - - 设备连接地址 {0} 以 {1} - Format string for displaying connection details. {0} = address, {1} = baud rate + + 地址 {0} 于 {1} + Brief connection status format. {0} = address, {1} = baud rate diff --git a/src/UI/UsbSerialForAndroid/.gitattributes b/src/UI/UsbSerialForAndroid/.gitattributes deleted file mode 100644 index 1ff0c42..0000000 --- a/src/UI/UsbSerialForAndroid/.gitattributes +++ /dev/null @@ -1,63 +0,0 @@ -############################################################################### -# Set default behavior to automatically normalize line endings. -############################################################################### -* text=auto - -############################################################################### -# Set default behavior for command prompt diff. -# -# This is need for earlier builds of msysgit that does not have it on by -# default for csharp files. -# Note: This is only used by command line -############################################################################### -#*.cs diff=csharp - -############################################################################### -# Set the merge driver for project and solution files -# -# Merging from the command prompt will add diff markers to the files if there -# are conflicts (Merging from VS is not affected by the settings below, in VS -# the diff markers are never inserted). Diff markers may cause the following -# file extensions to fail to load in VS. An alternative would be to treat -# these files as binary and thus will always conflict and require user -# intervention with every merge. To do so, just uncomment the entries below -############################################################################### -#*.sln merge=binary -#*.csproj merge=binary -#*.vbproj merge=binary -#*.vcxproj merge=binary -#*.vcproj merge=binary -#*.dbproj merge=binary -#*.fsproj merge=binary -#*.lsproj merge=binary -#*.wixproj merge=binary -#*.modelproj merge=binary -#*.sqlproj merge=binary -#*.wwaproj merge=binary - -############################################################################### -# behavior for image files -# -# image files are treated as binary by default. -############################################################################### -#*.jpg binary -#*.png binary -#*.gif binary - -############################################################################### -# diff behavior for common document formats -# -# Convert binary document formats to text before diffing them. This feature -# is only available from the command line. Turn it on by uncommenting the -# entries below. -############################################################################### -#*.doc diff=astextplain -#*.DOC diff=astextplain -#*.docx diff=astextplain -#*.DOCX diff=astextplain -#*.dot diff=astextplain -#*.DOT diff=astextplain -#*.pdf diff=astextplain -#*.PDF diff=astextplain -#*.rtf diff=astextplain -#*.RTF diff=astextplain diff --git a/src/UI/UsbSerialForAndroid/.gitignore b/src/UI/UsbSerialForAndroid/.gitignore deleted file mode 100644 index 84a4cfa..0000000 --- a/src/UI/UsbSerialForAndroid/.gitignore +++ /dev/null @@ -1,248 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -[Xx]64/ -[Xx]86/ -[Bb]uild/ -bld/ -[Bb]in/ -[Oo]bj/ - -# Visual Studio 2015 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# DNX -project.lock.json -artifacts/ - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml - -# TODO: Un-comment the next line if you do not want to checkin -# your web deploy settings because they may include unencrypted -# passwords -#*.pubxml -*.publishproj - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config -# NuGet v3's project.json files produces more ignoreable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Microsoft Azure ApplicationInsights config file -ApplicationInsights.config - -# Windows Store app package directory -AppPackages/ -BundleArtifacts/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -[Ss]tyle[Cc]op.* -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.pfx -*.publishsettings -node_modules/ -orleans.codegen.cs - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -*.mdf -*.ldf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# LightSwitch generated files -GeneratedArtifacts/ -ModelManifest.xml - -# Paket dependency manager -.paket/paket.exe - -# FAKE - F# Make -.fake/ - -#Zip files -*.zip \ No newline at end of file diff --git a/src/UI/UsbSerialForAndroid/LICENSE.txt b/src/UI/UsbSerialForAndroid/LICENSE.txt deleted file mode 100644 index c5e6b6b..0000000 --- a/src/UI/UsbSerialForAndroid/LICENSE.txt +++ /dev/null @@ -1,22 +0,0 @@ -MIT License - -Copyright (c) 2011-2017 Google Inc. -Copyright (c) 2017 Tyler Technologies - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/src/UI/UsbSerialForAndroid/README.md b/src/UI/UsbSerialForAndroid/README.md deleted file mode 100644 index 1780d36..0000000 --- a/src/UI/UsbSerialForAndroid/README.md +++ /dev/null @@ -1,107 +0,0 @@ -# UsbSerialForAndroid - -[![Build Status](https://chrismillercode.visualstudio.com/UsbSerialForAndroid/_apis/build/status/anotherlab.UsbSerialForAndroid?branchName=master)](https://chrismillercode.visualstudio.com/UsbSerialForAndroid/_build/latest?definitionId=1&branchName=master) - -This is a driver library to allow your Xamarin Android app to communicate with many common USB serial hardware. It uses the [Android USB Host API](http://developer.android.com/guide/topics/connectivity/usb/host.html) -available on Android 3.1+. - -No root access, ADK, or special kernel drivers are required; all drivers are implemented in -c#. You get a raw serial port with `Read()`, `Write()`, and other basic -functions for use with your own protocols. The appropriate driver is picked based on the device's Vendor ID and Product ID. - -This is a Xamarin C# port of Mike Wakerly's Java [usb-serial-for-android](https://github.com/mik3y/usb-serial-for-android) library. It followed that library very closely when it was ported. The main changes were to make the method names follow C# standard naming conventions. Some Java specific data types were replaced with .NET types and the reflection code is .NET specific. Code examples written for the Java version of the library should translate more or less faithfully to C#. - -It also includes code derived from a portion of LusoVU's [XamarinUsbSerial](https://bitbucket.org/lusovu/xamarinusbserial) library. XamarinUsbSerial was a C# wrapper for the Java usb-serial-for-android. It used an older version of the usb-serial-for-android .jar file. Only the the C# code was used, the Java library is not referenced. - -The default branch has been renamed from master to main. if you have a local clone, you can run the following commands to update the name of the default branch - -``` -git branch -m master main -git fetch origin -git branch -u origin/main main -git remote set-head origin -a -``` - -## Structure - -This solution contains two projects. - -* UsbSerialForAndroid - A port of the Java library usb-serial-for-android -* UsbSerialExampleApp - A Xamarin version of the example app that comes with usb-serial-for-android - -## Getting Started -**1.** Reference the library to your project - -**2.** Copy the [device_filter.axml](https://github.com/anotherlab/UsbSerialForAndroid/blob/master/UsbSerialExampleApp/Resources/xml/device_filter.xml) from the example app to your Resources/xml folder. Make sure that the Build Action is set to AndroidResource - -**3.** Add the following attribute to the main activity to enable the USB Host -```C# -[assembly: UsesFeature("android.hardware.usb.host")] -``` - -**4.** Add the following IntentFilter to the main activity to receive USB device attached notifications -```C# -[IntentFilter(new[] { UsbManager.ActionUsbDeviceAttached })] -``` - -**5.** Add the MetaData attribute to associate the device_filter with the USB attached event to only see the devices that we are looking for -```C# -[MetaData(UsbManager.ActionUsbDeviceAttached, Resource = "@xml/device_filter")] -``` - -**6.** Refer to [MainActivity.cs](https://github.com/anotherlab/UsbSerialForAndroid/blob/master/UsbSerialExampleApp/MainActivity.cs) in the example app to see how connect to a serial device and read data from it. - -## Working with unrecognized devices -The UsbSerialForAndroid has been compiled with the Vendor ID/Product ID pairs for many common serial devices. If you have a device that is not defined by the library, but will work with one of the drivers, you can manually add the VID/PID pair. - -UsbSerialProber is a class to help you find and instantiate compatible -UsbSerialDrivers from the tree of connected UsbDevices. Normally, you will use -the default prober returned by ``UsbSerialProber.getDefaultProber()``, which -uses the built-in list of well-known VIDs and PIDs that are supported by our -drivers. - -To use your own set of rules, create and use a custom prober: - -```C# -// Probe for our custom CDC devices, which use VID 0x1234 -// and PIDS 0x0001 and 0x0002. -var table = UsbSerialProber.DefaultProbeTable; -table.AddProduct(0x1b4f, 0x0008, typeof(CdcAcmSerialDriver)); // IOIO OTG - -table.AddProduct(0x09D8, 0x0420, typeof(CdcAcmSerialDriver)); // Elatec TWN4 - -var prober = new UsbSerialProber(table); -List drivers = prober.FindAllDrivers(usbManager); -// ... -``` - -Of course, nothing requires you to use UsbSerialProber at all: you can -instantiate driver classes directly if you know what you're doing; just supply -a compatible UsbDevice. - - -## Compatible Devices - -* *Serial chips:* FT232R, CDC/ACM (eg Arduino Uno) and possibly others. - See [CompatibleSerialDevices](https://github.com/mik3y/usb-serial-for-android/wiki/Compatible-Serial-Devices). -* *Android phones and tablets:* Nexus 7, Motorola Xoom, and many others. - See [CompatibleAndroidDevices](https://github.com/mik3y/usb-serial-for-android/wiki/Compatible-Android-Devices). - -## Additional information - -This is a port of the usb-serial-for-android library and code examples written for it can be adapted to C# without much effort. - -For common problems, see the -[Troubleshooting](https://github.com/mik3y/usb-serial-for-android/wiki/Troubleshooting) -wiki page for usb-serial-for-android library. - -For other help and discussion, please join the usb-serial-for-android Google Group, -[usb-serial-for-android](https://groups.google.com/forum/?fromgroups#!forum/usb-serial-for-android). - -Pull Requests are welcome, but please include what hardware was used for testing. I do not have the hardware or the bandwidth to test the various chipsets supported by the library. - -## Author, License, and Copyright - -This library is licensed under LGPL Version 2.1. Please see LICENSE.txt for the complete license. - -Copyright 2017, Tyler Technologies. All Rights Reserved. Portions of this library are based on the [usb-serial-for-android](https://github.com/mik3y/usb-serial-for-android) and [XamarinUsbSerial](https://bitbucket.org/lusovu/xamarinusbserial) libraries. Their rights remain intact. diff --git a/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Assets/AboutAssets.txt b/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Assets/AboutAssets.txt deleted file mode 100644 index ee39886..0000000 --- a/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Assets/AboutAssets.txt +++ /dev/null @@ -1,19 +0,0 @@ -Any raw assets you want to be deployed with your application can be placed in -this directory (and child directories) and given a Build Action of "AndroidAsset". - -These files will be deployed with you package and will be accessible using Android's -AssetManager, like this: - -public class ReadAsset : Activity -{ - protected override void OnCreate (Bundle bundle) - { - base.OnCreate (bundle); - - InputStream input = Assets.Open ("my_asset.txt"); - } -} - -Additionally, some Android functions will automatically load asset files: - -Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf"); \ No newline at end of file diff --git a/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/GettingStarted.Xamarin b/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/GettingStarted.Xamarin deleted file mode 100644 index e9d4f6a..0000000 --- a/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/GettingStarted.Xamarin +++ /dev/null @@ -1,4 +0,0 @@ - - GS\Android\CS\AndroidApp\GettingStarted.html - false - \ No newline at end of file diff --git a/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/MainActivity.cs b/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/MainActivity.cs deleted file mode 100644 index 3c6f148..0000000 --- a/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/MainActivity.cs +++ /dev/null @@ -1,222 +0,0 @@ -/* Copyright 2017 Tyler Technologies Inc. - * - * Project home page: https://github.com/anotherlab/xamarin-usb-serial-for-android - * Portions of this library are based on usb-serial-for-android (https://github.com/mik3y/usb-serial-for-android). - * Portions of this library are based on Xamarin USB Serial for Android (https://bitbucket.org/lusovu/xamarinusbserial). - */ - -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Android.App; -using Android.Content; -using Android.Hardware.Usb; -using Android.Runtime; -using Android.Views; -using Android.Widget; -using Android.OS; -using Android.Util; -using Hoho.Android.UsbSerial.Driver; -using Hoho.Android.UsbSerial.Extensions; -using Hoho.Android.UsbSerial.Util; - - -[assembly: UsesFeature("android.hardware.usb.host")] - - -namespace UsbSerialExampleApp -{ - [Activity(Label = "UsbSerialExampleApp", MainLauncher = true, Icon = "@drawable/icon")] - [IntentFilter(new[] { UsbManager.ActionUsbDeviceAttached })] - [MetaData(UsbManager.ActionUsbDeviceAttached, Resource = "@xml/device_filter")] - public class MainActivity : Activity - { - static readonly string TAG = typeof(MainActivity).Name; - const string ACTION_USB_PERMISSION = "com.hoho.android.usbserial.examples.USB_PERMISSION"; - - UsbManager usbManager; - ListView listView; - TextView progressBarTitle; - ProgressBar progressBar; - - UsbSerialPortAdapter adapter; - BroadcastReceiver detachedReceiver; - UsbSerialPort selectedPort; - - - protected override void OnCreate(Bundle bundle) - { - base.OnCreate(bundle); - - // Set our view from the "main" layout resource - SetContentView(Resource.Layout.Main); - - usbManager = GetSystemService(Context.UsbService) as UsbManager; - listView = FindViewById(Resource.Id.deviceList); - progressBar = FindViewById(Resource.Id.progressBar); - progressBarTitle = FindViewById(Resource.Id.progressBarTitle); - } - - protected override async void OnResume() - { - base.OnResume(); - - adapter = new UsbSerialPortAdapter(this); - listView.Adapter = adapter; - - listView.ItemClick += async (sender, e) => { - await OnItemClick(sender, e); - }; - - await PopulateListAsync(); - - //register the broadcast receivers - detachedReceiver = new UsbDeviceDetachedReceiver(this); - RegisterReceiver(detachedReceiver, new IntentFilter(UsbManager.ActionUsbDeviceDetached)); - } - protected override void OnPause() - { - base.OnPause(); - - // unregister the broadcast receivers - var temp = detachedReceiver; // copy reference for thread safety - if (temp != null) - UnregisterReceiver(temp); - } - internal static Task> FindAllDriversAsync(UsbManager usbManager) - { - // using the default probe table - // return UsbSerialProber.DefaultProber.FindAllDriversAsync (usbManager); - - // adding a custom driver to the default probe table - var table = UsbSerialProber.DefaultProbeTable; - table.AddProduct(0x1b4f, 0x0008, typeof(CdcAcmSerialDriver)); // IOIO OTG - - table.AddProduct(0x09D8, 0x0420, typeof(CdcAcmSerialDriver)); // Elatec TWN4 - - var prober = new UsbSerialProber(table); - return prober.FindAllDriversAsync(usbManager); - } - - async Task OnItemClick(object sender, AdapterView.ItemClickEventArgs e) - { - Log.Info(TAG, "Pressed item " + e.Position); - if (e.Position >= adapter.Count) - { - Log.Info(TAG, "Illegal position."); - return; - } - - // request user permission to connect to device - // NOTE: no request is shown to user if permission already granted - selectedPort = adapter.GetItem(e.Position); - var permissionGranted = await usbManager.RequestPermissionAsync(selectedPort.Driver.Device, this); - if (permissionGranted) - { - // start the SerialConsoleActivity for this device - var newIntent = new Intent(this, typeof(SerialConsoleActivity)); - newIntent.PutExtra(SerialConsoleActivity.EXTRA_TAG, new UsbSerialPortInfo(selectedPort)); - StartActivity(newIntent); - } - } - - async Task PopulateListAsync() - { - ShowProgressBar(); - - Log.Info(TAG, "Refreshing device list ..."); - - var drivers = await FindAllDriversAsync(usbManager); - - adapter.Clear(); - foreach (var driver in drivers) - { - var ports = driver.Ports; - Log.Info(TAG, string.Format("+ {0}: {1} port{2}", driver, ports.Count, ports.Count == 1 ? string.Empty : "s")); - foreach (var port in ports) - adapter.Add(port); - } - - adapter.NotifyDataSetChanged(); - progressBarTitle.Text = string.Format("{0} device{1} found", adapter.Count, adapter.Count == 1 ? string.Empty : "s"); - HideProgressBar(); - Log.Info(TAG, "Done refreshing, " + adapter.Count + " entries found."); - } - - void ShowProgressBar() - { - progressBar.Visibility = ViewStates.Visible; - progressBarTitle.Text = GetString(Resource.String.refreshing); - } - - void HideProgressBar() - { - progressBar.Visibility = ViewStates.Invisible; - } - - - #region UsbSerialPortAdapter implementation - - class UsbSerialPortAdapter : ArrayAdapter - { - public UsbSerialPortAdapter(Context context) - : base(context, global::Android.Resource.Layout.SimpleExpandableListItem2) - { - } - - public override View GetView(int position, View convertView, ViewGroup parent) - { - var row = convertView; - if (row == null) - { - var inflater = Context.GetSystemService(Context.LayoutInflaterService) as LayoutInflater; - row = inflater.Inflate(global::Android.Resource.Layout.SimpleListItem2, null); - } - - var port = this.GetItem(position); - var driver = port.GetDriver(); - var device = driver.GetDevice(); - - var title = string.Format("Vendor {0} Product {1}", - HexDump.ToHexString((short)device.VendorId), - HexDump.ToHexString((short)device.ProductId)); - row.FindViewById(global::Android.Resource.Id.Text1).Text = title; - - var subtitle = device.Class.SimpleName; - row.FindViewById(global::Android.Resource.Id.Text2).Text = subtitle; - - return row; - } - } - - #endregion - - #region UsbDeviceDetachedReceiver implementation - - class UsbDeviceDetachedReceiver - : BroadcastReceiver - { - readonly string TAG = typeof(UsbDeviceDetachedReceiver).Name; - readonly MainActivity activity; - - public UsbDeviceDetachedReceiver(MainActivity activity) - { - this.activity = activity; - } - - public async override void OnReceive(Context context, Intent intent) - { - var device = intent.GetParcelableExtra(UsbManager.ExtraDevice) as UsbDevice; - - Log.Info(TAG, "USB device detached: " + device.DeviceName); - - await activity.PopulateListAsync(); - } - } - - #endregion - - - } -} - diff --git a/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Properties/AndroidManifest.xml b/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Properties/AndroidManifest.xml deleted file mode 100644 index 2fc30a2..0000000 --- a/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Properties/AndroidManifest.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Properties/AssemblyInfo.cs b/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Properties/AssemblyInfo.cs deleted file mode 100644 index ba38bad..0000000 --- a/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using Android.App; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("UsbSerialExampleApp")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("UsbSerialExampleApp")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: ComVisible(false)] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/AboutResources.txt b/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/AboutResources.txt deleted file mode 100644 index c2bca97..0000000 --- a/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/AboutResources.txt +++ /dev/null @@ -1,44 +0,0 @@ -Images, layout descriptions, binary blobs and string dictionaries can be included -in your application as resource files. Various Android APIs are designed to -operate on the resource IDs instead of dealing with images, strings or binary blobs -directly. - -For example, a sample Android app that contains a user interface layout (main.axml), -an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png) -would keep its resources in the "Resources" directory of the application: - -Resources/ - drawable/ - icon.png - - layout/ - main.axml - - values/ - strings.xml - -In order to get the build system to recognize Android resources, set the build action to -"AndroidResource". The native Android APIs do not operate directly with filenames, but -instead operate on resource IDs. When you compile an Android application that uses resources, -the build system will package the resources for distribution and generate a class called "R" -(this is an Android convention) that contains the tokens for each one of the resources -included. For example, for the above Resources layout, this is what the R class would expose: - -public class R { - public class drawable { - public const int icon = 0x123; - } - - public class layout { - public const int main = 0x456; - } - - public class strings { - public const int first_string = 0xabc; - public const int second_string = 0xbcd; - } -} - -You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main -to reference the layout/main.axml file, or R.strings.first_string to reference the first -string in the dictionary file values/strings.xml. \ No newline at end of file diff --git a/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/Resource.Designer.cs b/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/Resource.Designer.cs deleted file mode 100644 index 696074e..0000000 --- a/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/Resource.Designer.cs +++ /dev/null @@ -1,169 +0,0 @@ -#pragma warning disable 1591 -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -[assembly: global::Android.Runtime.ResourceDesignerAttribute("UsbSerialExampleApp.Resource", IsApplication=true)] - -namespace UsbSerialExampleApp -{ - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")] - public partial class Resource - { - - static Resource() - { - global::Android.Runtime.ResourceIdManager.UpdateIdValues(); - } - - public static void UpdateIdValues() - { - global::Hoho.Android.UsbSerial.Resource.String.ApplicationName = global::UsbSerialExampleApp.Resource.String.ApplicationName; - global::Hoho.Android.UsbSerial.Resource.String.Hello = global::UsbSerialExampleApp.Resource.String.Hello; - } - - public partial class Attribute - { - - static Attribute() - { - global::Android.Runtime.ResourceIdManager.UpdateIdValues(); - } - - private Attribute() - { - } - } - - public partial class Drawable - { - - // aapt resource value: 0x7f020000 - public const int Icon = 2130837504; - - static Drawable() - { - global::Android.Runtime.ResourceIdManager.UpdateIdValues(); - } - - private Drawable() - { - } - } - - public partial class Id - { - - // aapt resource value: 0x7f060008 - public const int consoleText = 2131099656; - - // aapt resource value: 0x7f060007 - public const int demoScroller = 2131099655; - - // aapt resource value: 0x7f060001 - public const int demoTitle = 2131099649; - - // aapt resource value: 0x7f060004 - public const int deviceList = 2131099652; - - // aapt resource value: 0x7f060002 - public const int progressBar = 2131099650; - - // aapt resource value: 0x7f060000 - public const int progressBarTitle = 2131099648; - - // aapt resource value: 0x7f060003 - public const int separator = 2131099651; - - // aapt resource value: 0x7f060005 - public const int sleepButton = 2131099653; - - // aapt resource value: 0x7f060006 - public const int wakeupButton = 2131099654; - - static Id() - { - global::Android.Runtime.ResourceIdManager.UpdateIdValues(); - } - - private Id() - { - } - } - - public partial class Layout - { - - // aapt resource value: 0x7f030000 - public const int Main = 2130903040; - - // aapt resource value: 0x7f030001 - public const int serial_console = 2130903041; - - static Layout() - { - global::Android.Runtime.ResourceIdManager.UpdateIdValues(); - } - - private Layout() - { - } - } - - public partial class String - { - - // aapt resource value: 0x7f050001 - public const int ApplicationName = 2131034113; - - // aapt resource value: 0x7f050000 - public const int Hello = 2131034112; - - // aapt resource value: 0x7f050002 - public const int app_name = 2131034114; - - // aapt resource value: 0x7f050003 - public const int refreshing = 2131034115; - - // aapt resource value: 0x7f050004 - public const int sleep = 2131034116; - - // aapt resource value: 0x7f050005 - public const int wakeup = 2131034117; - - static String() - { - global::Android.Runtime.ResourceIdManager.UpdateIdValues(); - } - - private String() - { - } - } - - public partial class Xml - { - - // aapt resource value: 0x7f040000 - public const int device_filter = 2130968576; - - static Xml() - { - global::Android.Runtime.ResourceIdManager.UpdateIdValues(); - } - - private Xml() - { - } - } - } -} -#pragma warning restore 1591 diff --git a/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/drawable/Icon.png b/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/drawable/Icon.png deleted file mode 100644 index 8074c4c571b8cd19e27f4ee5545df367420686d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4147 zcmV-35X|q1P)OwvMs$Q8_8nISM!^>PxsujeDCl4&hPxrxkp%Qc^^|l zp6LqAcf3zf1H4aA1Gv-O6ha)ktct9Y+VA@N^9i;p0H%6v>ZJZYQ`zEa396z-gi{r_ zDz)D=vgRv62GCVeRjK{15j7V@v6|2nafFX6W7z2j1_T0a zLyT3pGTubf1lB5)32>bl0*BflrA!$|_(WD2)iJIfV}37=ZKAC zSe3boYtQ=;o0i>)RtBvsI#iT{0!oF1VFeW`jDjF2Q4aE?{pGCAd>o8Kg#neIh*AMY zLl{;F!vLiem7s*x0<9FKAd6LoPz3~G32P+F+cuGOJ5gcC@pU_?C2fmix7g2)SUaQO$NS07~H)#fn!Q<}KQWtX}wW`g2>cMld+`7Rxgq zChaey66SG560JhO66zA!;sK1cWa2AG$9k~VQY??6bOmJsw9@3uL*z;WWa7(Nm{^TA zilc?y#N9O3LcTo2c)6d}SQl-v-pE4^#wb=s(RxaE28f3FQW(yp$ulG9{KcQ7r>7mQ zE!HYxUYex~*7IinL+l*>HR*UaD;HkQhkL(5I@UwN%Wz504M^d!ylo>ANvKPF_TvA< zkugG5;F6x}$s~J8cnev->_(Ic7%lGQgUi3n#XVo36lUpcS9s z)ympRr7}@|6WF)Ae;D{owN1;aZSR50al9h~?-WhbtKK%bDd zhML131oi1Bu1&Qb$Cp199LJ#;j5d|FhW8_i4KO1OI>}J^p2DfreMSVGY9aFlr&90t zyI2FvxQiKMFviSQeP$Ixh#70qj5O%I+O_I2t2XHWqmh2!1~tHpN3kA4n=1iHj?`@c<~3q^X6_Q$AqTDjBU`|!y<&lkqL|m5tG(b z8a!z&j^m(|;?SW(l*?tZ*{m2H9d&3jqBtXh>O-5e4Qp-W*a5=2NL&Oi62BUM)>zE3 zbSHb>aU3d@3cGggA`C-PsT9^)oy}%dHCaO~nwOrm5E54=aDg(&HR4S23Oa#-a^=}w%g?ZP-1iq8PSjE8jYaGZu z$I)?YN8he?F9>)2d$G6a*zm0XB*Rf&gZAjq(8l@CUDSY1tB#!i> zW$VfG%#SYSiZ};)>pHA`qlfDTEYQEwN6>NNEp+uxuqx({Fgr zjI@!4xRc?vk^9+~eU|mzH__dCDI=xb{Cd}4bELS9xRaS!*FXMwtMR-RR%SLMh0Cjl zencr8#Su<4(%}$yGVBU-HX{18v=yPH*+%^Vtknc>2A;%-~DrYFx^3XfuVgvZ{#1tA== zm3>IzAM2{3Iv_d1XG{P6^tN3|PkJMnjs&CWN7%7_CmjoVakUhsa&dMv==2~^ri?&x zVdv*rnfVyM+I1^Kg*S=23mR@+0T9BWFZUu~@toA8d)fw6be=`Yb6DSX6D?jB%2YT~ z*aHjtIOozfMhA!Jd*?u5_n!SnX>vX`=Ti-1HA4RiE>eI3vTn zz+>Ccf0HX6Ans-ebOB>RJST-Cyr#4XAk+mAlJgdQnoE{^iIN)OcYFSpgJUmXtl@tT z-^ZuUeSj5hSFrQwqX>~EtZ*{>Gi8Bu9_|o06oNtaXP?E936!a@DsvS*tsB@fa6kEA z5GkjwmH?EgpiG&itsB_Tb1NxtFnvxh_s@9KYX1Sttf?AlI~)z zT=6Y7ulx=}<8Scr_UqU-_z)5gPo%050PsbM*ZLno;_-ow&k?FZJtYmb2hPA$LkP)8 z=^d0Q6PImh6Y|QT?{grxj)S=uBKvY2EQUbm@ns9^yKiP~$DcD)c$5Em`zDSScH%iH zVov&m=cMo`1tYwA=!a}vb_ef_{)Q2?FUqn>BR$6phXQRv^1%=YfyE-F$AR4Q?9D!f zCzB^^#td~4u&l~l#rp2QLfe3+_ub9@+|x+m;=2(sQ`s%gO|j$XBb>A7Q(UydipiMw%igcweV#Cr~SP);q>w`bxts_4} znKHg?X==JDkQl3Y>Ckt%`s{n?Nq-1Fw5~%Mq$CAsi-`yu_bKm zxs#QdE7&vgJD%M84f4SNzSDv)S|V?|$!d5a#lhT5>>YWE4NGqa9-fbmV$=)@k&32kdEYetna>=j@0>V8+wRsL;po!3ivVwh<9tn z2S<1u9DAAQ>x1Sn=fk`)At|quvleV($B|#Kap_lB-F^*yV=wZ{9baUu(uXfokr95^ zA*!*W=5a>$2Ps`-F^+qRQT^{*cN>vipT*4!r#p%{(#I7s z0NN94*q?ib$KJjfDI_sjHNdmEVp5wB&j54O#VoFqBwy)gfA$%)4d_X4q${L9Xom2R3xy&ZBSNgt4a1d7K^CDWa9r zVb-_52m}Vp)`9;ZSKd#|U4ZYj5}Gp49{4utST|=c`~(#>KHF6}CCov1iHYw zt{bWo)A@yF2$~c(nR$rSAaFQ$(Wh{vkG1AlutDMw=mM`C`T=X&|Ad9fb5Od}ROt1z zOpczHqrb4Jo^rSCiW#&o(m7jFamnrsTpQb;*h4o8r#$aZ}2RaT-x2u^^ z%u@YyIv$U^u~@9(XGbSwU@fk6SikH>j+D1jQrYTKGJpW%vUT{!d}7THI5&Sa?~MKy zS0-mvMl+BOcroEJ@hN!2H_?coTEJ5Q<;Nd?yx;eIj4{$$E2?YUO|NtNPJ-PdDf;s} zab;}Mz0kbOI}5*w@3gROcnl#5)wQnEhDBfn!Xhy`u>C}*E~vWpO^HS)FC>8^umI=+ z&H;LW6w#;EF`}vQd_9Muru`KnQVPI9U?(sD)&Dg-0j3#(!fNKVZ_GoYH{la~d*1Yh$TI-TL>mI4vpNb@sU2=IZ8vL%AXUx0 zz{K0|nK(yizLHaeW#ZhRfQXoK^}1$=$#1{Yn002ovPDHLkV1n#w+^+xt diff --git a/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/layout/Main.axml b/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/layout/Main.axml deleted file mode 100644 index 683e784..0000000 --- a/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/layout/Main.axml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/layout/serial_console.axml b/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/layout/serial_console.axml deleted file mode 100644 index f97b0de..0000000 --- a/src/UI/UsbSerialForAndroid/UsbSerialExampleApp/Resources/layout/serial_console.axml +++ /dev/null @@ -1,44 +0,0 @@ - - - -