mirror of
https://github.com/WowUp/WowUp.git
synced 2026-05-24 22:46:45 -04:00
Merge branch 'develop' into electron
This commit is contained in:
@@ -36,8 +36,8 @@ namespace WowUp.Common.Models.Curse
|
||||
public int? FileTypeId { get; set; }
|
||||
public object ExposeAsAlternative { get; set; }
|
||||
public long PackageFingerprintId { get; set; }
|
||||
public DateTime GameVersionDateReleased { get; set; }
|
||||
public long GameVersionMappingId { get; set; }
|
||||
public DateTime? GameVersionDateReleased { get; set; }
|
||||
public long? GameVersionMappingId { get; set; }
|
||||
public int GameVersionId { get; set; }
|
||||
public int GameId { get; set; }
|
||||
public bool IsServerPack { get; set; }
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Flurl;
|
||||
using Flurl.Http;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
@@ -45,6 +46,7 @@ namespace WowUp.WPF.AddonProviders
|
||||
AddonChannelType addonChannelType,
|
||||
IEnumerable<AddonFolder> addonFolders)
|
||||
{
|
||||
Log.Debug($"{Name} Scanning {addonFolders.Count()} addons");
|
||||
var addonDirectory = addonFolders.FirstOrDefault()?.Directory.Parent.FullName;
|
||||
var scanResults = await GetScanResults(addonFolders);
|
||||
|
||||
@@ -332,24 +334,34 @@ namespace WowUp.WPF.AddonProviders
|
||||
|
||||
private async Task MapAddonFolders(List<CurseScanResult> scanResults, WowClientType clientType)
|
||||
{
|
||||
//var fingerprintStr = string.Join(",", scanResults.Select(sf => sf.FolderScanner.Fingerprint));
|
||||
var fingerprintResponse = await GetAddonsByFingerprints(scanResults.Select(sf => sf.FolderScanner.Fingerprint));
|
||||
var fingerprints = scanResults.Select(sf => sf.FolderScanner.Fingerprint);
|
||||
|
||||
foreach (var scanResult in scanResults)
|
||||
try
|
||||
{
|
||||
// Curse can deliver the wrong result sometimes, ensure the result matches the client type
|
||||
scanResult.ExactMatch = fingerprintResponse.ExactMatches
|
||||
.FirstOrDefault(exactMatch =>
|
||||
IsClientType(exactMatch.File.GameVersionFlavor, clientType) &&
|
||||
HasMatchingFingerprint(scanResult, exactMatch));
|
||||
var fingerprintResponse = await GetAddonsByFingerprints(fingerprints);
|
||||
|
||||
// If the addon does not have an exact match, check the partial matches.
|
||||
if (scanResult.ExactMatch == null)
|
||||
foreach (var scanResult in scanResults)
|
||||
{
|
||||
scanResult.ExactMatch = fingerprintResponse.PartialMatches
|
||||
.FirstOrDefault(partialMatch => partialMatch.File.Modules.Any(module => module.Fingerprint == scanResult.FolderScanner.Fingerprint));
|
||||
// Curse can deliver the wrong result sometimes, ensure the result matches the client type
|
||||
scanResult.ExactMatch = fingerprintResponse.ExactMatches
|
||||
.FirstOrDefault(exactMatch =>
|
||||
IsClientType(exactMatch.File.GameVersionFlavor, clientType) &&
|
||||
HasMatchingFingerprint(scanResult, exactMatch));
|
||||
|
||||
// If the addon does not have an exact match, check the partial matches.
|
||||
if (scanResult.ExactMatch == null)
|
||||
{
|
||||
scanResult.ExactMatch = fingerprintResponse.PartialMatches
|
||||
.FirstOrDefault(partialMatch => partialMatch.File.Modules.Any(module => module.Fingerprint == scanResult.FolderScanner.Fingerprint));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Failed to map addon folders");
|
||||
Log.Error($"Fingerprints\n{string.Join(",", fingerprints)}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasMatchingFingerprint(CurseScanResult scanResult, CurseMatch exactMatch)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Flurl.Http;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -29,8 +30,9 @@ namespace WowUp.WPF.AddonProviders
|
||||
public Task Scan(
|
||||
WowClientType clientType,
|
||||
AddonChannelType addonChannelType,
|
||||
IEnumerable<AddonFolder> addonFolder)
|
||||
IEnumerable<AddonFolder> addonFolders)
|
||||
{
|
||||
Log.Debug($"{Name} Scanning {addonFolders.Count()} addons");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace WowUp.WPF.AddonProviders
|
||||
AddonChannelType addonChannelType,
|
||||
IEnumerable<AddonFolder> addonFolders)
|
||||
{
|
||||
Log.Debug($"{Name} Scanning {addonFolders.Count()} addons");
|
||||
var addons = await GetAllAddons(clientType);
|
||||
|
||||
foreach (var addonFolder in addonFolders)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Flurl.Http;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -40,6 +41,7 @@ namespace WowUp.WPF.AddonProviders
|
||||
AddonChannelType addonChannelType,
|
||||
IEnumerable<AddonFolder> addonFolders)
|
||||
{
|
||||
Log.Debug($"{Name} Scanning {addonFolders.Count()} addons");
|
||||
foreach (var addonFolder in addonFolders)
|
||||
{
|
||||
if (string.IsNullOrEmpty(addonFolder.Toc.WowInterfaceId))
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using CommandLine;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -10,6 +12,7 @@ using WowUp.Common.Services.Contracts;
|
||||
using WowUp.WPF.AddonProviders;
|
||||
using WowUp.WPF.AddonProviders.Contracts;
|
||||
using WowUp.WPF.Enums;
|
||||
using WowUp.WPF.Models.WowUp;
|
||||
using WowUp.WPF.Repositories;
|
||||
using WowUp.WPF.Repositories.Contracts;
|
||||
using WowUp.WPF.Services;
|
||||
@@ -40,6 +43,8 @@ namespace WowUp.WPF
|
||||
[DllImport("user32.dll")]
|
||||
public static extern int SetForegroundWindow(IntPtr hwnd);
|
||||
|
||||
public static StartupOptions StartupOptions { get; private set; }
|
||||
|
||||
public App()
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(ExceptionHandler);
|
||||
@@ -56,13 +61,14 @@ namespace WowUp.WPF
|
||||
|
||||
Log.Information($"Starting {AppUtilities.CurrentVersion}");
|
||||
|
||||
ParseCommandLineArgs();
|
||||
|
||||
var serviceCollection = new ServiceCollection();
|
||||
ConfigureServices(serviceCollection);
|
||||
|
||||
_serviceProvider = serviceCollection.BuildServiceProvider();
|
||||
_analyticsService = _serviceProvider.GetRequiredService<IAnalyticsService>();
|
||||
}
|
||||
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
HandleSingleInstance();
|
||||
@@ -159,5 +165,15 @@ namespace WowUp.WPF
|
||||
//there is already another instance running!
|
||||
Current.Shutdown();
|
||||
}
|
||||
|
||||
private void ParseCommandLineArgs()
|
||||
{
|
||||
var args = Environment.GetCommandLineArgs().Skip(1);
|
||||
Parser.Default.ParseArguments<StartupOptions>(args)
|
||||
.WithParsed(
|
||||
options => StartupOptions = options)
|
||||
.WithNotParsed(
|
||||
errors => Log.Error(string.Join("\r\n", errors.Select(x => x.ToString()).ToArray())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,15 @@
|
||||
"ChangeLogs": [
|
||||
{
|
||||
"Version": "1.18.0",
|
||||
"Description": "Add an 'Open Folder' option to the addon context menu (By Xathz).\nFeatured addons are now sorted by download count."
|
||||
"Description": "Add an 'Open Folder' option to the addon context menu (By Xathz).\nAdd command line paramater to start the app minimized '-m' (By Noxis).\nAdd command line paramater to start the app and quit after auto updates are complete '-q' (By Noxis).\nAdd selector for when the app fails to automatically find WoW install folders.\nAdd the ability to select multiple addons and update their AutoUpdate status.\nAdd the ability to select multiple addons and update their Channel.\nAdd the ability to select multiple addons and re-install them.\nAdd the ability to select multiple addons and un-install them.\nFeatured addons are now sorted by download count.\nAddon icons should now be updated when a change is detected.\nThe system tray icon will now show the window when double clicked."
|
||||
},
|
||||
{
|
||||
"Version": "1.17.3",
|
||||
"Description": "Fix another CurseForge API error.\nAdd some better error logging around CurseForge scanning."
|
||||
},
|
||||
{
|
||||
"Version": "1.17.2",
|
||||
"Description": "Fix an issue with handling CurseForge API responses."
|
||||
},
|
||||
{
|
||||
"Version": "1.17.1",
|
||||
|
||||
@@ -31,18 +31,9 @@ namespace WowUp.WPF.Converters
|
||||
BitmapImage thumbnail = new BitmapImage();
|
||||
thumbnail.BeginInit();
|
||||
thumbnail.DecodePixelWidth = 80;
|
||||
|
||||
if (uri.IsFile)
|
||||
{
|
||||
imageStream = FileUtilities.GetMemoryStreamFromFile(uri.LocalPath);
|
||||
thumbnail.StreamSource = imageStream;
|
||||
}
|
||||
else
|
||||
{
|
||||
thumbnail.UriSource = uri;
|
||||
}
|
||||
|
||||
thumbnail.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
|
||||
thumbnail.CacheOption = BitmapCacheOption.OnLoad;
|
||||
thumbnail.UriSource = uri;
|
||||
thumbnail.EndInit();
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:WowUp.WPF"
|
||||
xmlns:vw = "clr-namespace:WowUp.WPF.Views"
|
||||
@@ -123,6 +124,33 @@
|
||||
Foreground="{StaticResource White2Brush}"
|
||||
FontSize="12"
|
||||
HorizontalAlignment="Center"/>
|
||||
|
||||
<Label Margin="0 20 0 0" HorizontalAlignment="Center">
|
||||
Manually Select World of Warcraft client location to get started.
|
||||
</Label>
|
||||
<StackPanel Margin="0 0 0 10" HorizontalAlignment="Center" Orientation="Horizontal">
|
||||
<Label>World of Warcraft Client</Label>
|
||||
<ComboBox x:Name="WowClientComboBox"
|
||||
SelectedItem="{Binding SelectedClientType}"
|
||||
Style="{StaticResource ComboBoxFlatStyle}"
|
||||
ToolTip="World of Warcraft client type"
|
||||
ItemsSource="{Binding WowClientTypes}">
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="SelectionChanged">
|
||||
<i:InvokeCommandAction Command="{Binding SelectedWowClientChangedCommand}"
|
||||
CommandParameter="{Binding ElementName=WowClientComboBox, Path=SelectedValue}"/>
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<Button Command="{Binding SetWowLocationCommand}"
|
||||
Style="{StaticResource purpleButton}"
|
||||
ToolTip="Select World of Warcraft Folder">
|
||||
Select Location
|
||||
</Button>
|
||||
<Label Foreground="{StaticResource White2Brush}"
|
||||
HorizontalAlignment="Center"
|
||||
Content="{Binding WowClientHint}"></Label>
|
||||
</StackPanel>
|
||||
<!--TABS-->
|
||||
<TabControl x:Name="Tabs"
|
||||
@@ -161,6 +189,7 @@
|
||||
x:Name="TrayIcon"
|
||||
IconSource="/Assets/wowup_logo_512np_RRT_icon.ico"
|
||||
ToolTipText="WowUp"
|
||||
NoLeftClickDelay="True"
|
||||
LeftClickCommand="{Binding TaskbarIconClickCommand}">
|
||||
<tb:TaskbarIcon.ContextMenu>
|
||||
<ContextMenu Style="{StaticResource DarkMenu}">
|
||||
|
||||
18
WowUp.WPF/Models/WowUp/StartupOptions.cs
Normal file
18
WowUp.WPF/Models/WowUp/StartupOptions.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using CommandLine;
|
||||
using System.Collections.Generic;
|
||||
using WowUp.Common.Enums;
|
||||
|
||||
namespace WowUp.WPF.Models.WowUp
|
||||
{
|
||||
public class StartupOptions
|
||||
{
|
||||
[Option(shortName: 'i', longName: "install", HelpText = "Specify addon URLs to install them")]
|
||||
public IEnumerable<string> InputURLs { get; set; }
|
||||
[Option(shortName: 'm', longName: "minimized", HelpText = "Start the application minimized")]
|
||||
public bool Minimized { get; set; }
|
||||
[Option(shortName: 'q', longName: "quit", HelpText = "Exit the application after auto-updates")]
|
||||
public bool Quit { get; set; }
|
||||
[Option(shortName: 'c', longName: "client", HelpText = "Specify client version to use", Default = WowClientType.None)]
|
||||
public WowClientType ClientType { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -269,7 +269,16 @@ namespace WowUp.WPF.Services
|
||||
|
||||
if (result == null || latestFile == null || latestFile.Version == addon.LatestVersion)
|
||||
{
|
||||
await SyncThumbnail(addon);
|
||||
if(addon.ThumbnailUrl != result.ThumbnailUrl)
|
||||
{
|
||||
addon.ThumbnailUrl = result.ThumbnailUrl;
|
||||
_addonRepository.UpdateItem(addon);
|
||||
await SyncThumbnail(addon, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
await SyncThumbnail(addon);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -293,9 +302,9 @@ namespace WowUp.WPF.Services
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SyncThumbnail(Addon addon)
|
||||
private async Task SyncThumbnail(Addon addon, bool force = false)
|
||||
{
|
||||
if (!File.Exists(addon.GetThumbnailPath()))
|
||||
if (force || !File.Exists(addon.GetThumbnailPath()))
|
||||
{
|
||||
await CacheThumbnail(addon);
|
||||
}
|
||||
@@ -480,6 +489,7 @@ namespace WowUp.WPF.Services
|
||||
|
||||
try
|
||||
{
|
||||
Log.Information($"Caching thumbnail {addon.Name}: {addon.ThumbnailUrl}");
|
||||
using var imageStream = await addon.ThumbnailUrl.GetStreamAsync();
|
||||
|
||||
using Image image = Image.Load(imageStream);
|
||||
@@ -496,7 +506,7 @@ namespace WowUp.WPF.Services
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_analyticsService.Track(ex, "Failed to download thumbnail");
|
||||
_analyticsService.Track(ex, $"Failed to download thumbnail {addon.Name}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -620,6 +630,8 @@ namespace WowUp.WPF.Services
|
||||
}
|
||||
}
|
||||
|
||||
Log.Debug($"Scanned {addonFolders.Count()} folders");
|
||||
|
||||
var matchedAddonFolders = addonFolders.Where(af => af.MatchingAddon != null);
|
||||
var matchedGroups = matchedAddonFolders.GroupBy(af => $"{af.MatchingAddon.ProviderName}{af.MatchingAddon.ExternalId}");
|
||||
|
||||
|
||||
@@ -25,5 +25,7 @@ namespace WowUp.WPF.Services.Contracts
|
||||
string GetAddonFolderPath(WowClientType clientType);
|
||||
|
||||
Task<IEnumerable<AddonFolder>> ListAddons(WowClientType clientType);
|
||||
|
||||
string GetClientFolderName(WowClientType clientType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,12 @@ using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
using WowUp.Common.Enums;
|
||||
using WowUp.Common.Models;
|
||||
using WowUp.Common.Models.Events;
|
||||
using WowUp.WPF.Extensions;
|
||||
using WowUp.WPF.Services.Contracts;
|
||||
|
||||
namespace WowUp.WPF.Services
|
||||
@@ -54,7 +57,6 @@ namespace WowUp.WPF.Services
|
||||
StatusText = string.Empty,
|
||||
UpdaterReady = false
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private async void UpdateCheckTimerElapsed()
|
||||
@@ -112,9 +114,16 @@ namespace WowUp.WPF.Services
|
||||
SessionChanged?.Invoke(this, new SessionEventArgs(_sessionState));
|
||||
}
|
||||
|
||||
public void AppLoaded()
|
||||
public async void AppLoaded()
|
||||
{
|
||||
if(_updateCheckTimer == null)
|
||||
if (App.StartupOptions != null && App.StartupOptions.ClientType != WowClientType.None)
|
||||
{
|
||||
SelectedClientType = App.StartupOptions.ClientType;
|
||||
}
|
||||
|
||||
await ProcessInputUrls();
|
||||
|
||||
if (_updateCheckTimer == null)
|
||||
{
|
||||
_updateCheckTimer = new Timer(_ => UpdateCheckTimerElapsed(), null, TimeSpan.FromSeconds(0), TimeSpan.FromMinutes(60));
|
||||
}
|
||||
@@ -136,6 +145,41 @@ namespace WowUp.WPF.Services
|
||||
SetContextText(text);
|
||||
}
|
||||
|
||||
private async Task ProcessInputUrls()
|
||||
{
|
||||
if (!App.StartupOptions?.InputURLs.Any() ?? false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await App.StartupOptions.InputURLs.ForEachAsync(2, async x =>
|
||||
{
|
||||
PotentialAddon potentialAddon = null;
|
||||
try
|
||||
{
|
||||
potentialAddon = await _addonService.GetAddonByUri(new Uri(x), SelectedClientType);
|
||||
}
|
||||
catch
|
||||
{
|
||||
MessageBox.Show($"Failed to import addon by URI: {x}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (potentialAddon != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _addonService.InstallAddon(potentialAddon, SelectedClientType);
|
||||
}
|
||||
catch
|
||||
{
|
||||
MessageBox.Show($"Failed to install addon {potentialAddon.Name}");
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private async void ProcessAutoUpdates()
|
||||
{
|
||||
var updateCount = await _addonService.ProcessAutoUpdates();
|
||||
@@ -144,6 +188,13 @@ namespace WowUp.WPF.Services
|
||||
{
|
||||
TaskbarIcon.ShowBalloonTip("WowUp", $"Automatically updated {updateCount} addons.", TaskbarIcon.Icon, true);
|
||||
}
|
||||
|
||||
if (App.StartupOptions?.Quit == true)
|
||||
{
|
||||
// Artificial delay to allow notification to fire.
|
||||
await Task.Delay(3000);
|
||||
await Application.Current.Dispatcher.BeginInvoke(() => { Application.Current.Shutdown(); }, DispatcherPriority.SystemIdle);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetContextText(string text)
|
||||
|
||||
@@ -246,6 +246,7 @@ namespace WowUp.WPF.Services
|
||||
|
||||
foreach (var directory in addonDirectories)
|
||||
{
|
||||
Log.Debug($"Getting addon folder {directory.Name}");
|
||||
var addonFolder = await GetAddonFolder(directory);
|
||||
addons.Add(addonFolder);
|
||||
}
|
||||
@@ -253,6 +254,19 @@ namespace WowUp.WPF.Services
|
||||
return addons;
|
||||
}
|
||||
|
||||
public string GetClientFolderName(WowClientType clientType)
|
||||
{
|
||||
return clientType switch
|
||||
{
|
||||
WowClientType.Retail => RetailFolderName,
|
||||
WowClientType.Classic => ClassicFolderName,
|
||||
WowClientType.RetailPtr => RetailPtrFolderName,
|
||||
WowClientType.ClassicPtr => ClassicPtrFolderName,
|
||||
WowClientType.Beta => BetaFolderName,
|
||||
_ => string.Empty,
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<AddonFolder> GetAddonFolder(DirectoryInfo directory)
|
||||
{
|
||||
var toc = await ParseToc(directory);
|
||||
@@ -295,19 +309,6 @@ namespace WowUp.WPF.Services
|
||||
return new TocParser(fileText).GetMetaData();
|
||||
}
|
||||
|
||||
private string GetClientFolderName(WowClientType clientType)
|
||||
{
|
||||
return clientType switch
|
||||
{
|
||||
WowClientType.Retail => RetailFolderName,
|
||||
WowClientType.Classic => ClassicFolderName,
|
||||
WowClientType.RetailPtr => RetailPtrFolderName,
|
||||
WowClientType.ClassicPtr => ClassicPtrFolderName,
|
||||
WowClientType.Beta => BetaFolderName,
|
||||
_ => string.Empty,
|
||||
};
|
||||
}
|
||||
|
||||
private string GetClientLocationPreferenceKey(WowClientType clientType)
|
||||
{
|
||||
return clientType switch
|
||||
|
||||
@@ -281,7 +281,7 @@ namespace WowUp.WPF.ViewModels
|
||||
_epicBrush = Application.Current.Resources["EpicBrush"] as SolidColorBrush;
|
||||
}
|
||||
|
||||
private void SetupDisplayState()
|
||||
public void SetupDisplayState()
|
||||
{
|
||||
Name = _addon.Name;
|
||||
CurrentVersion = string.IsNullOrEmpty(_addon.InstalledVersion)
|
||||
|
||||
@@ -10,7 +10,6 @@ using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using WowUp.Common.Enums;
|
||||
using WowUp.Common.Services.Contracts;
|
||||
using WowUp.WPF.Entities;
|
||||
using WowUp.WPF.Extensions;
|
||||
using WowUp.WPF.Services.Contracts;
|
||||
@@ -23,12 +22,16 @@ namespace WowUp.WPF.ViewModels
|
||||
private static readonly object ClientNamesLock = new object();
|
||||
private static readonly object DisplayAddonsLock = new object();
|
||||
|
||||
private readonly IAnalyticsService _analyticsService;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IWarcraftService _warcraftService;
|
||||
private readonly IAddonService _addonService;
|
||||
private readonly ISessionService _sessionService;
|
||||
|
||||
private List<Addon> _addons;
|
||||
private bool _disableUpdateLoad;
|
||||
private IEnumerable<AddonListItemViewModel> _selectedRows;
|
||||
private IEnumerable<Addon> _selectedAddons;
|
||||
|
||||
private string _busyText;
|
||||
public string BusyText
|
||||
@@ -170,6 +173,48 @@ namespace WowUp.WPF.ViewModels
|
||||
set { SetProperty(ref _selectedClientType, value); }
|
||||
}
|
||||
|
||||
private ContextMenu _activeContextMenu;
|
||||
public ContextMenu ActiveContextMenu
|
||||
{
|
||||
get => _activeContextMenu;
|
||||
set { SetProperty(ref _activeContextMenu, value); }
|
||||
}
|
||||
|
||||
private string _multiRowMenuTitle;
|
||||
public string MultiRowMenuTitle
|
||||
{
|
||||
get => _multiRowMenuTitle;
|
||||
set { SetProperty(ref _multiRowMenuTitle, value); }
|
||||
}
|
||||
|
||||
private bool _multiRowMenuAutoUpdateCheck;
|
||||
public bool MultiRowMenuAutoUpdateCheck
|
||||
{
|
||||
get => _multiRowMenuAutoUpdateCheck;
|
||||
set { SetProperty(ref _multiRowMenuAutoUpdateCheck, value); }
|
||||
}
|
||||
|
||||
private bool _multiRowMenuStableChannelCheck;
|
||||
public bool MultiRowMenuStableChannelCheck
|
||||
{
|
||||
get => _multiRowMenuStableChannelCheck;
|
||||
set { SetProperty(ref _multiRowMenuStableChannelCheck, value); }
|
||||
}
|
||||
|
||||
private bool _multiRowMenuBetaChannelCheck;
|
||||
public bool MultiRowMenuBetaChannelCheck
|
||||
{
|
||||
get => _multiRowMenuBetaChannelCheck;
|
||||
set { SetProperty(ref _multiRowMenuBetaChannelCheck, value); }
|
||||
}
|
||||
|
||||
private bool _multiRowMenuAlphaChannelCheck;
|
||||
public bool MultiRowMenuAlphaChannelCheck
|
||||
{
|
||||
get => _multiRowMenuAlphaChannelCheck;
|
||||
set { SetProperty(ref _multiRowMenuAlphaChannelCheck, value); }
|
||||
}
|
||||
|
||||
public SearchInputViewModel SearchInputViewModel { get; set; }
|
||||
|
||||
public Command LoadItemsCommand { get; set; }
|
||||
@@ -181,17 +226,28 @@ namespace WowUp.WPF.ViewModels
|
||||
public Command SelectedWowClientCommand { get; set; }
|
||||
public Command GridSortingCommand { get; set; }
|
||||
public Command ViewInitializedCommand { get; set; }
|
||||
public Command AutoUpdateCheckedCommand { get; set; }
|
||||
public Command StableChannelCheckedCommand { get; set; }
|
||||
public Command BetaChannelCheckedCommand { get; set; }
|
||||
public Command AlphaChannelCheckedCommand { get; set; }
|
||||
public Command ReInstallAllCommand { get; set; }
|
||||
public Command UninstallAllCommand { get; set; }
|
||||
|
||||
public ContextMenu MultiRowMenu { get; set; }
|
||||
public ContextMenu RowMenu { get; set; }
|
||||
|
||||
public ObservableCollection<AddonListItemViewModel> DisplayAddons { get; set; }
|
||||
public ObservableCollection<WowClientType> ClientTypeNames { get; set; }
|
||||
|
||||
public AddonsViewViewModel(
|
||||
IAnalyticsService analyticsService,
|
||||
IServiceProvider serviceProvider,
|
||||
IAddonService addonService,
|
||||
IWarcraftService warcraftService,
|
||||
ISessionService sessionService)
|
||||
{
|
||||
_addonService = addonService;
|
||||
_analyticsService = analyticsService;
|
||||
_warcraftService = warcraftService;
|
||||
_serviceProvider = serviceProvider;
|
||||
_sessionService = sessionService;
|
||||
@@ -244,6 +300,12 @@ namespace WowUp.WPF.ViewModels
|
||||
SelectedWowClientCommand = new Command(async () => await OnSelectedWowClientChanged(SelectedClientType));
|
||||
GridSortingCommand = new Command((args) => OnGridSorting(args as DataGridSortingEventArgs));
|
||||
ViewInitializedCommand = new Command(() => OnViewInitialized());
|
||||
AutoUpdateCheckedCommand = new Command(() => OnAutoUpdateCheckedCommand());
|
||||
StableChannelCheckedCommand = new Command(() => OnChangeAllChannelCommand(AddonChannelType.Stable));
|
||||
BetaChannelCheckedCommand = new Command(() => OnChangeAllChannelCommand(AddonChannelType.Beta));
|
||||
AlphaChannelCheckedCommand = new Command(() => OnChangeAllChannelCommand(AddonChannelType.Alpha));
|
||||
ReInstallAllCommand = new Command(async () => await ReInstallAll());
|
||||
UninstallAllCommand = new Command(async () => await UninstallAll());
|
||||
|
||||
SearchInputViewModel = serviceProvider.GetService<SearchInputViewModel>();
|
||||
SearchInputViewModel.TextChanged += SearchInputViewModel_TextChanged;
|
||||
@@ -261,6 +323,138 @@ namespace WowUp.WPF.ViewModels
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void OnAutoUpdateCheckedCommand()
|
||||
{
|
||||
_disableUpdateLoad = true;
|
||||
foreach (var addon in _selectedAddons)
|
||||
{
|
||||
addon.AutoUpdateEnabled = MultiRowMenuAutoUpdateCheck;
|
||||
_addonService.UpdateAddon(addon);
|
||||
|
||||
var listItem = DisplayAddons.FirstOrDefault(item => item.Addon.Id == addon.Id);
|
||||
listItem.IsAutoUpdated = addon.AutoUpdateEnabled;
|
||||
}
|
||||
_disableUpdateLoad = false;
|
||||
}
|
||||
|
||||
private void OnChangeAllChannelCommand(AddonChannelType addonChannel)
|
||||
{
|
||||
_disableUpdateLoad = true;
|
||||
foreach (var addon in _selectedAddons)
|
||||
{
|
||||
addon.ChannelType = addonChannel;
|
||||
_addonService.UpdateAddon(addon);
|
||||
|
||||
var listItem = DisplayAddons.FirstOrDefault(item => item.Addon.Id == addon.Id);
|
||||
listItem.Addon.ChannelType = addonChannel;
|
||||
listItem.SetupDisplayState();
|
||||
}
|
||||
|
||||
SetSelectionChannelState();
|
||||
|
||||
_disableUpdateLoad = false;
|
||||
}
|
||||
|
||||
private async Task ReInstallAll()
|
||||
{
|
||||
IsBusy = true;
|
||||
EnableUpdateAll = false;
|
||||
EnableRefresh = false;
|
||||
EnableRescan = false;
|
||||
|
||||
await _selectedAddons.ForEachAsync(2, async (addon) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await _addonService.InstallAddon(addon.Id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_analyticsService.Track(ex, "Failed during bulk install");
|
||||
}
|
||||
});
|
||||
|
||||
IsBusy = false;
|
||||
EnableUpdateAll = CanUpdateAll;
|
||||
EnableRefresh = true;
|
||||
EnableRescan = true;
|
||||
|
||||
await _analyticsService.TrackUserAction(
|
||||
"Addons",
|
||||
"ReInstallBulk",
|
||||
_selectedAddons.Count().ToString());
|
||||
}
|
||||
|
||||
public async Task UninstallAll()
|
||||
{
|
||||
var messageBoxResult = MessageBox.Show(
|
||||
$"Are you sure you want to remove {_selectedAddons.Count()} addons? This will remove all related folders from your World of Warcraft folder.",
|
||||
"Uninstall Addon?",
|
||||
MessageBoxButton.YesNo);
|
||||
|
||||
if (messageBoxResult != MessageBoxResult.Yes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IsBusy = true;
|
||||
EnableUpdateAll = false;
|
||||
EnableRefresh = false;
|
||||
EnableRescan = false;
|
||||
|
||||
foreach (var addon in _selectedAddons.ToList())
|
||||
{
|
||||
try
|
||||
{
|
||||
await _addonService.UninstallAddon(addon);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Failed to uninstall addon {addon.Name}");
|
||||
}
|
||||
}
|
||||
|
||||
IsBusy = false;
|
||||
EnableUpdateAll = CanUpdateAll;
|
||||
EnableRefresh = true;
|
||||
EnableRescan = true;
|
||||
|
||||
await _analyticsService.TrackUserAction(
|
||||
"Addons",
|
||||
"UninstallBulk",
|
||||
_selectedAddons.Count().ToString());
|
||||
}
|
||||
|
||||
public void OnDataGridSelectionChange(
|
||||
IEnumerable<AddonListItemViewModel> selectedItems)
|
||||
{
|
||||
_selectedRows = selectedItems;
|
||||
_selectedAddons = selectedItems.Select(item => item.Addon);
|
||||
MultiRowMenuTitle = selectedItems.Count() > 1
|
||||
? $"{selectedItems.Count()} addons selected"
|
||||
: string.Empty;
|
||||
|
||||
ActiveContextMenu = selectedItems.Count() > 1
|
||||
? MultiRowMenu
|
||||
: RowMenu;
|
||||
|
||||
MultiRowMenuAutoUpdateCheck = selectedItems.All(item => item.IsAutoUpdated);
|
||||
|
||||
SetSelectionChannelState();
|
||||
}
|
||||
|
||||
private void SetSelectionChannelState()
|
||||
{
|
||||
MultiRowMenuStableChannelCheck = _selectedRows
|
||||
.All(item => item.Addon.ChannelType == AddonChannelType.Stable);
|
||||
|
||||
MultiRowMenuBetaChannelCheck = _selectedRows
|
||||
.All(item => item.Addon.ChannelType == AddonChannelType.Beta);
|
||||
|
||||
MultiRowMenuAlphaChannelCheck = _selectedRows
|
||||
.All(item => item.Addon.ChannelType == AddonChannelType.Alpha);
|
||||
}
|
||||
|
||||
private void SessionService_TabChanged(object sender, Type tabType)
|
||||
{
|
||||
SetAddonCountContextText(DisplayAddons.Count);
|
||||
@@ -377,13 +571,15 @@ namespace WowUp.WPF.ViewModels
|
||||
}
|
||||
finally
|
||||
{
|
||||
EnableUpdateAll = DisplayAddons.Any(addon => addon.CanUpdate || addon.CanInstall);
|
||||
EnableUpdateAll = CanUpdateAll;
|
||||
EnableRefresh = true;
|
||||
EnableRescan = true;
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanUpdateAll => DisplayAddons.Any(addon => addon.CanUpdate || addon.CanInstall);
|
||||
|
||||
public async Task UpdateAllRetailClassic()
|
||||
{
|
||||
await UpdateAllWithSpinner(WowClientType.Retail, WowClientType.Classic);
|
||||
@@ -558,8 +754,10 @@ namespace WowUp.WPF.ViewModels
|
||||
}
|
||||
|
||||
// If this addon is already in the list, ignore it
|
||||
if (DisplayAddons.Any(da => da.Addon.Id == addon.Id))
|
||||
var displayItem = DisplayAddons.FirstOrDefault(listItem => listItem.Addon.Id == addon.Id);
|
||||
if (displayItem != null)
|
||||
{
|
||||
displayItem.ThumbnailUrl = addon.ThumbnailUrl;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -579,7 +777,7 @@ namespace WowUp.WPF.ViewModels
|
||||
|
||||
private void AddonUpdated(Addon addon)
|
||||
{
|
||||
if (IsBusy)
|
||||
if (IsBusy || _disableUpdateLoad)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using Hardcodet.Wpf.TaskbarNotification;
|
||||
using Hardcodet.Wpf.TaskbarNotification;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using WowUp.Common.Services.Contracts;
|
||||
using WowUp.Common.Enums;
|
||||
using WowUp.WPF.Entities;
|
||||
using WowUp.WPF.Extensions;
|
||||
using WowUp.WPF.Repositories.Contracts;
|
||||
@@ -27,10 +27,15 @@ namespace WowUp.WPF.ViewModels
|
||||
private readonly IAnalyticsService _analyticsService;
|
||||
private readonly ISessionService _sessionService;
|
||||
|
||||
public ObservableCollection<WowClientType> WowClientTypes { get; set; }
|
||||
public ObservableCollection<TabItem> TabItems { get; set; }
|
||||
|
||||
public Command SelectWowCommand { get; set; }
|
||||
public Command CloseWindowCommand { get; set; }
|
||||
public Command TaskbarIconCloseCommand { get; set; }
|
||||
public Command TaskbarIconClickCommand { get; set; }
|
||||
public Command SetWowLocationCommand { get; set; }
|
||||
public Command SelectedWowClientChangedCommand { get; set; }
|
||||
|
||||
private TaskbarIcon _taskbarIcon;
|
||||
public TaskbarIcon TaskbarIcon
|
||||
@@ -116,7 +121,19 @@ namespace WowUp.WPF.ViewModels
|
||||
set { SetProperty(ref _contextText, value); }
|
||||
}
|
||||
|
||||
public ObservableCollection<TabItem> TabItems { get; set; }
|
||||
private WowClientType _selectedClientType;
|
||||
public WowClientType SelectedClientType
|
||||
{
|
||||
get => _selectedClientType;
|
||||
set { SetProperty(ref _selectedClientType, value); }
|
||||
}
|
||||
|
||||
private string _wowClientHint;
|
||||
public string WowClientHint
|
||||
{
|
||||
get => _wowClientHint;
|
||||
set { SetProperty(ref _wowClientHint, value); }
|
||||
}
|
||||
|
||||
public ApplicationUpdateControlViewModel ApplicationUpdateControlViewModel { get; set; }
|
||||
|
||||
@@ -140,17 +157,59 @@ namespace WowUp.WPF.ViewModels
|
||||
CloseWindowCommand = new Command(() => OnCloseWindow());
|
||||
TaskbarIconCloseCommand = new Command(() => OnTaskbarIconClose());
|
||||
TaskbarIconClickCommand = new Command(() => OnTaskbarIconClick());
|
||||
SetWowLocationCommand = new Command(() => OnSetWowLocation());
|
||||
SelectedWowClientChangedCommand = new Command(() => OnSelectedWowClientChanged());
|
||||
|
||||
ApplicationUpdateControlViewModel = serviceProvider.GetService<ApplicationUpdateControlViewModel>();
|
||||
|
||||
TabItems = new ObservableCollection<TabItem>();
|
||||
|
||||
WowClientTypes = new ObservableCollection<WowClientType>(
|
||||
Enum.GetValues(typeof(WowClientType))
|
||||
.Cast<WowClientType>()
|
||||
.Where(type => type != WowClientType.None));
|
||||
|
||||
migrationService.MigrateDatabase();
|
||||
|
||||
InitializeView();
|
||||
|
||||
_sessionService.SessionChanged += SessionService_SessionChanged;
|
||||
_sessionService.ContextTextChanged += SessionService_ContextTextChanged;
|
||||
|
||||
SetClientHint();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle when the user wants to change the install folder for a particular client
|
||||
/// </summary>
|
||||
/// <param name="clientType"></param>
|
||||
private void OnSetWowLocation()
|
||||
{
|
||||
var selectedPath = DialogUtilities.SelectFolder();
|
||||
if (string.IsNullOrEmpty(selectedPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_warcraftService.SetWowFolderPath(SelectedClientType, selectedPath))
|
||||
{
|
||||
MessageBox.Show($"Unable to set \"{selectedPath}\" as your {SelectedClientType} folder");
|
||||
return;
|
||||
}
|
||||
|
||||
_sessionService.SelectedClientType = SelectedClientType;
|
||||
InitializeView();
|
||||
}
|
||||
|
||||
private void OnSelectedWowClientChanged()
|
||||
{
|
||||
SetClientHint();
|
||||
}
|
||||
|
||||
private void SetClientHint()
|
||||
{
|
||||
var clientFolderName = _warcraftService.GetClientFolderName(SelectedClientType);
|
||||
WowClientHint = $"Select the folder that contains the {SelectedClientType} client folder _{clientFolderName}";
|
||||
}
|
||||
|
||||
private void OnTaskbarIconClick()
|
||||
@@ -160,6 +219,7 @@ namespace WowUp.WPF.ViewModels
|
||||
return;
|
||||
}
|
||||
|
||||
Application.Current.MainWindow.ShowInTaskbar = true;
|
||||
Application.Current.MainWindow.Show();
|
||||
Application.Current.MainWindow.WindowState = WindowState.Normal;
|
||||
Application.Current.MainWindow.Activate();
|
||||
@@ -196,6 +256,13 @@ namespace WowUp.WPF.ViewModels
|
||||
|
||||
public void OnSourceInitialized(Window window)
|
||||
{
|
||||
if (App.StartupOptions?.Minimized == true)
|
||||
{
|
||||
window.Hide();
|
||||
window.ShowInTaskbar = false;
|
||||
window.WindowState = WindowState.Minimized;
|
||||
}
|
||||
|
||||
var windowPref = _preferenceRepository.FindByKey(WindowPlacementKey);
|
||||
var windowStatePref = _preferenceRepository.FindByKey(WindowStateKey);
|
||||
if (windowPref == null)
|
||||
|
||||
@@ -192,17 +192,17 @@ namespace WowUp.WPF.ViewModels
|
||||
WowUpReleaseChannelChangedCommand = new Command(() => OnWowUpReleaseChannelChange(SelectedWowUpReleaseChannelType));
|
||||
DumpDebugDataCommand = new Command(() => DumpDebugData());
|
||||
|
||||
RetailAddonChannelChangeCommand = new Command(() => OnAddonChannelChange(WowClientType.Retail, SelectedRetailAddonChannelType));;
|
||||
RetailAddonChannelChangeCommand = new Command(() => OnAddonChannelChange(WowClientType.Retail, SelectedRetailAddonChannelType));
|
||||
RetailPtrAddonChannelChangeCommand = new Command(() => OnAddonChannelChange(WowClientType.RetailPtr, SelectedRetailPtrAddonChannelType));
|
||||
ClassicAddonChannelChangeCommand = new Command(() => OnAddonChannelChange(WowClientType.Classic, SelectedClassicAddonChannelType));
|
||||
ClassicPtrAddonChannelChangeCommand = new Command(() => OnAddonChannelChange(WowClientType.ClassicPtr, SelectedClassicPtrAddonChannelType));
|
||||
BetaAddonChannelChangeCommand = new Command(() => OnAddonChannelChange(WowClientType.Beta, SelectedBetaAddonChannelType));
|
||||
|
||||
RetailAutoUpdateChangeCommand = new Command(() => OnAddonAutoUpdateChange(WowClientType.Retail, RetailAutoUpdateAddons)); ;
|
||||
RetailPtrAutoUpdateChangeCommand = new Command(() => OnAddonAutoUpdateChange(WowClientType.RetailPtr, RetailPtrAutoUpdateAddons)); ;
|
||||
ClassicAutoUpdateChangeCommand = new Command(() => OnAddonAutoUpdateChange(WowClientType.Classic, ClassicAutoUpdateAddons)); ;
|
||||
ClassicPtrAutoUpdateChangeCommand = new Command(() => OnAddonAutoUpdateChange(WowClientType.ClassicPtr, ClassicPtrAutoUpdateAddons)); ;
|
||||
BetaAutoUpdateChangeCommand = new Command(() => OnAddonAutoUpdateChange(WowClientType.Beta, BetaAutoUpdateAddons)); ;
|
||||
RetailAutoUpdateChangeCommand = new Command(() => OnAddonAutoUpdateChange(WowClientType.Retail, RetailAutoUpdateAddons));
|
||||
RetailPtrAutoUpdateChangeCommand = new Command(() => OnAddonAutoUpdateChange(WowClientType.RetailPtr, RetailPtrAutoUpdateAddons));
|
||||
ClassicAutoUpdateChangeCommand = new Command(() => OnAddonAutoUpdateChange(WowClientType.Classic, ClassicAutoUpdateAddons));
|
||||
ClassicPtrAutoUpdateChangeCommand = new Command(() => OnAddonAutoUpdateChange(WowClientType.ClassicPtr, ClassicPtrAutoUpdateAddons));
|
||||
BetaAutoUpdateChangeCommand = new Command(() => OnAddonAutoUpdateChange(WowClientType.Beta, BetaAutoUpdateAddons));
|
||||
|
||||
AddonChannelNames = new ObservableCollection<AddonChannelType>
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
xmlns:vw = "clr-namespace:WowUp.WPF.Views"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
x:Name="AddonsViewControl"
|
||||
Initialized="UserControl_Initialized">
|
||||
|
||||
<UserControl.Resources>
|
||||
@@ -247,10 +248,40 @@
|
||||
HorizontalGridLinesBrush="{StaticResource Dark2}"
|
||||
RowHeaderWidth="0"
|
||||
BorderThickness="0"
|
||||
SelectionMode="Extended"
|
||||
VirtualizingPanel.ScrollUnit="Pixel"
|
||||
SelectionChanged="AddonGrid_SelectionChanged"
|
||||
BorderBrush="Transparent"
|
||||
Sorting="AddonGrid_Sorting">
|
||||
<DataGrid.Resources>
|
||||
<ContextMenu x:Key="MultiRowMenu"
|
||||
DataContext="{Binding DataContext, Source={x:Reference AddonsViewControl}}"
|
||||
Style="{StaticResource DarkMenu}">
|
||||
<MenuItem Header="{Binding MultiRowMenuTitle}" IsEnabled="False" />
|
||||
<MenuItem Header="Auto Update"
|
||||
IsCheckable="True"
|
||||
IsChecked="{Binding MultiRowMenuAutoUpdateCheck}"
|
||||
Command="{Binding AutoUpdateCheckedCommand}" />
|
||||
<MenuItem Header="Channel">
|
||||
<MenuItem Header="Stable"
|
||||
IsCheckable="True"
|
||||
IsChecked="{Binding MultiRowMenuStableChannelCheck}"
|
||||
Command="{Binding StableChannelCheckedCommand}"></MenuItem>
|
||||
<MenuItem Header="Beta"
|
||||
IsCheckable="True"
|
||||
IsChecked="{Binding MultiRowMenuBetaChannelCheck}"
|
||||
Command="{Binding BetaChannelCheckedCommand}"></MenuItem>
|
||||
<MenuItem Header="Alpha"
|
||||
IsCheckable="True"
|
||||
IsChecked="{Binding MultiRowMenuAlphaChannelCheck}"
|
||||
Command="{Binding AlphaChannelCheckedCommand}"></MenuItem>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Re-Install"
|
||||
Command="{Binding ReInstallAllCommand}"/>
|
||||
<Separator />
|
||||
<MenuItem Header="Remove"
|
||||
Command="{Binding UninstallAllCommand}"/>
|
||||
</ContextMenu>
|
||||
<ContextMenu x:Key="RowMenu"
|
||||
Style="{StaticResource DarkMenu}"
|
||||
DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
|
||||
@@ -326,12 +357,15 @@
|
||||
</DataGrid.Resources>
|
||||
<DataGrid.RowStyle>
|
||||
<Style TargetType="DataGridRow" >
|
||||
<Setter Property="ContextMenu" Value="{StaticResource RowMenu}" />
|
||||
<Setter Property="ContextMenu" Value="{Binding DataContext.ActiveContextMenu, RelativeSource={RelativeSource AncestorType=UserControl}}" />
|
||||
<Setter Property="Background" Value="{StaticResource Dark3}"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource Dark1}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource Purple4}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGrid.RowStyle>
|
||||
@@ -388,8 +422,7 @@
|
||||
<DataTemplate>
|
||||
<Border Padding="5">
|
||||
<StackPanel Orientation="Horizontal" >
|
||||
<TextBlock
|
||||
Text="{Binding DataContext.LatestVersionHeaderText, RelativeSource={RelativeSource AncestorType=DataGrid}}"
|
||||
<TextBlock Text="{Binding DataContext.LatestVersionHeaderText, RelativeSource={RelativeSource AncestorType=DataGrid}}"
|
||||
TextWrapping="Wrap"
|
||||
Style="{StaticResource labelTableHeader}" />
|
||||
<Image Width="20"
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using System.Windows.Controls;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Controls;
|
||||
using WowUp.WPF.Extensions;
|
||||
using WowUp.WPF.ViewModels;
|
||||
|
||||
@@ -46,7 +49,15 @@ namespace WowUp.WPF.Views
|
||||
|
||||
private void UserControl_Initialized(object sender, System.EventArgs e)
|
||||
{
|
||||
_viewModel.MultiRowMenu = (ContextMenu)AddonGrid.Resources["MultiRowMenu"];
|
||||
_viewModel.RowMenu = (ContextMenu)AddonGrid.Resources["RowMenu"];
|
||||
_viewModel.ViewInitializedCommand.Execute(e);
|
||||
}
|
||||
|
||||
private void AddonGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
var selectedItems = ((DataGrid)sender).SelectedItems.Cast<AddonListItemViewModel>();
|
||||
_viewModel.OnDataGridSelectionChange(selectedItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<Color x:Key="Purple1Color">#6B69D6</Color>
|
||||
<Color x:Key="Purple2Color">#504FA1</Color>
|
||||
<Color x:Key="Purple3Color">#383773</Color>
|
||||
<Color x:Key="Purple4Color">#282836</Color>
|
||||
<Color x:Key="White1Color">#FFFFFF</Color>
|
||||
<Color x:Key="White2Color">#DDDDDD</Color>
|
||||
<Color x:Key="White3Color">#CCCCCC</Color>
|
||||
@@ -45,6 +46,7 @@
|
||||
<SolidColorBrush x:Key="Purple1">#6B69D6</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="Purple2">#504FA1</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="Purple3">#383773</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="Purple4">#282836</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="Blue1Brush">#315891</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="Blue2Brush">#24416c</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="Highlight1Brush">#01BAEF</SolidColorBrush>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<PackageId>WowUp</PackageId>
|
||||
<Authors>Jliddev</Authors>
|
||||
<Product>WowUp</Product>
|
||||
<Version>1.18.0-beta.3</Version>
|
||||
<Version>1.18.0-beta.12</Version>
|
||||
<ApplicationIcon>wowup_logo_512np_RRT_icon.ico</ApplicationIcon>
|
||||
<Copyright>jliddev</Copyright>
|
||||
<PackageProjectUrl>https://wowup.io</PackageProjectUrl>
|
||||
@@ -54,6 +54,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommandLineParser" Version="2.8.0" />
|
||||
<PackageReference Include="Flurl.Http" Version="2.4.2" />
|
||||
<PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="1.0.8" />
|
||||
<PackageReference Include="Microsoft.AppCenter.Analytics" Version="3.4.1" />
|
||||
|
||||
Reference in New Issue
Block a user