From 526bc2661aeae655a3d75cb9ae0d67ea625284d0 Mon Sep 17 00:00:00 2001 From: SpoinkyNL Date: Fri, 3 Jun 2016 20:59:58 +0200 Subject: [PATCH] Added layer unsaved changes warning --- Artemis/Artemis/Artemis.csproj | 3 +- .../ILayerEditorVmFactory.cs | 12 +++ .../IProfileEditorViewModelFactory.cs | 12 --- .../IProfileEditorVmFactory.cs | 13 ++++ .../Artemis/InjectionModules/BaseModules.cs | 3 +- .../CounterStrike/CounterStrikeViewModel.cs | 2 +- .../Modules/Games/Dota2/Dota2ViewModel.cs | 2 +- .../Games/Overwatch/OverwatchViewModel.cs | 2 +- .../RocketLeague/RocketLeagueViewModel.cs | 2 +- .../Games/TheDivision/TheDivisionViewModel.cs | 2 +- .../Games/Witcher3/Witcher3ViewModel.cs | 2 +- Artemis/Artemis/Utilities/GeneralHelpers.cs | 15 ++++ .../ViewModels/Abstract/GameViewModel.cs | 6 +- .../Profiles/LayerEditorViewModel.cs | 76 ++++++++++++------- .../Profiles/ProfileEditorViewModel.cs | 11 ++- .../Views/Profiles/LayerEditorView.xaml | 2 +- 16 files changed, 111 insertions(+), 54 deletions(-) create mode 100644 Artemis/Artemis/InjectionFactories/ILayerEditorVmFactory.cs delete mode 100644 Artemis/Artemis/InjectionFactories/IProfileEditorViewModelFactory.cs create mode 100644 Artemis/Artemis/InjectionFactories/IProfileEditorVmFactory.cs diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj index d9384595c..e62a1d2e4 100644 --- a/Artemis/Artemis/Artemis.csproj +++ b/Artemis/Artemis/Artemis.csproj @@ -289,7 +289,8 @@ - + + diff --git a/Artemis/Artemis/InjectionFactories/ILayerEditorVmFactory.cs b/Artemis/Artemis/InjectionFactories/ILayerEditorVmFactory.cs new file mode 100644 index 000000000..67a0e6672 --- /dev/null +++ b/Artemis/Artemis/InjectionFactories/ILayerEditorVmFactory.cs @@ -0,0 +1,12 @@ +using Artemis.Models.Interfaces; +using Artemis.Models.Profiles; +using Artemis.Services; +using Artemis.ViewModels.Profiles; + +namespace Artemis.InjectionFactories +{ + public interface ILayerEditorVmFactory + { + LayerEditorViewModel CreateLayerEditorVm(IGameDataModel gameDataModel, LayerModel layer); + } +} \ No newline at end of file diff --git a/Artemis/Artemis/InjectionFactories/IProfileEditorViewModelFactory.cs b/Artemis/Artemis/InjectionFactories/IProfileEditorViewModelFactory.cs deleted file mode 100644 index 38b247a80..000000000 --- a/Artemis/Artemis/InjectionFactories/IProfileEditorViewModelFactory.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Artemis.Managers; -using Artemis.Models; -using Artemis.ViewModels.Profiles; -using Caliburn.Micro; - -namespace Artemis.InjectionFactories -{ - public interface IProfileEditorViewModelFactory - { - ProfileEditorViewModel CreateProfileEditorViewModel(IEventAggregator events, MainManager mainManager, GameModel gameModel, string lastProfile); - } -} \ No newline at end of file diff --git a/Artemis/Artemis/InjectionFactories/IProfileEditorVmFactory.cs b/Artemis/Artemis/InjectionFactories/IProfileEditorVmFactory.cs new file mode 100644 index 000000000..c6bc58d58 --- /dev/null +++ b/Artemis/Artemis/InjectionFactories/IProfileEditorVmFactory.cs @@ -0,0 +1,13 @@ +using Artemis.Managers; +using Artemis.Models; +using Artemis.ViewModels.Profiles; +using Caliburn.Micro; + +namespace Artemis.InjectionFactories +{ + public interface IProfileEditorVmFactory + { + ProfileEditorViewModel CreateProfileEditorVm(IEventAggregator events, MainManager mainManager, + GameModel gameModel, string lastProfile); + } +} \ No newline at end of file diff --git a/Artemis/Artemis/InjectionModules/BaseModules.cs b/Artemis/Artemis/InjectionModules/BaseModules.cs index dcbcc440b..05805579a 100644 --- a/Artemis/Artemis/InjectionModules/BaseModules.cs +++ b/Artemis/Artemis/InjectionModules/BaseModules.cs @@ -16,7 +16,8 @@ namespace Artemis.InjectionModules { // ViewModels Bind().To().InSingletonScope(); - Bind().ToFactory(); + Bind().ToFactory(); + Bind().ToFactory(); Bind().ToSelf(); Bind().To().InSingletonScope(); diff --git a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeViewModel.cs b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeViewModel.cs index d2908da24..6bfd6008c 100644 --- a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeViewModel.cs +++ b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeViewModel.cs @@ -11,7 +11,7 @@ namespace Artemis.Modules.Games.CounterStrike { public sealed class CounterStrikeViewModel : GameViewModel { - public CounterStrikeViewModel(MainManager main, IEventAggregator events, IProfileEditorViewModelFactory pFactory) + public CounterStrikeViewModel(MainManager main, IEventAggregator events, IProfileEditorVmFactory pFactory) : base(main, new CounterStrikeModel(main, new CounterStrikeSettings()), events, pFactory) { DisplayName = "CS:GO"; diff --git a/Artemis/Artemis/Modules/Games/Dota2/Dota2ViewModel.cs b/Artemis/Artemis/Modules/Games/Dota2/Dota2ViewModel.cs index 2334c907a..2fff1cc90 100644 --- a/Artemis/Artemis/Modules/Games/Dota2/Dota2ViewModel.cs +++ b/Artemis/Artemis/Modules/Games/Dota2/Dota2ViewModel.cs @@ -11,7 +11,7 @@ namespace Artemis.Modules.Games.Dota2 { public sealed class Dota2ViewModel : GameViewModel { - public Dota2ViewModel(MainManager main, IEventAggregator events, IProfileEditorViewModelFactory pFactory) + public Dota2ViewModel(MainManager main, IEventAggregator events, IProfileEditorVmFactory pFactory) : base(main, new Dota2Model(main, new Dota2Settings()), events, pFactory) { DisplayName = "Dota 2"; diff --git a/Artemis/Artemis/Modules/Games/Overwatch/OverwatchViewModel.cs b/Artemis/Artemis/Modules/Games/Overwatch/OverwatchViewModel.cs index 10953e5a0..c1765707e 100644 --- a/Artemis/Artemis/Modules/Games/Overwatch/OverwatchViewModel.cs +++ b/Artemis/Artemis/Modules/Games/Overwatch/OverwatchViewModel.cs @@ -12,7 +12,7 @@ namespace Artemis.Modules.Games.Overwatch { public sealed class OverwatchViewModel : GameViewModel { - public OverwatchViewModel(MainManager main, IEventAggregator events, IProfileEditorViewModelFactory pFactory) + public OverwatchViewModel(MainManager main, IEventAggregator events, IProfileEditorVmFactory pFactory) : base(main, new OverwatchModel(events, main, new OverwatchSettings()), events, pFactory) { DisplayName = "Overwatch"; diff --git a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueViewModel.cs b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueViewModel.cs index 2cd6d9111..b71d5d4a1 100644 --- a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueViewModel.cs +++ b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueViewModel.cs @@ -13,7 +13,7 @@ namespace Artemis.Modules.Games.RocketLeague { private string _versionText; - public RocketLeagueViewModel(MainManager main, IEventAggregator events, IProfileEditorViewModelFactory pFactory) + public RocketLeagueViewModel(MainManager main, IEventAggregator events, IProfileEditorVmFactory pFactory) : base(main, new RocketLeagueModel(main, new RocketLeagueSettings()), events, pFactory) { DisplayName = "Rocket League"; diff --git a/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionViewModel.cs b/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionViewModel.cs index 4d33f68c2..b30a07c1c 100644 --- a/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionViewModel.cs +++ b/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionViewModel.cs @@ -7,7 +7,7 @@ namespace Artemis.Modules.Games.TheDivision { public sealed class TheDivisionViewModel : GameViewModel { - public TheDivisionViewModel(MainManager main, IEventAggregator events, IProfileEditorViewModelFactory pFactory) + public TheDivisionViewModel(MainManager main, IEventAggregator events, IProfileEditorVmFactory pFactory) : base(main, new TheDivisionModel(main, new TheDivisionSettings()), events, pFactory) { DisplayName = "The Division"; diff --git a/Artemis/Artemis/Modules/Games/Witcher3/Witcher3ViewModel.cs b/Artemis/Artemis/Modules/Games/Witcher3/Witcher3ViewModel.cs index d03d3ffa5..559e7c8df 100644 --- a/Artemis/Artemis/Modules/Games/Witcher3/Witcher3ViewModel.cs +++ b/Artemis/Artemis/Modules/Games/Witcher3/Witcher3ViewModel.cs @@ -13,7 +13,7 @@ namespace Artemis.Modules.Games.Witcher3 { public sealed class Witcher3ViewModel : GameViewModel { - public Witcher3ViewModel(MainManager main, IEventAggregator events, IProfileEditorViewModelFactory pFactory) + public Witcher3ViewModel(MainManager main, IEventAggregator events, IProfileEditorVmFactory pFactory) : base(main, new Witcher3Model(main, new Witcher3Settings()), events, pFactory) { DisplayName = "The Witcher 3"; diff --git a/Artemis/Artemis/Utilities/GeneralHelpers.cs b/Artemis/Artemis/Utilities/GeneralHelpers.cs index fa72c5e75..627a0bb00 100644 --- a/Artemis/Artemis/Utilities/GeneralHelpers.cs +++ b/Artemis/Artemis/Utilities/GeneralHelpers.cs @@ -60,6 +60,21 @@ namespace Artemis.Utilities } } + public static string Serialize(T source) + { + // Don't serialize a null object, simply return the default for that object + if (ReferenceEquals(source, null)) + return null; + + var serializer = new XmlSerializer(typeof(T)); + var stream = new StringWriter(); + using (stream) + { + serializer.Serialize(stream, source); + return stream.ToString(); + } + } + public static object GetPropertyValue(object o, string path) { var propertyNames = path.Split('.'); diff --git a/Artemis/Artemis/ViewModels/Abstract/GameViewModel.cs b/Artemis/Artemis/ViewModels/Abstract/GameViewModel.cs index 5974812b2..c292d9542 100644 --- a/Artemis/Artemis/ViewModels/Abstract/GameViewModel.cs +++ b/Artemis/Artemis/ViewModels/Abstract/GameViewModel.cs @@ -16,7 +16,7 @@ namespace Artemis.ViewModels.Abstract private GameSettings _gameSettings; protected GameViewModel(MainManager mainManager, GameModel gameModel, IEventAggregator events, - IProfileEditorViewModelFactory pFactory) + IProfileEditorVmFactory pFactory) { MainManager = mainManager; GameModel = gameModel; @@ -24,7 +24,7 @@ namespace Artemis.ViewModels.Abstract PFactory = pFactory; GameSettings = gameModel.Settings; - ProfileEditor = PFactory.CreateProfileEditorViewModel(Events, mainManager, gameModel, + ProfileEditor = PFactory.CreateProfileEditorVm(Events, mainManager, gameModel, GameSettings.LastProfile); GameModel.Profile = ProfileEditor.SelectedProfile; ProfileEditor.PropertyChanged += ProfileUpdater; @@ -41,7 +41,7 @@ namespace Artemis.ViewModels.Abstract public MetroDialogService DialogService { get; set; } public IEventAggregator Events { get; set; } - public IProfileEditorViewModelFactory PFactory { get; set; } + public IProfileEditorVmFactory PFactory { get; set; } public ProfileEditorViewModel ProfileEditor { get; set; } diff --git a/Artemis/Artemis/ViewModels/Profiles/LayerEditorViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/LayerEditorViewModel.cs index c15bbb9a7..6ce4208ae 100644 --- a/Artemis/Artemis/ViewModels/Profiles/LayerEditorViewModel.cs +++ b/Artemis/Artemis/ViewModels/Profiles/LayerEditorViewModel.cs @@ -1,6 +1,8 @@ -using System.ComponentModel; +using System; +using System.ComponentModel; using System.IO; using System.Linq; +using System.Xml.Serialization; using Artemis.Models.Interfaces; using Artemis.Models.Profiles; using Artemis.Models.Profiles.Properties; @@ -8,6 +10,7 @@ using Artemis.Services; using Artemis.Utilities; using Artemis.ViewModels.Profiles.Properties; using Caliburn.Micro; +using Newtonsoft.Json; using Ninject; namespace Artemis.ViewModels.Profiles @@ -26,6 +29,8 @@ namespace Artemis.ViewModels.Profiles _gameDataModel = gameDataModel; Layer = layer; + ProposedLayer = GeneralHelpers.Clone(layer); + if (Layer.Properties == null) Layer.SetupProperties(); @@ -38,6 +43,8 @@ namespace Artemis.ViewModels.Profiles PreSelect(); } + public bool ModelChanged { get; set; } + [Inject] public MetroDialogService DialogService { get; set; } @@ -69,17 +76,6 @@ namespace Artemis.ViewModels.Profiles } } - public LayerPropertiesModel ProposedProperties - { - get { return _proposedProperties; } - set - { - if (Equals(value, _proposedProperties)) return; - _proposedProperties = value; - NotifyOfPropertyChange(() => ProposedProperties); - } - } - public LayerType LayerType { get { return _layerType; } @@ -102,17 +98,15 @@ namespace Artemis.ViewModels.Profiles } } - public bool KeyboardGridIsVisible => Layer.LayerType == LayerType.Keyboard; - public bool GifGridIsVisible => Layer.LayerType == LayerType.KeyboardGif; + public bool KeyboardGridIsVisible => ProposedLayer.LayerType == LayerType.Keyboard; + public bool GifGridIsVisible => ProposedLayer.LayerType == LayerType.KeyboardGif; public void PreSelect() { - LayerType = Layer.LayerType; + LayerType = ProposedLayer.LayerType; if (LayerType == LayerType.Folder && !(LayerPropertiesViewModel is FolderPropertiesViewModel)) - LayerPropertiesViewModel = new FolderPropertiesViewModel(_gameDataModel, Layer.Properties); - - ProposedProperties = GeneralHelpers.Clone(Layer.Properties); + LayerPropertiesViewModel = new FolderPropertiesViewModel(_gameDataModel, ProposedLayer.Properties); } private void PropertiesViewModelHandler(object sender, PropertyChangedEventArgs e) @@ -124,14 +118,14 @@ namespace Artemis.ViewModels.Profiles var oldBrush = LayerPropertiesViewModel?.GetAppliedProperties().Brush; // Update the model - if (Layer.LayerType != LayerType) + if (ProposedLayer.LayerType != LayerType) { - Layer.LayerType = LayerType; - Layer.SetupProperties(); + ProposedLayer.LayerType = LayerType; + ProposedLayer.SetupProperties(); } if (oldBrush != null) - Layer.Properties.Brush = oldBrush; + ProposedLayer.Properties.Brush = oldBrush; // Update the KeyboardPropertiesViewModel if it's being used var model = LayerPropertiesViewModel as KeyboardPropertiesViewModel; @@ -142,17 +136,17 @@ namespace Artemis.ViewModels.Profiles if ((LayerType == LayerType.Keyboard || LayerType == LayerType.KeyboardGif) && !(LayerPropertiesViewModel is KeyboardPropertiesViewModel)) { - LayerPropertiesViewModel = new KeyboardPropertiesViewModel(_gameDataModel, Layer.Properties) + LayerPropertiesViewModel = new KeyboardPropertiesViewModel(_gameDataModel, ProposedLayer.Properties) { IsGif = LayerType == LayerType.KeyboardGif }; } else if (LayerType == LayerType.Mouse && !(LayerPropertiesViewModel is MousePropertiesViewModel)) - LayerPropertiesViewModel = new MousePropertiesViewModel(_gameDataModel, Layer.Properties); + LayerPropertiesViewModel = new MousePropertiesViewModel(_gameDataModel, ProposedLayer.Properties); else if (LayerType == LayerType.Headset && !(LayerPropertiesViewModel is HeadsetPropertiesViewModel)) - LayerPropertiesViewModel = new HeadsetPropertiesViewModel(_gameDataModel, Layer.Properties); + LayerPropertiesViewModel = new HeadsetPropertiesViewModel(_gameDataModel, ProposedLayer.Properties); else if (LayerType == LayerType.Folder && !(LayerPropertiesViewModel is FolderPropertiesViewModel)) - LayerPropertiesViewModel = new FolderPropertiesViewModel(_gameDataModel, Layer.Properties); + LayerPropertiesViewModel = new FolderPropertiesViewModel(_gameDataModel, ProposedLayer.Properties); NotifyOfPropertyChange(() => LayerPropertiesViewModel); } @@ -165,11 +159,17 @@ namespace Artemis.ViewModels.Profiles public void Apply() { + Layer.Name = ProposedLayer.Name; + Layer.LayerType = ProposedLayer.LayerType; + if (LayerPropertiesViewModel != null) Layer.Properties = LayerPropertiesViewModel.GetAppliedProperties(); Layer.Properties.Conditions.Clear(); foreach (var conditionViewModel in LayerConditionVms) + { + Layer.Properties.Conditions.Add(conditionViewModel.LayerConditionModel); + } if (Layer.LayerType != LayerType.KeyboardGif) return; // Don't bother checking for a GIF path unless the type is GIF @@ -183,5 +183,29 @@ namespace Artemis.ViewModels.Profiles LayerConditionVms.Remove(layerConditionViewModel); Layer.Properties.Conditions.Remove(layerConditionModel); } + + public override async void CanClose(Action callback) + { + // Create a fake layer and apply the properties to it + var fakeLayer = GeneralHelpers.Clone(ProposedLayer); + if (LayerPropertiesViewModel != null) + fakeLayer.Properties = LayerPropertiesViewModel.GetAppliedProperties(); + fakeLayer.Properties.Conditions.Clear(); + foreach (var conditionViewModel in LayerConditionVms) + fakeLayer.Properties.Conditions.Add(conditionViewModel.LayerConditionModel); + + + var fake = GeneralHelpers.Serialize(fakeLayer); + var real = GeneralHelpers.Serialize(Layer); + + if (fake.Equals(real)) + { + callback(true); + return; + } + + var close = await DialogService.ShowQuestionMessageBox("Unsaved changes", "Do you want to discard your changes?"); + callback(close.Value); + } } } \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs index 01b6381f6..b99c93683 100644 --- a/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs +++ b/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs @@ -12,6 +12,7 @@ using System.Windows.Media.Imaging; using Artemis.DAL; using Artemis.DeviceProviders; using Artemis.Events; +using Artemis.InjectionFactories; using Artemis.Managers; using Artemis.Models; using Artemis.Models.Profiles; @@ -33,18 +34,20 @@ namespace Artemis.ViewModels.Profiles public sealed class ProfileEditorViewModel : Screen, IHandle, IDropTarget { private readonly GameModel _gameModel; + private readonly ILayerEditorVmFactory _layerEditorVmFactory; private readonly MainManager _mainManager; - private LayerEditorViewModel _editorVm; private ImageSource _keyboardPreview; private BindableCollection _layers; private BindableCollection _profiles; private ProfileModel _selectedProfile; public ProfileEditorViewModel(IEventAggregator events, MainManager mainManager, GameModel gameModel, - ProfileViewModel profileViewModel, MetroDialogService dialogService, string lastProfile) + ProfileViewModel profileViewModel, MetroDialogService dialogService, string lastProfile, + ILayerEditorVmFactory layerEditorVmFactory) { _mainManager = mainManager; _gameModel = gameModel; + _layerEditorVmFactory = layerEditorVmFactory; Profiles = new BindableCollection(); Layers = new BindableCollection(); @@ -263,7 +266,7 @@ namespace Artemis.ViewModels.Profiles public void EditLayer(LayerModel layer) { IWindowManager manager = new WindowManager(); - _editorVm = new LayerEditorViewModel(_gameModel.GameDataModel, layer); + var editorVm = _layerEditorVmFactory.CreateLayerEditorVm(_gameModel.GameDataModel, layer); dynamic settings = new ExpandoObject(); var iconImage = new Image { @@ -278,7 +281,7 @@ namespace Artemis.ViewModels.Profiles settings.Title = "Artemis | Edit " + layer.Name; settings.Icon = bitmap; - manager.ShowDialog(_editorVm, null, settings); + manager.ShowDialog(editorVm, null, settings); // If the layer was a folder, but isn't anymore, assign it's children to it's parent. if (layer.LayerType != LayerType.Folder && layer.Children.Any()) diff --git a/Artemis/Artemis/Views/Profiles/LayerEditorView.xaml b/Artemis/Artemis/Views/Profiles/LayerEditorView.xaml index a695107ea..a6655937f 100644 --- a/Artemis/Artemis/Views/Profiles/LayerEditorView.xaml +++ b/Artemis/Artemis/Views/Profiles/LayerEditorView.xaml @@ -45,7 +45,7 @@ - +