From 6d54ca9221255735bf737e7401d5f673b2e8e6d5 Mon Sep 17 00:00:00 2001 From: Jos Demmers Date: Wed, 21 Dec 2022 12:03:23 +0100 Subject: [PATCH] - Added automatic updates - Added server health indicator - Green: Scanned within the last 24 hours - Orange: Scanned between 24-36 hours ago - Red: Last scan was over 36 hours ago - Moved all price overlay settings to Config > Overlay - Fixed exception in storage filter --- NewWorldCompanion.Entities/PriceServer.cs | 1 + NewWorldCompanion.Entities/SettingsNWC.cs | 1 + .../IScreenCaptureHandler.cs | 2 +- NewWorldCompanion.Services/PriceManager.cs | 42 ++++++----- .../RelatedPriceManager.cs | 6 +- .../ScreenCaptureHandler.cs | 12 ++- .../Converters/DateTimeToHealthConverter.cs | 33 +++++++++ .../ViewModels/MainWindowViewModel.cs | 45 +++++++++++- .../Tabs/Config/ConfigOverlayViewModel.cs | 25 +++++++ .../ViewModels/Tabs/CraftingViewModel.cs | 11 --- .../ViewModels/Tabs/StorageViewModel.cs | 6 +- NewWorldCompanion/Views/MainWindow.xaml | 35 +++++---- .../Views/Tabs/Config/ConfigOverlayView.xaml | 31 +++++--- .../Views/Tabs/CraftingView.xaml | 7 +- .../Views/Tabs/CraftingView.xaml.cs | 29 ++++++-- NewWorldCompanion/Views/Tabs/StorageView.xaml | 73 ++++++++++--------- .../Views/Tabs/StorageView.xaml.cs | 13 ++++ NewWorldCompanion/common.props | 4 +- 18 files changed, 261 insertions(+), 115 deletions(-) create mode 100644 NewWorldCompanion/Converters/DateTimeToHealthConverter.cs diff --git a/NewWorldCompanion.Entities/PriceServer.cs b/NewWorldCompanion.Entities/PriceServer.cs index 68ba6f5..1b64c49 100644 --- a/NewWorldCompanion.Entities/PriceServer.cs +++ b/NewWorldCompanion.Entities/PriceServer.cs @@ -10,5 +10,6 @@ public class PriceServer { public string Name { get; set; } = string.Empty; public int Id { get; set; } = 1; + public DateTime Updated { get; set; } = DateTime.MinValue; } } diff --git a/NewWorldCompanion.Entities/SettingsNWC.cs b/NewWorldCompanion.Entities/SettingsNWC.cs index 40dab32..99f0af5 100644 --- a/NewWorldCompanion.Entities/SettingsNWC.cs +++ b/NewWorldCompanion.Entities/SettingsNWC.cs @@ -12,6 +12,7 @@ public class SettingsNWC public bool DebugModeActive { get; set; } = false; // Overlay + public bool TooltipEnabled { get; set; } = true; public bool ExtendedTooltipEnabled { get; set; } = false; public int PriceServerId { get; set; } = 1; diff --git a/NewWorldCompanion.Interfaces/IScreenCaptureHandler.cs b/NewWorldCompanion.Interfaces/IScreenCaptureHandler.cs index 76c682b..c7696c7 100644 --- a/NewWorldCompanion.Interfaces/IScreenCaptureHandler.cs +++ b/NewWorldCompanion.Interfaces/IScreenCaptureHandler.cs @@ -7,7 +7,7 @@ public interface IScreenCaptureHandler { Bitmap? CurrentScreen { get; } Bitmap? CurrentScreenMouseArea { get; } - bool IsActive { get; set; } + bool IsActive { get; } string MouseCoordinates { get; } string MouseCoordinatesScaled { get; } int OffsetX { get; } diff --git a/NewWorldCompanion.Services/PriceManager.cs b/NewWorldCompanion.Services/PriceManager.cs index f40ef20..1b39491 100644 --- a/NewWorldCompanion.Services/PriceManager.cs +++ b/NewWorldCompanion.Services/PriceManager.cs @@ -13,6 +13,7 @@ using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; +using System.Windows; namespace NewWorldCompanion.Services { @@ -50,8 +51,8 @@ public PriceManager(IEventAggregator eventAggregator, ILogger logg _newWorldDataStore = newWorldDataStore; _relatedPriceManager = relatedPriceManager; - // Init servers - UpdateServerList(); + // Init servers + UpdateServerList(); } #endregion @@ -79,23 +80,30 @@ private async void UpdateServerList() { try { - string json = await _httpClientHandler.GetRequest("https://nwmarketprices.com/api/servers/") ?? string.Empty; - var servers = JsonSerializer.Deserialize>(json); + string json = await _httpClientHandler.GetRequest("https://nwmarketprices.com/api/servers_updated/") ?? string.Empty; + var servers = JsonSerializer.Deserialize(json); - foreach (var server in servers ?? new Dictionary()) + _servers.Clear(); + foreach (var server in servers?.ServersLastUpdated ?? new List>()) { - string serverId = server.Key; - string serverName = server.Value.Name; + var serverId = ((JsonElement)server[0]).GetInt32(); + var serverName = ((JsonElement)server[1]).GetString() ?? string.Empty; + var updated = ((JsonElement)server[2]).GetDateTime(); - if (!string.IsNullOrWhiteSpace(serverId) && !string.IsNullOrWhiteSpace(serverName)) + _servers.Add(new PriceServer() { - _servers.Add(new PriceServer() - { - Id = int.Parse(serverId), - Name = serverName - }); - } + Id = serverId, + Name = serverName, + Updated = updated + }); } + + // Sort server list by name + _servers.Sort((x, y) => + { + int result = string.Compare(x.Name, y.Name, StringComparison.Ordinal); + return result; + }); } catch (Exception ex) { @@ -319,10 +327,10 @@ public void UpdatePriceData(string itemName) #endregion - private class Server + private class UpdatedServers { - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + [JsonPropertyName("server_last_updated")] + public List> ServersLastUpdated { get; set; } = new List> { }; } } } diff --git a/NewWorldCompanion.Services/RelatedPriceManager.cs b/NewWorldCompanion.Services/RelatedPriceManager.cs index 9c206d1..f2ac180 100644 --- a/NewWorldCompanion.Services/RelatedPriceManager.cs +++ b/NewWorldCompanion.Services/RelatedPriceManager.cs @@ -79,8 +79,10 @@ public void SetRawResourceRecipeVisibility(string itemIDRawResource, string item { // Recipe resource exists var recipe = rawResource.PersistableOverlayResourceRecipes.FirstOrDefault(resource => resource.ItemId.Equals(itemID)); - recipe.IsVisible = isVisible; - + if (recipe != null) + { + recipe.IsVisible = isVisible; + } } else { diff --git a/NewWorldCompanion.Services/ScreenCaptureHandler.cs b/NewWorldCompanion.Services/ScreenCaptureHandler.cs index 91758ee..f803bd0 100644 --- a/NewWorldCompanion.Services/ScreenCaptureHandler.cs +++ b/NewWorldCompanion.Services/ScreenCaptureHandler.cs @@ -18,6 +18,7 @@ public class ScreenCaptureHandler : IScreenCaptureHandler { private readonly IEventAggregator _eventAggregator; private readonly ILogger _logger; + private readonly ISettingsManager _settingsManager; private DispatcherTimer _captureTimer = new(); private DispatcherTimer _coordinatesTimer = new(); @@ -25,7 +26,6 @@ public class ScreenCaptureHandler : IScreenCaptureHandler private Bitmap? _currentScreenMouseArea = null; private int _delay = 100; private int _delayCoordinates = 100; - private bool _isActive = true; private int _offsetX = 0; private int _offsetY = 0; private ScreenCapture _screenCapture = new ScreenCapture(); @@ -34,7 +34,7 @@ public class ScreenCaptureHandler : IScreenCaptureHandler #region Constructor - public ScreenCaptureHandler(IEventAggregator eventAggregator, ILogger logger) + public ScreenCaptureHandler(IEventAggregator eventAggregator, ILogger logger, ISettingsManager settingsManager) { // Init IEventAggregator _eventAggregator = eventAggregator; @@ -42,6 +42,9 @@ public ScreenCaptureHandler(IEventAggregator eventAggregator, ILogger _currentScreenMouseArea; set => _currentScreenMouseArea = value; } public int Delay { get => _delay; set => _delay = value; } public int DelayCoordinates { get => _delayCoordinates; set => _delayCoordinates = value; } - public bool IsActive { get => _isActive; set => _isActive = value; } + public bool IsActive + { + get => _settingsManager.Settings.TooltipEnabled; + } public string MouseCoordinates { get; set; } = string.Empty; public string MouseCoordinatesScaled { get; set; } = string.Empty; public int OffsetX { get => _offsetX; set => _offsetX = value; } diff --git a/NewWorldCompanion/Converters/DateTimeToHealthConverter.cs b/NewWorldCompanion/Converters/DateTimeToHealthConverter.cs new file mode 100644 index 0000000..6fa47cc --- /dev/null +++ b/NewWorldCompanion/Converters/DateTimeToHealthConverter.cs @@ -0,0 +1,33 @@ +using System; +using System.Globalization; +using System.Windows.Data; +using System.Windows.Media; + +namespace NewWorldCompanion.Converters +{ + class DateTimeToHealthConverter : IValueConverter + { + public Object Convert(Object value, Type targetType, Object parameter, CultureInfo culture) + { + if (targetType == typeof(Brush)) + { + var updated = System.Convert.ToDateTime(value, culture); + var timeSpan = DateTime.Now - updated; + + if (timeSpan < TimeSpan.FromHours(24)) + return Brushes.Green; + else if (timeSpan < TimeSpan.FromHours(36)) + return Brushes.Orange; + else + return Brushes.Red; + } + + throw new InvalidOperationException("Converter can only convert to value of type Brush."); + } + + public Object ConvertBack(Object aValue, Type aTargetType, Object aParameter, CultureInfo aCulture) + { + throw new InvalidOperationException("Converter cannot convert back."); + } + } +} diff --git a/NewWorldCompanion/ViewModels/MainWindowViewModel.cs b/NewWorldCompanion/ViewModels/MainWindowViewModel.cs index e3e0526..90044a9 100644 --- a/NewWorldCompanion/ViewModels/MainWindowViewModel.cs +++ b/NewWorldCompanion/ViewModels/MainWindowViewModel.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Logging; +using MahApps.Metro.Controls.Dialogs; +using Microsoft.Extensions.Logging; using NewWorldCompanion.Events; using NewWorldCompanion.Interfaces; using Prism.Commands; @@ -6,8 +7,8 @@ using Prism.Mvvm; using System; using System.Diagnostics; +using System.IO; using System.Reflection; -using System.Threading.Tasks; namespace NewWorldCompanion.ViewModels { @@ -18,6 +19,7 @@ public class MainWindowViewModel : BindableBase private readonly ISettingsManager _settingsManager; private readonly IOverlayHandler _overlayHandler; private readonly IVersionManager _versionManager; + private readonly IDialogCoordinator _dialogCoordinator; private string _windowTitle = $"New World Companion v{Assembly.GetExecutingAssembly().GetName().Version}"; @@ -25,7 +27,7 @@ public class MainWindowViewModel : BindableBase #region Constructor - public MainWindowViewModel(IEventAggregator eventAggregator, ILogger logger, ISettingsManager settingsManager, IOverlayHandler overlayHandler, IVersionManager versionManager) + public MainWindowViewModel(IEventAggregator eventAggregator, ILogger logger, ISettingsManager settingsManager, IOverlayHandler overlayHandler, IVersionManager versionManager, IDialogCoordinator dialogCoordinator) { // Init IEventAggregator _eventAggregator = eventAggregator; @@ -38,9 +40,11 @@ public MainWindowViewModel(IEventAggregator eventAggregator, ILogger _settingsManager.Settings.DebugModeActive; } public string WindowTitle { get => _windowTitle; set => _windowTitle = value; } @@ -66,6 +71,24 @@ private void HandleVersionInfoUpdatedEvent() !_versionManager.LatestVersion.Equals(_versionManager.CurrentVersion)) { WindowTitle = $"New World Companion v{_versionManager.CurrentVersion} (v{_versionManager.LatestVersion} available)"; + + // Ask for update when Updater.GitHub.exe exists. + if (File.Exists("Updater.GitHub.exe")) + { + _dialogCoordinator.ShowMessageAsync(this, $"Update", $"New version available, do you want to download v{_versionManager.LatestVersion}?", MessageDialogStyle.AffirmativeAndNegative).ContinueWith(t => + { + if (t.Result == MessageDialogResult.Affirmative) + { + var app = System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName ?? "NewWorldCompanion.exe"; + app = Path.GetFileName(app); + Process.Start("Updater.GitHub.exe", $"--repo \"josdemmers/NewWorldCompanion\" --app \"{app}\""); + } + }); + } + else + { + _logger.LogWarning("Cannot update applicaiton, Updater.GitHub.exe not available."); + } } else { @@ -94,6 +117,20 @@ private void LaunchNWCOnGitHubExecute() } } + private void LaunchKofiExecute() + { + { + try + { + Process.Start(new ProcessStartInfo("https://ko-fi.com/josdemmers") { UseShellExecute = true }); + } + catch (Exception ex) + { + _logger.LogError(ex, MethodBase.GetCurrentMethod()?.Name); + } + } + } + #endregion } diff --git a/NewWorldCompanion/ViewModels/Tabs/Config/ConfigOverlayViewModel.cs b/NewWorldCompanion/ViewModels/Tabs/Config/ConfigOverlayViewModel.cs index 0704b16..4123ec3 100644 --- a/NewWorldCompanion/ViewModels/Tabs/Config/ConfigOverlayViewModel.cs +++ b/NewWorldCompanion/ViewModels/Tabs/Config/ConfigOverlayViewModel.cs @@ -27,6 +27,7 @@ public class ConfigOverlayViewModel : BindableBase private ObservableCollection _overlayResources = new ObservableCollection(); private OverlayResource _selectedOverlayResource = new OverlayResource(); + private bool _toggleTooltip = false; private bool _toggleExtendedTooltip = false; private int _serverIndex = 0; private string _itemNameFilter = string.Empty; @@ -73,12 +74,35 @@ public OverlayResource SelectedOverlayResource } } + public bool ToggleTooltip + { + get => _toggleTooltip; + set + { + _toggleTooltip = value; + RaisePropertyChanged(); + if (!ToggleTooltip) + { + ToggleExtendedTooltip = false; + } + + _settingsManager.Settings.TooltipEnabled = value; + _settingsManager.SaveSettings(); + } + } + public bool ToggleExtendedTooltip { get => _toggleExtendedTooltip; set { _toggleExtendedTooltip = value; + RaisePropertyChanged(); + if (_toggleExtendedTooltip) + { + ToggleTooltip = true; + } + _settingsManager.Settings.ExtendedTooltipEnabled = value; _settingsManager.SaveSettings(); } @@ -180,6 +204,7 @@ private bool FilterOverlayResources(object overlayResourceObj) private void InitOverlayResources() { // Load extended tooltip toggle + ToggleTooltip = _settingsManager.Settings.TooltipEnabled; ToggleExtendedTooltip = _settingsManager.Settings.ExtendedTooltipEnabled; // Get interesting resources for extended overlay diff --git a/NewWorldCompanion/ViewModels/Tabs/CraftingViewModel.cs b/NewWorldCompanion/ViewModels/Tabs/CraftingViewModel.cs index 759087b..b04497f 100644 --- a/NewWorldCompanion/ViewModels/Tabs/CraftingViewModel.cs +++ b/NewWorldCompanion/ViewModels/Tabs/CraftingViewModel.cs @@ -52,7 +52,6 @@ public class CraftingViewModel : BindableBase private bool _toggleJewelcrafting = true; private bool _toggleWeaponsmithing = true; private bool _toggleMusicSheets = true; - private bool _toggleRefresh = true; private int _counterArcana = 0; private int _counterArmoring = 0; private int _counterCooking = 0; @@ -263,16 +262,6 @@ public bool ToggleMusicSheets } } - public bool ToggleRefresh - { - get => _toggleRefresh; - set - { - _toggleRefresh = value; - _screenCaptureHandler.IsActive = value; - } - } - public string SelectedCraftingRecipePrice { get diff --git a/NewWorldCompanion/ViewModels/Tabs/StorageViewModel.cs b/NewWorldCompanion/ViewModels/Tabs/StorageViewModel.cs index d2c4c57..1818621 100644 --- a/NewWorldCompanion/ViewModels/Tabs/StorageViewModel.cs +++ b/NewWorldCompanion/ViewModels/Tabs/StorageViewModel.cs @@ -94,7 +94,11 @@ public string ItemNameFilter if (ItemsFiltered?.Count == 1) { - SelectedItem = (Item)ItemsFiltered.GetItemAt(0); + var selection = ItemsFiltered.GetItemAt(0) as Item; + if (selection != null) + { + SelectedItem = selection; + } } } } diff --git a/NewWorldCompanion/Views/MainWindow.xaml b/NewWorldCompanion/Views/MainWindow.xaml index df54479..9f75b4f 100644 --- a/NewWorldCompanion/Views/MainWindow.xaml +++ b/NewWorldCompanion/Views/MainWindow.xaml @@ -1,16 +1,18 @@ - + - + + diff --git a/NewWorldCompanion/Views/Tabs/Config/ConfigOverlayView.xaml b/NewWorldCompanion/Views/Tabs/Config/ConfigOverlayView.xaml index 3d4ce09..8d8780b 100644 --- a/NewWorldCompanion/Views/Tabs/Config/ConfigOverlayView.xaml +++ b/NewWorldCompanion/Views/Tabs/Config/ConfigOverlayView.xaml @@ -3,15 +3,21 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:local="clr-namespace:NewWorldCompanion.Views.Tabs.Config" - xmlns:configvm="clr-namespace:NewWorldCompanion.ViewModels.Tabs.Config" + xmlns:local="clr-namespace:NewWorldCompanion.Views.Tabs.Config" + xmlns:configvm="clr-namespace:NewWorldCompanion.ViewModels.Tabs.Config" + xmlns:converters="clr-namespace:NewWorldCompanion.Converters" d:DataContext="{d:DesignInstance Type=configvm:ConfigOverlayViewModel}" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> + + + + + @@ -26,20 +32,23 @@ - + + + + + + - - - - + Price overlay + Extended overlay + + + - - - - + + - /// Interaction logic for CraftingView.xaml - /// - public partial class CraftingView : UserControl - { - public CraftingView() + /// + /// Interaction logic for CraftingView.xaml + /// + public partial class CraftingView : UserControl { - InitializeComponent(); + public CraftingView() + { + InitializeComponent(); + } + + private void TextBoxFilter_GotFocus(object sender, RoutedEventArgs e) + { + TextBoxFilterWatermark.Visibility = Visibility.Collapsed; + } + + private void TextBoxFilter_LostFocus(object sender, RoutedEventArgs e) + { + if (string.IsNullOrWhiteSpace(TextBoxFilter.Text)) + { + TextBoxFilterWatermark.Visibility = Visibility.Visible; + } + } } - } } diff --git a/NewWorldCompanion/Views/Tabs/StorageView.xaml b/NewWorldCompanion/Views/Tabs/StorageView.xaml index 5d13a6b..4f1b9ec 100644 --- a/NewWorldCompanion/Views/Tabs/StorageView.xaml +++ b/NewWorldCompanion/Views/Tabs/StorageView.xaml @@ -8,46 +8,47 @@ mc:Ignorable="d" d:DataContext="{d:DesignInstance Type=tabs:StorageViewModel}" d:DesignHeight="450" d:DesignWidth="800"> - - - - - - - - - - - + + + + + + + + + + + - + + - - - - - - - - - - + + + + + + + + + - + - - -