Profiles - Finished dispose implementation

Profiles - Added transition between active profiles
Core - Added startup animation
This commit is contained in:
Robert committed 2020-08-10 17:25:41 +02:00
1 parent ce353fd84f
commit e09920df4f
43 files changed
+1908 -361

No files matched your search

@@ -79,7 +79,7 @@
</Grid.ColumnDefinitions>
<RadioButton Grid.Column="0"
Style="{StaticResource MaterialDesignTabRadioButton}"
IsChecked="{Binding RenderProfileElement.DisplayContinuously}"
IsChecked="{Binding DisplayContinuously}"
MinWidth="0"
Padding="5 0">
<RadioButton.ToolTip>
@@ -96,7 +96,7 @@
</RadioButton>
<RadioButton Grid.Column="1"
Style="{StaticResource MaterialDesignTabRadioButton}"
IsChecked="{Binding RenderProfileElement.DisplayContinuously, Converter={StaticResource InverseBooleanConverter}}"
IsChecked="{Binding DisplayContinuously, Converter={StaticResource InverseBooleanConverter}}"
MinWidth="0"
Padding="5 0">
<RadioButton.ToolTip>
@@ -135,7 +135,7 @@
</Grid.ColumnDefinitions>
<RadioButton Grid.Column="0"
Style="{StaticResource MaterialDesignTabRadioButton}"
IsChecked="{Binding RenderProfileElement.AlwaysFinishTimeline}"
IsChecked="{Binding AlwaysFinishTimeline}"
MinWidth="0"
Padding="5 0">
<RadioButton.ToolTip>
@@ -152,7 +152,7 @@
</RadioButton>
<RadioButton Grid.Column="1"
Style="{StaticResource MaterialDesignTabRadioButton}"
IsChecked="{Binding RenderProfileElement.AlwaysFinishTimeline, Converter={StaticResource InverseBooleanConverter}}"
IsChecked="{Binding AlwaysFinishTimeline, Converter={StaticResource InverseBooleanConverter}}"
MinWidth="0"
Padding="5 0">
<RadioButton.ToolTip>
@@ -14,6 +14,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
private RenderProfileElement _renderProfileElement;
private DisplayConditionGroupViewModel _rootGroup;
private int _transitionerIndex;
private bool _displayContinuously;
private bool _alwaysFinishTimeline;
public DisplayConditionsViewModel(IProfileEditorService profileEditorService, IDisplayConditionsVmFactory displayConditionsVmFactory)
{
@@ -39,15 +41,22 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
set => SetAndNotify(ref _renderProfileElement, value);
}
public int ConditionBehaviourIndex
public bool DisplayContinuously
{
get => RenderProfileElement != null && RenderProfileElement.AlwaysFinishTimeline ? 0 : 1;
get => _displayContinuously;
set
{
if (RenderProfileElement == null)
return;
if (!SetAndNotify(ref _displayContinuously, value)) return;
_profileEditorService.UpdateSelectedProfileElement();
}
}
RenderProfileElement.AlwaysFinishTimeline = value == 0;
public bool AlwaysFinishTimeline
{
get => _alwaysFinishTimeline;
set
{
if (!SetAndNotify(ref _alwaysFinishTimeline, value)) return;
_profileEditorService.UpdateSelectedProfileElement();
}
}
@@ -70,9 +79,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
private void ProfileEditorServiceOnProfileElementSelected(object sender, RenderProfileElementEventArgs e)
{
RenderProfileElement = e.RenderProfileElement;
NotifyOfPropertyChange(nameof(ConditionBehaviourIndex));
NotifyOfPropertyChange(nameof(ConditionBehaviourEnabled));
_displayContinuously = RenderProfileElement?.DisplayContinuously ?? false;
NotifyOfPropertyChange(nameof(DisplayContinuously));
_alwaysFinishTimeline = RenderProfileElement?.AlwaysFinishTimeline ?? false;
NotifyOfPropertyChange(nameof(AlwaysFinishTimeline));
if (e.RenderProfileElement == null)
{
RootGroup?.Dispose();
@@ -209,7 +209,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
public List<LayerPropertyGroupViewModel> GetAllLayerPropertyGroupViewModels()
{
var groups = LayerPropertyGroups.ToList();
groups.AddRange(groups.SelectMany(g => g.Children).Where(g => g is LayerPropertyGroupViewModel).Cast<LayerPropertyGroupViewModel>());
var toAdd = groups.SelectMany(g => g.Children).Where(g => g is LayerPropertyGroupViewModel).Cast<LayerPropertyGroupViewModel>().ToList();
groups.AddRange(toAdd);
return groups;
}
@@ -9,6 +9,7 @@ using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Abstract;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Tree;
using Artemis.UI.Shared.Services.Interfaces;
using Humanizer;
using Ninject;
using Ninject.Parameters;
@@ -42,6 +43,16 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
TreePropertyGroupViewModel = _layerPropertyVmFactory.TreePropertyGroupViewModel(this);
TimelinePropertyGroupViewModel = _layerPropertyVmFactory.TimelinePropertyGroupViewModel(this);
// Generate a fallback name if the description does not contain one
if (PropertyGroupDescription.Name == null)
{
var propertyInfo = LayerPropertyGroup.Parent?.GetType().GetProperties().FirstOrDefault(p => ReferenceEquals(p.GetValue(LayerPropertyGroup.Parent), LayerPropertyGroup));
if (propertyInfo != null)
PropertyGroupDescription.Name = propertyInfo.Name.Humanize();
else
PropertyGroupDescription.Name = "Unknown group";
}
LayerPropertyGroup.VisibilityChanged += LayerPropertyGroupOnVisibilityChanged;
PopulateChildren();
DetermineType();
@@ -21,7 +21,8 @@
Text="{Binding LayerPropertyGroupViewModel.PropertyGroupDescription.Name}"
ToolTip="{Binding LayerPropertyGroupViewModel.PropertyGroupDescription.Description}"
VerticalAlignment="Center"
Margin="0 5">
HorizontalAlignment="Left"
Margin="3 5 0 5">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="Collapsed" />
@@ -9,7 +9,7 @@
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance {x:Type local:TreePropertyViewModel}}">
<Grid Height="22">
<Grid Height="22" Margin="-20 0 0 0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
@@ -7,6 +7,8 @@
xmlns:s="https://github.com/canton7/Stylet"
xmlns:profileEditor="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor"
xmlns:behaviors="clr-namespace:Artemis.UI.Behaviors"
xmlns:profile="clr-namespace:Artemis.Core.Models.Profile;assembly=Artemis.Core"
xmlns:layerBrush="clr-namespace:Artemis.Core.Plugins.LayerBrush;assembly=Artemis.Core"
mc:Ignorable="d"
behaviors:InputBindingBehavior.PropagateInputBindingsToWindow="True"
d:DesignHeight="450" d:DesignWidth="800"
@@ -19,6 +21,38 @@
<ResourceDictionary
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.PopupBox.xaml" />
</ResourceDictionary.MergedDictionaries>
<ControlTemplate x:Key="SimpleTemplate">
<StackPanel d:DataContext="{d:DesignInstance {x:Type profile:ProfileDescriptor}}" Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
</StackPanel>
</ControlTemplate>
<ControlTemplate x:Key="ExtendedTemplate">
<Grid d:DataContext="{d:DesignInstance {x:Type profile:ProfileDescriptor}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" />
<Button Grid.Column="1"
Style="{StaticResource MaterialDesignFloatingActionMiniDarkButton}"
Width="26"
Height="26"
VerticalAlignment="Top"
Command="{s:Action DeleteProfile}"
CommandParameter="{Binding}">
<materialDesign:PackIcon Kind="TrashCanOutline" Height="14" Width="14" HorizontalAlignment="Right" />
</Button>
</Grid>
</ControlTemplate>
<DataTemplate x:Key="ProfileDescriptorTemplate">
<Control x:Name="TemplateControl" Focusable="False" Template="{StaticResource ExtendedTemplate}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ComboBoxItem}}, Path=IsSelected}" Value="{x:Null}">
<Setter TargetName="TemplateControl" Property="Template" Value="{StaticResource SimpleTemplate}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ResourceDictionary>
</UserControl.Resources>
@@ -98,12 +132,11 @@
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ComboBox Name="LocaleCombo"
Height="26"
<ComboBox Height="26"
VerticalAlignment="Top"
ItemsSource="{Binding Profiles}"
SelectedItem="{Binding SelectedProfile}"
DisplayMemberPath="Name">
SelectedItem="{Binding SelectedProfile}"
ItemTemplate="{StaticResource ProfileDescriptorTemplate}">
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
@@ -25,7 +25,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
private readonly IProfileService _profileService;
private readonly ISettingsService _settingsService;
private readonly ISnackbarMessageQueue _snackbarMessageQueue;
private BindableCollection<Profile> _profiles;
private BindableCollection<ProfileDescriptor> _profiles;
private PluginSetting<GridLength> _sidePanelsWidth;
private PluginSetting<GridLength> _displayConditionsHeight;
private PluginSetting<GridLength> _bottomPanelsHeight;
@@ -34,6 +34,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
private ProfileTreeViewModel _profileTreeViewModel;
private LayerPropertiesViewModel _layerPropertiesViewModel;
private DisplayConditionsViewModel _displayConditionsViewModel;
private ProfileDescriptor _selectedProfile;
public ProfileEditorViewModel(ProfileModule module,
ICollection<ProfileEditorPanelViewModel> viewModels,
@@ -52,7 +53,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
Module = module;
DialogService = dialogService;
Profiles = new BindableCollection<Profile>();
Profiles = new BindableCollection<ProfileDescriptor>();
// Run this first to let VMs activate without causing constant UI updates
Items.AddRange(viewModels);
@@ -91,7 +92,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
set => SetAndNotify(ref _profileViewModel, value);
}
public BindableCollection<Profile> Profiles
public BindableCollection<ProfileDescriptor> Profiles
{
get => _profiles;
set => SetAndNotify(ref _profiles, value);
@@ -121,17 +122,22 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
set => SetAndNotify(ref _elementPropertiesWidth, value);
}
public Profile SelectedProfile
public ProfileDescriptor SelectedProfile
{
get => Module.ActiveProfile;
set => ChangeSelectedProfile(value);
get => _selectedProfile;
set
{
if (!SetAndNotify(ref _selectedProfile, value)) return;
NotifyOfPropertyChange(nameof(CanDeleteActiveProfile));
ActivateSelectedProfile();
}
}
public bool CanDeleteActiveProfile => SelectedProfile != null && Profiles.Count > 1;
public Profile CreateProfile(string name)
public ProfileDescriptor CreateProfile(string name)
{
var profile = _profileService.CreateProfile(Module, name);
var profile = _profileService.CreateProfileDescriptor(Module, name);
Profiles.Add(profile);
return profile;
}
@@ -146,6 +152,17 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
}
}
public async Task DeleteProfile(ProfileDescriptor profileDescriptor)
{
var result = await DialogService.ShowConfirmDialog(
"Delete profile",
$"Are you sure you want to delete '{profileDescriptor.Name}'? This cannot be undone."
);
if (result)
RemoveProfile(profileDescriptor);
}
public async Task DeleteActiveProfile()
{
var result = await DialogService.ShowConfirmDialog(
@@ -153,21 +170,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
"Are you sure you want to delete your currently active profile? This cannot be undone."
);
if (!result || !CanDeleteActiveProfile)
return;
var profile = SelectedProfile;
var index = Profiles.IndexOf(profile);
// Get a new active profile
var newActiveProfile = index - 1 > -1 ? Profiles[index - 1] : Profiles[index + 1];
// Activate the new active profile
SelectedProfile = newActiveProfile;
// Remove the old one
Profiles.Remove(profile);
_profileService.DeleteProfile(profile);
if (result)
RemoveProfile(SelectedProfile);
}
public void Undo()
@@ -176,7 +180,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
var beforeGroups = LayerPropertiesViewModel.GetAllLayerPropertyGroupViewModels();
var expandedPaths = beforeGroups.Where(g => g.IsExpanded).Select(g => g.LayerPropertyGroup.Path).ToList();
if (!_profileEditorService.UndoUpdateProfile(Module))
if (!_profileEditorService.UndoUpdateProfile())
{
_snackbarMessageQueue.Enqueue("Nothing to undo");
return;
@@ -195,7 +199,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
var beforeGroups = LayerPropertiesViewModel.GetAllLayerPropertyGroupViewModels();
var expandedPaths = beforeGroups.Where(g => g.IsExpanded).Select(g => g.LayerPropertyGroup.Path).ToList();
if (!_profileEditorService.RedoUpdateProfile(Module))
if (!_profileEditorService.RedoUpdateProfile())
{
_snackbarMessageQueue.Enqueue("Nothing to redo");
return;
@@ -225,29 +229,38 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
base.OnClose();
}
private void ChangeSelectedProfile(Profile profile)
private void RemoveProfile(ProfileDescriptor profileDescriptor)
{
var oldProfile = Module.ActiveProfile;
_profileService.ActivateProfile(Module, profile);
if (SelectedProfile == profileDescriptor && !CanDeleteActiveProfile)
return;
if (oldProfile != null)
_profileService.UpdateProfile(oldProfile, false);
if (profile != null)
_profileService.UpdateProfile(profile, false);
var index = Profiles.IndexOf(profileDescriptor);
if (_profileEditorService.SelectedProfile != profile)
// Get a new active profile
var newActiveProfile = index - 1 > -1 ? Profiles[index - 1] : Profiles[index + 1];
// Activate the new active profile
SelectedProfile = newActiveProfile;
// Remove the old one
Profiles.Remove(profileDescriptor);
_profileService.DeleteProfile(profileDescriptor);
}
private void ActivateSelectedProfile()
{
Execute.PostToUIThread(async () =>
{
var changeTask = _profileService.ActivateProfileAnimated(SelectedProfile);
_profileEditorService.ChangeSelectedProfile(null);
var profile = await changeTask;
_profileEditorService.ChangeSelectedProfile(profile);
NotifyOfPropertyChange(nameof(SelectedProfile));
NotifyOfPropertyChange(nameof(CanDeleteActiveProfile));
});
}
private void ModuleOnActiveProfileChanged(object sender, EventArgs e)
{
if (SelectedProfile == Module.ActiveProfile)
return;
SelectedProfile = Profiles.FirstOrDefault(p => p == Module.ActiveProfile);
SelectedProfile = Profiles.FirstOrDefault(d => d.Id == Module.ActiveProfile.EntityId);
}
private void LoadWorkspaceSettings()
@@ -269,29 +282,19 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
private void LoadProfiles()
{
// Get all profiles from the database
var profiles = _profileService.GetProfiles(Module);
// Get the latest active profile, this falls back to just any profile so if null, create a default profile
var activeProfile = _profileService.GetActiveProfile(Module) ?? _profileService.CreateProfile(Module, "Default");
Profiles.Clear();
Profiles.AddRange(_profileService.GetProfileDescriptors(Module).OrderBy(d => d.Name));
// GetActiveProfile can return a duplicate because inactive profiles aren't kept in memory, make sure it's unique in the profiles list
profiles = profiles.Where(p => p.EntityId != activeProfile.EntityId).ToList();
profiles.Add(activeProfile);
// Populate the selected profile
SelectedProfile = Profiles.FirstOrDefault(p => p.IsLastActiveProfile);
// Populate the UI collection
Profiles.AddRange(profiles.Except(Profiles).ToList());
Profiles.RemoveRange(Profiles.Except(profiles).ToList());
var index = 0;
foreach (var profile in Profiles.OrderBy(p => p.Name).ToList())
{
Profiles.Move(Profiles.IndexOf(profile), index);
index++;
}
if (SelectedProfile != null)
return;
SelectedProfile = activeProfile;
if (_profileEditorService.SelectedProfile != activeProfile)
_profileEditorService.ChangeSelectedProfile(activeProfile);
if (!activeProfile.IsActivated)
_profileService.ActivateProfile(Module, activeProfile);
// Create a default profile if there is none
var defaultProfile = _profileService.CreateProfileDescriptor(Module, "Default");
Profiles.Add(defaultProfile);
SelectedProfile = defaultProfile;
}
}
}
@@ -2,9 +2,7 @@
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Artemis.Core.Models.Profile;
using Artemis.Core.Models.Profile.LayerShapes;
using Artemis.Core.Models.Surface;
@@ -12,7 +10,6 @@ using Artemis.UI.Extensions;
using Artemis.UI.Services.Interfaces;
using Artemis.UI.Shared.Services.Interfaces;
using Stylet;
using Rectangle = Artemis.Core.Models.Profile.LayerShapes.Rectangle;
namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
{
@@ -48,7 +45,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
get => _shapeGeometry;
set => SetAndNotify(ref _shapeGeometry, value);
}
public Rect ViewportRectangle
{
get => _viewportRectangle;
@@ -117,7 +114,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
private void Update()
{
IsSelected = _profileEditorService.SelectedProfileElement == Layer;
CreateShapeGeometry();
CreateViewportRectangle();
}