1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

UI - Moved exception viewer to its own seperate window

Conditions - Started adding list conditions
This commit is contained in:
Robert 2020-08-11 22:47:41 +02:00
parent f21ade955d
commit cb69760971
36 changed files with 930 additions and 471 deletions

View File

@ -25,8 +25,10 @@ namespace Artemis.Core.Models.Profile.Conditions
{
if (childEntity is DisplayConditionGroupEntity groupEntity)
AddChild(new DisplayConditionGroup(this, groupEntity));
if (childEntity is DisplayConditionPredicateEntity predicateEntity)
else if (childEntity is DisplayConditionPredicateEntity predicateEntity)
AddChild(new DisplayConditionPredicate(this, predicateEntity));
else if (childEntity is DisplayConditionListPredicateEntity listPredicateEntity)
AddChild(new DisplayConditionListPredicate(this, listPredicateEntity));
}
}

View File

@ -1,30 +1,100 @@
using Artemis.Core.Models.Profile.Conditions.Abstract;
using System.Linq;
using Artemis.Core.Exceptions;
using Artemis.Core.Models.Profile.Conditions.Abstract;
using Artemis.Core.Plugins.Abstract.DataModels;
using Artemis.Core.Services.Interfaces;
using Artemis.Storage.Entities.Profile;
using Artemis.Storage.Entities.Profile.Abstract;
namespace Artemis.Core.Models.Profile.Conditions
{
public class DisplayConditionListPredicate : DisplayConditionPart
{
public DisplayConditionListPredicate(DisplayConditionPart parent)
{
Parent = parent;
DisplayConditionListPredicateEntity = new DisplayConditionListPredicateEntity();
}
public DisplayConditionListPredicate(DisplayConditionPart parent, DisplayConditionListPredicateEntity entity)
{
Parent = parent;
DisplayConditionListPredicateEntity = entity;
ListOperator = (ListOperator) entity.ListOperator;
foreach (var childEntity in DisplayConditionListPredicateEntity.Children)
{
if (childEntity is DisplayConditionGroupEntity groupEntity)
AddChild(new DisplayConditionGroup(this, groupEntity));
else if (childEntity is DisplayConditionPredicateEntity predicateEntity)
AddChild(new DisplayConditionPredicate(this, predicateEntity));
else if (childEntity is DisplayConditionListPredicateEntity listPredicateEntity)
AddChild(new DisplayConditionListPredicate(this, listPredicateEntity));
}
}
public DisplayConditionListPredicateEntity DisplayConditionListPredicateEntity { get; set; }
public ListOperator ListOperator { get; set; }
public DataModel ListDataModel { get; private set; }
public string ListPropertyPath { get; private set; }
public override bool Evaluate()
{
return true;
}
internal override void ApplyToEntity()
{
// Target list
DisplayConditionListPredicateEntity.ListDataModelGuid = ListDataModel?.PluginInfo?.Guid;
DisplayConditionListPredicateEntity.ListPropertyPath = ListPropertyPath;
// Operator
DisplayConditionListPredicateEntity.ListOperator = (int) ListOperator;
// Children
DisplayConditionListPredicateEntity.Children.Clear();
DisplayConditionListPredicateEntity.Children.AddRange(Children.Select(c => c.GetEntity()));
foreach (var child in Children)
child.ApplyToEntity();
}
internal override DisplayConditionPartEntity GetEntity()
{
return null;
return DisplayConditionListPredicateEntity;
}
internal override void Initialize(IDataModelService dataModelService)
{
// Target list
if (DisplayConditionListPredicateEntity.ListDataModelGuid != null)
{
var dataModel = dataModelService.GetPluginDataModelByGuid(DisplayConditionListPredicateEntity.ListDataModelGuid.Value);
if (dataModel != null && dataModel.ContainsPath(DisplayConditionListPredicateEntity.ListPropertyPath))
UpdateList(dataModel, DisplayConditionListPredicateEntity.ListPropertyPath);
}
// Children
foreach (var child in Children)
child.Initialize(dataModelService);
}
public void UpdateList(DataModel dataModel, string path)
{
if (dataModel != null && path == null)
throw new ArtemisCoreException("If a data model is provided, a path is also required");
if (dataModel == null && path != null)
throw new ArtemisCoreException("If path is provided, a data model is also required");
if (dataModel != null)
{
if (!dataModel.ContainsPath(path))
throw new ArtemisCoreException($"Data model of type {dataModel.GetType().Name} does not contain a property at path '{path}'");
}
ListDataModel = dataModel;
ListPropertyPath = path;
}
}

View File

@ -52,7 +52,7 @@
"Id": "2464a52c-4cec-4f17-87ed-edfe4bfed6f6",
"ParentId": "cc21b67c-3485-4dc6-b2af-105fda42a915",
"Order": 1,
"Name": "Teal layer",
"Name": "Noise",
"Enabled": true,
"Leds": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.LedEntity, Artemis.Storage]], System.Private.CoreLib",
@ -149,14 +149,14 @@
"$values": [
{
"$type": "Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage",
"Position": "00:00:02.5000000",
"Position": "00:00:01.3200000",
"Timeline": 0,
"Value": "{\"IsEmpty\":false,\"Width\":300.0,\"Height\":0.0}",
"EasingFunction": 3
},
{
"$type": "Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage",
"Position": "00:00:03.7500000",
"Position": "00:00:03",
"Timeline": 0,
"Value": "{\"IsEmpty\":false,\"Width\":300.0,\"Height\":400.0}",
"EasingFunction": 0
@ -193,7 +193,7 @@
},
{
"$type": "Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage",
"Position": "00:00:04.4000000",
"Position": "00:00:04.9100000",
"Timeline": 0,
"Value": "0.0",
"EasingFunction": 0
@ -205,7 +205,7 @@
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "61cbbf01-8d69-4ede-a972-f3f269da66d9",
"Path": "LayerBrush.ColorType",
"Value": "0",
"Value": "1",
"KeyframesEnabled": false,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
@ -238,7 +238,7 @@
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "61cbbf01-8d69-4ede-a972-f3f269da66d9",
"Path": "LayerBrush.GradientColor",
"Value": "{\"Stops\":[{\"Color\":\"#ffff0000\",\"Position\":0.0},{\"Color\":\"#ffff8800\",\"Position\":0.125},{\"Color\":\"#ffedff00\",\"Position\":0.25},{\"Color\":\"#ff65ff00\",\"Position\":0.375},{\"Color\":\"#ff00ff22\",\"Position\":0.5},{\"Color\":\"#ff00ffaa\",\"Position\":0.625},{\"Color\":\"#ff00cbff\",\"Position\":0.75},{\"Color\":\"#ff0043ff\",\"Position\":0.875},{\"Color\":\"#ffff0000\",\"Position\":1.0}],\"Rotation\":0.0}",
"Value": "{\"Stops\":[{\"Color\":\"#ff0b4a40\",\"Position\":0.0},{\"Color\":\"#ff00897c\",\"Position\":0.242},{\"Color\":\"#ffffffff\",\"Position\":1.0},{\"Color\":\"#ff00ffe6\",\"Position\":0.67391306}],\"Rotation\":0.0}",
"KeyframesEnabled": false,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
@ -249,7 +249,7 @@
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "61cbbf01-8d69-4ede-a972-f3f269da66d9",
"Path": "LayerBrush.Scale",
"Value": "{\"IsEmpty\":false,\"Width\":100.0,\"Height\":100.0}",
"Value": "{\"IsEmpty\":false,\"Width\":44.9,\"Height\":31.0}",
"KeyframesEnabled": false,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
@ -260,7 +260,7 @@
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "61cbbf01-8d69-4ede-a972-f3f269da66d9",
"Path": "LayerBrush.Hardness",
"Value": "300.0",
"Value": "228.5",
"KeyframesEnabled": false,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
@ -294,267 +294,6 @@
"ExpandedPropertyGroups": {
"$type": "System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib",
"$values": [
"Transform",
"General"
]
},
"RootDisplayCondition": {
"$type": "Artemis.Storage.Entities.Profile.DisplayConditionGroupEntity, Artemis.Storage",
"BooleanOperator": 0,
"Children": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.Abstract.DisplayConditionPartEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": []
}
}
},
{
"$type": "Artemis.Storage.Entities.Profile.LayerEntity, Artemis.Storage",
"Id": "8d5fa358-88ed-4501-8cb2-fd9c31a34274",
"ParentId": "cc21b67c-3485-4dc6-b2af-105fda42a915",
"Order": 2,
"Name": "RGB layer",
"Enabled": true,
"Leds": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.LedEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": []
},
"Profile": null,
"ProfileId": "eb4f487b-475b-408f-a84f-733412d41b44",
"StartSegmentLength": "00:00:00",
"MainSegmentLength": "00:00:03.7500000",
"EndSegmentLength": "00:00:00",
"DisplayContinuously": false,
"AlwaysFinishTimeline": false,
"LayerEffects": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.LayerEffectEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": []
},
"PropertyEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": [
{
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "ffffffff-ffff-ffff-ffff-ffffffffffff",
"Path": "General.ShapeType",
"Value": "1",
"KeyframesEnabled": false,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": []
}
},
{
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "ffffffff-ffff-ffff-ffff-ffffffffffff",
"Path": "General.ResizeMode",
"Value": "0",
"KeyframesEnabled": false,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": []
}
},
{
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "ffffffff-ffff-ffff-ffff-ffffffffffff",
"Path": "General.BlendMode",
"Value": "3",
"KeyframesEnabled": false,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": []
}
},
{
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "ffffffff-ffff-ffff-ffff-ffffffffffff",
"Path": "General.BrushReference",
"Value": "{\"BrushPluginGuid\":\"92a9d6ba-6f7a-4937-94d5-c1d715b4141a\",\"BrushType\":\"ColorBrush\"}",
"KeyframesEnabled": false,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": []
}
},
{
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "ffffffff-ffff-ffff-ffff-ffffffffffff",
"Path": "Transform.AnchorPoint",
"Value": "{\"IsEmpty\":true,\"Length\":0.0,\"LengthSquared\":0.0,\"X\":0.0,\"Y\":0.0}",
"KeyframesEnabled": false,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": []
}
},
{
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "ffffffff-ffff-ffff-ffff-ffffffffffff",
"Path": "Transform.Position",
"Value": "{\"IsEmpty\":false,\"Length\":0.5,\"LengthSquared\":0.25,\"X\":-0.5,\"Y\":-0.0}",
"KeyframesEnabled": true,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": [
{
"$type": "Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage",
"Position": "00:00:01.2500000",
"Timeline": 0,
"Value": "{\"IsEmpty\":false,\"Length\":0.25,\"LengthSquared\":0.0625,\"X\":-0.25,\"Y\":0.0}",
"EasingFunction": 0
},
{
"$type": "Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage",
"Position": "00:00:03.7500000",
"Timeline": 0,
"Value": "{\"IsEmpty\":false,\"Length\":0.25,\"LengthSquared\":0.0625,\"X\":0.25,\"Y\":0.0}",
"EasingFunction": 0
}
]
}
},
{
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "ffffffff-ffff-ffff-ffff-ffffffffffff",
"Path": "Transform.Scale",
"Value": "{\"IsEmpty\":false,\"Width\":200.0,\"Height\":0.0}",
"KeyframesEnabled": true,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": [
{
"$type": "Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage",
"Position": "00:00:01.2500000",
"Timeline": 0,
"Value": "{\"IsEmpty\":false,\"Width\":150.0,\"Height\":0.0}",
"EasingFunction": 5
},
{
"$type": "Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage",
"Position": "00:00:02.2700000",
"Timeline": 0,
"Value": "{\"IsEmpty\":false,\"Width\":150.0,\"Height\":100.0}",
"EasingFunction": 0
}
]
}
},
{
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "ffffffff-ffff-ffff-ffff-ffffffffffff",
"Path": "Transform.Rotation",
"Value": "0.0",
"KeyframesEnabled": false,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": []
}
},
{
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "ffffffff-ffff-ffff-ffff-ffffffffffff",
"Path": "Transform.Opacity",
"Value": "100.0",
"KeyframesEnabled": false,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": []
}
},
{
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "92a9d6ba-6f7a-4937-94d5-c1d715b4141a",
"Path": "LayerBrush.GradientType",
"Value": "1",
"KeyframesEnabled": false,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": []
}
},
{
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "92a9d6ba-6f7a-4937-94d5-c1d715b4141a",
"Path": "LayerBrush.TileMode",
"Value": "0",
"KeyframesEnabled": false,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": []
}
},
{
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "92a9d6ba-6f7a-4937-94d5-c1d715b4141a",
"Path": "LayerBrush.Color",
"Value": "\"#ffff0000\"",
"KeyframesEnabled": false,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": []
}
},
{
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "92a9d6ba-6f7a-4937-94d5-c1d715b4141a",
"Path": "LayerBrush.Colors",
"Value": "{\"Stops\":[{\"Color\":\"#ffff0000\",\"Position\":0.0},{\"Color\":\"#ffff8800\",\"Position\":0.125},{\"Color\":\"#ffedff00\",\"Position\":0.25},{\"Color\":\"#ff65ff00\",\"Position\":0.375},{\"Color\":\"#ff00ff22\",\"Position\":0.5},{\"Color\":\"#ff00ffaa\",\"Position\":0.625},{\"Color\":\"#ff00cbff\",\"Position\":0.75},{\"Color\":\"#ff0043ff\",\"Position\":0.875},{\"Color\":\"#ffff0000\",\"Position\":1.0}],\"Rotation\":0.0}",
"KeyframesEnabled": false,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": []
}
},
{
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "92a9d6ba-6f7a-4937-94d5-c1d715b4141a",
"Path": "LayerBrush.ColorsMultiplier",
"Value": "2",
"KeyframesEnabled": false,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": []
}
},
{
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "92a9d6ba-6f7a-4937-94d5-c1d715b4141a",
"Path": "LayerBrush.LinearGradientRotation",
"Value": "0.0",
"KeyframesEnabled": false,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": []
}
},
{
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "92a9d6ba-6f7a-4937-94d5-c1d715b4141a",
"Path": "LayerBrush.RadialGradient.CenterOffset",
"Value": "{\"IsEmpty\":true,\"Length\":0.0,\"LengthSquared\":0.0,\"X\":0.0,\"Y\":0.0}",
"KeyframesEnabled": false,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": []
}
},
{
"$type": "Artemis.Storage.Entities.Profile.PropertyEntity, Artemis.Storage",
"PluginGuid": "92a9d6ba-6f7a-4937-94d5-c1d715b4141a",
"Path": "LayerBrush.RadialGradient.ResizeMode",
"Value": "0",
"KeyframesEnabled": false,
"KeyframeEntities": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage]], System.Private.CoreLib",
"$values": []
}
}
]
},
"ExpandedPropertyGroups": {
"$type": "System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib",
"$values": [
"Transform",
"LayerBrush"
]
},
@ -571,8 +310,8 @@
"$type": "Artemis.Storage.Entities.Profile.LayerEntity, Artemis.Storage",
"Id": "72a7e56c-0649-4449-8dca-eb937161f228",
"ParentId": "cc21b67c-3485-4dc6-b2af-105fda42a915",
"Order": 3,
"Name": "Exploison layer",
"Order": 2,
"Name": "Exploison",
"Enabled": true,
"Leds": {
"$type": "System.Collections.Generic.List`1[[Artemis.Storage.Entities.Profile.LedEntity, Artemis.Storage]], System.Private.CoreLib",
@ -581,7 +320,7 @@
"Profile": null,
"ProfileId": "eb4f487b-475b-408f-a84f-733412d41b44",
"StartSegmentLength": "00:00:00",
"MainSegmentLength": "00:00:02.2500000",
"MainSegmentLength": "00:00:03",
"EndSegmentLength": "00:00:00",
"DisplayContinuously": false,
"AlwaysFinishTimeline": false,
@ -676,9 +415,9 @@
},
{
"$type": "Artemis.Storage.Entities.Profile.KeyframeEntity, Artemis.Storage",
"Position": "00:00:02",
"Position": "00:00:01.5000000",
"Timeline": 0,
"Value": "{\"IsEmpty\":false,\"Width\":200.0,\"Height\":200.0}",
"Value": "{\"IsEmpty\":false,\"Width\":300.0,\"Height\":300.0}",
"EasingFunction": 0
}
]
@ -798,9 +537,7 @@
},
"ExpandedPropertyGroups": {
"$type": "System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib",
"$values": [
"LayerBrush"
]
"$values": []
},
"RootDisplayCondition": {
"$type": "Artemis.Storage.Entities.Profile.DisplayConditionGroupEntity, Artemis.Storage",
@ -815,7 +552,7 @@
"$type": "Artemis.Storage.Entities.Profile.LayerEntity, Artemis.Storage",
"Id": "f046f56f-a236-4ed6-bbd9-b5a4731878cf",
"ParentId": "cc21b67c-3485-4dc6-b2af-105fda42a915",
"Order": 4,
"Order": 2,
"Name": "Background",
"Enabled": true,
"Leds": {
@ -825,7 +562,7 @@
"Profile": null,
"ProfileId": "eb4f487b-475b-408f-a84f-733412d41b44",
"StartSegmentLength": "00:00:00",
"MainSegmentLength": "00:00:03.7500000",
"MainSegmentLength": "00:00:03",
"EndSegmentLength": "00:00:00",
"DisplayContinuously": false,
"AlwaysFinishTimeline": false,

View File

@ -88,9 +88,26 @@ namespace Artemis.Core.Services.Storage.Interfaces
bool RedoUpdateProfile(Profile profile);
/// <summary>
/// Prepares the profile for rendering. You should not need to call this, it is exposed for some niche usage in the core
/// Prepares the profile for rendering. You should not need to call this, it is exposed for some niche usage in the
/// core
/// </summary>
/// <param name="profile"></param>
void InstantiateProfile(Profile profile);
/// <summary>
/// [Placeholder] Exports the profile described in the given <see cref="ProfileDescriptor" /> in a JSON format
/// </summary>
/// <param name="profileDescriptor">The descriptor of the profile to export</param>
/// <returns>The resulting JSON</returns>
string ExportProfile(ProfileDescriptor profileDescriptor);
/// <summary>
/// [Placeholder] Imports the provided base64 encoded GZIPed JSON as a profile for the given
/// <see cref="ProfileModule" />
/// </summary>
/// <param name="json">The content of the profile as JSON</param>
/// <param name="profileModule">The module to import the profile in to</param>
/// <returns></returns>
ProfileDescriptor ImportProfile(string json, ProfileModule profileModule);
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO.Compression;
using System.Linq;
using System.Threading.Tasks;
using Artemis.Core.Events;
@ -10,6 +11,7 @@ using Artemis.Core.Plugins.Abstract;
using Artemis.Core.Plugins.LayerEffect.Abstract;
using Artemis.Core.Services.Interfaces;
using Artemis.Core.Services.Storage.Interfaces;
using Artemis.Core.Utilities;
using Artemis.Storage.Entities.Profile;
using Artemis.Storage.Repositories.Interfaces;
using Newtonsoft.Json;
@ -40,6 +42,7 @@ namespace Artemis.Core.Services.Storage
}
public JsonSerializerSettings MementoSettings { get; set; } = new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.All};
public JsonSerializerSettings ExportSettings { get; set; } = new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.All, Formatting = Formatting.Indented};
public void ActivateLastActiveProfiles()
{
@ -222,6 +225,26 @@ namespace Artemis.Core.Services.Storage
InstantiateFolders(profile);
}
public string ExportProfile(ProfileDescriptor profileDescriptor)
{
var profileEntity = _profileRepository.Get(profileDescriptor.Id);
if (profileEntity == null)
throw new ArtemisCoreException($"Cannot find profile named: {profileDescriptor.Name} ID: {profileDescriptor.Id}");
return JsonConvert.SerializeObject(profileEntity, ExportSettings);
}
public ProfileDescriptor ImportProfile(string json, ProfileModule profileModule)
{
var profileEntity = JsonConvert.DeserializeObject<ProfileEntity>(json, ExportSettings);
// Assign a new GUID to make sure it is unique in case of a previous import of the same content
profileEntity.Id = Guid.NewGuid();
_profileRepository.Add(profileEntity);
return new ProfileDescriptor(profileModule, profileEntity);
}
/// <summary>
/// Initializes the properties on the layers of the given profile
/// </summary>

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using Artemis.Storage.Entities.Profile.Abstract;
namespace Artemis.Storage.Entities.Profile
{
public class DisplayConditionListPredicateEntity : DisplayConditionPartEntity
{
public DisplayConditionListPredicateEntity()
{
Children = new List<DisplayConditionPartEntity>();
}
public Guid? ListDataModelGuid { get; set; }
public string ListPropertyPath { get; set; }
public int ListOperator { get; set; }
}
}

View File

@ -40,7 +40,7 @@
</Border>
<!-- Input -->
<TextBox x:Name="Input"
<TextBox x:Name="DraggableFloatInputTextBox"
Width="60"
Height="21"
Padding="0 0 -2 0"

View File

@ -140,7 +140,7 @@ namespace Artemis.UI.Shared.Controls
DisplayDragHandle();
else if (e.Key == Key.Escape)
{
Input.Text = _startValue.ToString();
DraggableFloatInputTextBox.Text = _startValue.ToString();
DisplayDragHandle();
}
}
@ -148,14 +148,14 @@ namespace Artemis.UI.Shared.Controls
private void DisplayInput()
{
DragHandle.Visibility = Visibility.Collapsed;
Input.Visibility = Visibility.Visible;
Input.Focus();
Input.SelectAll();
DraggableFloatInputTextBox.Visibility = Visibility.Visible;
DraggableFloatInputTextBox.Focus();
DraggableFloatInputTextBox.SelectAll();
}
private void DisplayDragHandle()
{
Input.Visibility = Visibility.Collapsed;
DraggableFloatInputTextBox.Visibility = Visibility.Collapsed;
DragHandle.Visibility = Visibility.Visible;
}

View File

@ -1,50 +0,0 @@
<UserControl x:Class="Artemis.UI.Shared.Screens.Dialogs.ExceptionDialogView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:s="https://github.com/canton7/Stylet"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:dialogs="clr-namespace:Artemis.UI.Shared.Screens.Dialogs"
xmlns:avalonedit="http://icsharpcode.net/sharpdevelop/avalonedit"
mc:Ignorable="d"
d:DesignHeight="163.274" d:DesignWidth="254.425"
d:DataContext="{d:DesignInstance dialogs:ExceptionDialogViewModel}">
<StackPanel Orientation="Vertical" HorizontalAlignment="Right" Margin="16">
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" Text="{Binding Header}"
TextWrapping="Wrap" />
<Separator Margin="0 15" />
<ScrollViewer MaxHeight="500" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<StackPanel>
<ItemsControl ItemsSource="{Binding Exceptions}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}"
Text="Stack trace"
TextWrapping="Wrap"
FontWeight="Bold"
MaxWidth="1000"/>
<avalonedit:TextEditor SyntaxHighlighting="C#"
FontFamily="pack://application:,,,/Resources/Fonts/#Roboto Mono"
FontSize="10pt"
IsReadOnly="True"
Document="{Binding Document}"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
MaxWidth="1000"
Margin="0 10 10 0"
Padding="10" />
<Separator Margin="0 15" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
<Button Style="{StaticResource MaterialDesignFlatButton}" IsDefault="True" Margin="0 8 0 0"
Command="{s:Action Close}" Content="Close" HorizontalAlignment="Right" />
</StackPanel>
</UserControl>

View File

@ -0,0 +1,59 @@
<controls:MaterialWindow x:Class="Artemis.UI.Shared.Screens.Exceptions.ExceptionView"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:exceptions="clr-namespace:Artemis.UI.Shared.Screens.Exceptions"
xmlns:avalonedit="http://icsharpcode.net/sharpdevelop/avalonedit"
mc:Ignorable="d"
Title="Unhandled exception"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="pack://application:,,,/MaterialDesignThemes.Wpf;component/Resources/Roboto/#Roboto"
UseLayoutRounding="True"
Width="800"
Height="800"
d:DesignHeight="800"
d:DesignWidth="800"
d:DataContext="{d:DesignInstance exceptions:ExceptionViewModel}">
<DockPanel>
<controls:AppBar Type="Dense" Title="{Binding Header}" DockPanel.Dock="Top" Margin="-18 0 0 0" ShowShadow="False">
<controls:AppBar.AppIcon>
<materialDesign:PackIcon Kind="ErrorOutline" Width="20" Height="28" />
</controls:AppBar.AppIcon>
</controls:AppBar>
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" Margin="16">
<StackPanel>
<ItemsControl ItemsSource="{Binding Exceptions}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}"
Text="Stack trace"
TextWrapping="Wrap"
FontWeight="Bold"
MaxWidth="1000" />
<avalonedit:TextEditor SyntaxHighlighting="C#"
FontFamily="pack://application:,,,/Resources/Fonts/#Roboto Mono"
FontSize="10pt"
IsReadOnly="True"
Document="{Binding Document}"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
Margin="0 10 10 0"
MaxHeight="500"
Padding="10" />
<Separator Margin="0 15" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</DockPanel>
</controls:MaterialWindow>

View File

@ -2,14 +2,15 @@
using System.Collections.Generic;
using Artemis.UI.Shared.Services.Dialog;
using ICSharpCode.AvalonEdit.Document;
using Stylet;
namespace Artemis.UI.Shared.Screens.Dialogs
namespace Artemis.UI.Shared.Screens.Exceptions
{
public class ExceptionDialogViewModel : DialogViewModelBase
public class ExceptionViewModel : Screen
{
private List<DialogException> _exceptions;
public ExceptionDialogViewModel(string message, Exception exception)
public ExceptionViewModel(string message, Exception exception)
{
Header = message;
Exceptions = new List<DialogException>();
@ -29,11 +30,6 @@ namespace Artemis.UI.Shared.Screens.Dialogs
get => _exceptions;
set => SetAndNotify(ref _exceptions, value);
}
public void Close()
{
Session.Close();
}
}
public class DialogException

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Artemis.UI.Shared.Screens.Dialogs;
using Artemis.UI.Shared.Screens.Exceptions;
using Artemis.UI.Shared.Services.Interfaces;
using MaterialDesignThemes.Wpf;
using Ninject;
@ -15,15 +16,15 @@ namespace Artemis.UI.Shared.Services.Dialog
{
private readonly IKernel _kernel;
private readonly IViewManager _viewManager;
private readonly IWindowManager _windowManager;
public DialogService(IKernel kernel, IViewManager viewManager)
public DialogService(IKernel kernel, IViewManager viewManager, IWindowManager windowManager)
{
_kernel = kernel;
_viewManager = viewManager;
_windowManager = windowManager;
}
public bool IsExceptionDialogOpen { get; private set; }
public async Task<bool> ShowConfirmDialog(string header, string text, string confirmText = "Confirm", string cancelText = "Cancel")
{
var arguments = new IParameter[]
@ -90,30 +91,9 @@ namespace Artemis.UI.Shared.Services.Dialog
return await ShowDialog(identifier, _kernel.Get<T>(parameters));
}
public async Task ShowExceptionDialog(string message, Exception exception)
public void ShowExceptionDialog(string message, Exception exception)
{
if (IsExceptionDialogOpen)
return;
IsExceptionDialogOpen = true;
var arguments = new IParameter[]
{
new ConstructorArgument("message", message),
new ConstructorArgument("exception", exception)
};
await Execute.OnUIThreadAsync(async () =>
{
try
{
DialogHost.CloseDialogCommand.Execute(new object(), null);
await ShowDialog<ExceptionDialogViewModel>(arguments);
}
finally
{
IsExceptionDialogOpen = false;
}
});
_windowManager.ShowDialog(new ExceptionViewModel(message, exception));
}
private async Task<object> ShowDialog(string identifier, DialogViewModelBase viewModel)

View File

@ -99,10 +99,7 @@ namespace Artemis.UI.Shared.Services.Interfaces
/// Shows a dialog displaying the provided message and exception. Does not handle, log or throw the exception.
/// </summary>
/// <param name="message">The message to display in the dialog title</param>
/// <param name="exception">The exception to display. The exception message and stacktrace will be shown.</param>
/// <returns>A task resolving when the dialog is closed</returns>
Task ShowExceptionDialog(string message, Exception exception);
bool IsExceptionDialogOpen { get; }
void ShowExceptionDialog(string message, Exception exception);
}
}

View File

@ -1,6 +1,8 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Artemis.UI.ResourceDictionaries">
xmlns:dataModel="clr-namespace:Artemis.UI.Shared.DataModelVisualization.Shared;assembly=Artemis.UI.Shared"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:s="https://github.com/canton7/Stylet">
<Style x:Key="DisplayConditionButton" TargetType="{x:Type Button}" BasedOn="{StaticResource MaterialDesignFlatAccentBgButton}">
<Setter Property="Margin" Value="3 0" />
<Setter Property="Padding" Value="6 4" />
@ -9,14 +11,14 @@
<Setter Property="FontSize" Value="12" />
</Style>
<Style x:Key="DisplayConditionButtonLeftClickMenu" TargetType="{x:Type Button}" BasedOn="{StaticResource DisplayConditionButton}">
<Style x:Key="DisplayConditionButtonLeftClickMenu" TargetType="{x:Type Button}" BasedOn="{StaticResource DisplayConditionButton}">
<Style.Triggers>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/>
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
@ -24,4 +26,75 @@
</EventTrigger>
</Style.Triggers>
</Style>
<DataTemplate x:Key="DataModelSelectionTemplate">
<StackPanel>
<StackPanel.Resources>
<DataTemplate DataType="{x:Type dataModel:DataModelPropertiesViewModel}">
<TextBlock Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" />
</DataTemplate>
<DataTemplate DataType="{x:Type dataModel:DataModelListViewModel}">
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="FormatListBulleted" VerticalAlignment="Center" Margin="0 0 5 0" />
<TextBlock Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type dataModel:DataModelPropertyViewModel}">
<Grid>
<!-- Value description -->
<TextBlock Grid.Column="0" Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" />
</Grid>
</DataTemplate>
</StackPanel.Resources>
<ContentPresenter Content="{Binding}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="DataModelSelectionTemplateWithValues">
<StackPanel>
<StackPanel.Resources>
<DataTemplate DataType="{x:Type dataModel:DataModelPropertiesViewModel}">
<TextBlock Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" />
</DataTemplate>
<DataTemplate DataType="{x:Type dataModel:DataModelListViewModel}">
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="FormatListBulleted" VerticalAlignment="Center" Margin="0 0 5 0" />
<TextBlock Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type dataModel:DataModelPropertyViewModel}">
<Grid ToolTip="{Binding PropertyDescription.Description}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Value description -->
<TextBlock Grid.Column="0" Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" />
<!-- Value display -->
<StackPanel Grid.Column="1">
<TextBlock Text="{Binding DisplayValue, Mode=OneWay}"
FontFamily="Consolas"
HorizontalAlignment="Right"
Visibility="{Binding ShowToString, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"
Margin="15 0.5 0 0" />
<TextBlock Text="null"
FontFamily="Consolas"
HorizontalAlignment="Right"
Foreground="{DynamicResource MaterialDesignCheckBoxDisabled}"
Margin="15 0.5 0 0"
Visibility="{Binding ShowNull, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
<ContentControl s:View.Model="{Binding DisplayViewModel}"
FontFamily="Consolas"
Margin="15 0.5 0 0"
Visibility="{Binding ShowViewModel, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
</StackPanel>
</Grid>
</DataTemplate>
</StackPanel.Resources>
<ContentPresenter Content="{Binding}" />
</StackPanel>
</DataTemplate>
</ResourceDictionary>

View File

@ -19,19 +19,9 @@
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Style="{StaticResource MaterialDesignFlatButton}" IsCancel="True" Margin="0 8 8 0" Command="{s:Action Cancel}">
<Button.CommandParameter>
<system:Boolean xmlns:system="clr-namespace:System;assembly=mscorlib">
False
</system:Boolean>
</Button.CommandParameter>
CANCEL
</Button>
<Button Style="{StaticResource MaterialDesignFlatButton}" IsDefault="True" Margin="0 8 8 0" Command="{s:Action Accept}">
<Button.CommandParameter>
<system:Boolean xmlns:system="clr-namespace:System;assembly=mscorlib">
True
</system:Boolean>
</Button.CommandParameter>
ACCEPT
</Button>
</StackPanel>

View File

@ -0,0 +1,40 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.Dialogs.ProfileExportView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:Artemis.UI.Screens.Module.ProfileEditor.Dialogs"
xmlns:s="https://github.com/canton7/Stylet"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Margin="16" Width="500">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" Grid.Row="0">
Export current profile
</TextBlock>
<TextBlock Margin="0 10" TextAlignment="Justify" TextWrapping="Wrap" Grid.Row="1">
Please note that exporting profiles like this is placeholder functionality. The idea is that this will eventually happen via the workshop.
</TextBlock>
<TextBlock Margin="0 10" TextAlignment="Justify" TextWrapping="Wrap" Grid.Row="2">
The workshop will include tools to make profiles convert easily and look good on different layouts.
That means right now when someone imports this export unless they have the exact same setup as
you, they'll have to select LEDs for each layer in the profile.
</TextBlock>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="3">
<Button Style="{StaticResource MaterialDesignFlatButton}" IsCancel="True" Margin="0 8 8 0" Command="{s:Action Cancel}">
CANCEL
</Button>
<Button Style="{StaticResource MaterialDesignFlatButton}" IsDefault="True" Margin="0 8 0 0" Command="{s:Action Accept}">
I UNDERSTAND, EXPORT
</Button>
</StackPanel>
</Grid>
</UserControl>

View File

@ -0,0 +1,39 @@
using System.Windows;
using Artemis.Core.Models.Profile;
using Artemis.Core.Services.Storage.Interfaces;
using Artemis.UI.Shared.Services.Dialog;
using MaterialDesignThemes.Wpf;
namespace Artemis.UI.Screens.Module.ProfileEditor.Dialogs
{
public class ProfileExportViewModel : DialogViewModelBase
{
private readonly ISnackbarMessageQueue _mainMessageQueue;
private readonly IProfileService _profileService;
public ProfileExportViewModel(ProfileDescriptor profileDescriptor, IProfileService profileService, ISnackbarMessageQueue mainMessageQueue)
{
ProfileDescriptor = profileDescriptor;
_profileService = profileService;
_mainMessageQueue = mainMessageQueue;
}
public ProfileDescriptor ProfileDescriptor { get; }
public void Accept()
{
var encoded = _profileService.ExportProfile(ProfileDescriptor);
Clipboard.SetText(encoded);
_mainMessageQueue.Enqueue("Profile contents exported to clipboard.");
Session.Close();
}
public void Cancel()
{
Session.Close();
}
}
}

View File

@ -0,0 +1,51 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.Dialogs.ProfileImportView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:Artemis.UI.Screens.Module.ProfileEditor.Dialogs"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:avalonedit="http://icsharpcode.net/sharpdevelop/avalonedit"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Margin="16" Width="800">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" Grid.Row="0">
Import profile to current module
</TextBlock>
<TextBlock Margin="0 10" TextAlignment="Justify" TextWrapping="Wrap" Grid.Row="1">
Please note that importing profiles like this is placeholder functionality. The idea is that this will eventually happen via the workshop.
</TextBlock>
<TextBlock Margin="0 10" TextAlignment="Justify" TextWrapping="Wrap" Grid.Row="2">
The workshop will include tools to make profiles convert easily and look good on different layouts.
That means right now when you import this profile unless you have the exact same setup as
the person who exported it, you'll have to select LEDs for each layer in the profile.
</TextBlock>
<avalonedit:TextEditor Grid.Row="3" SyntaxHighlighting="JavaScript"
FontFamily="pack://application:,,,/Resources/Fonts/#Roboto Mono"
FontSize="10pt"
Document="{Binding Document}"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
Height="500"
Padding="10" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="4">
<Button Style="{StaticResource MaterialDesignFlatButton}" IsCancel="True" Margin="0 8 8 0" Command="{s:Action Cancel}">
CANCEL
</Button>
<Button Style="{StaticResource MaterialDesignFlatButton}" IsDefault="True" Margin="0 8 0 0" Command="{s:Action Accept}">
I UNDERSTAND, IMPORT
</Button>
</StackPanel>
</Grid>
</UserControl>

View File

@ -0,0 +1,47 @@
using System.Windows;
using Artemis.Core.Models.Profile;
using Artemis.Core.Plugins.Abstract;
using Artemis.Core.Services.Storage.Interfaces;
using Artemis.UI.Shared.Services.Dialog;
using ICSharpCode.AvalonEdit.Document;
using MaterialDesignThemes.Wpf;
namespace Artemis.UI.Screens.Module.ProfileEditor.Dialogs
{
public class ProfileImportViewModel : DialogViewModelBase
{
private readonly ISnackbarMessageQueue _mainMessageQueue;
private readonly IProfileService _profileService;
private string _profileJson;
public ProfileImportViewModel(ProfileModule profileModule, IProfileService profileService, ISnackbarMessageQueue mainMessageQueue)
{
ProfileModule = profileModule;
Document = new TextDocument();
_profileService = profileService;
_mainMessageQueue = mainMessageQueue;
}
public ProfileModule ProfileModule { get; }
public TextDocument Document { get; set; }
public string ProfileJson
{
get => _profileJson;
set => SetAndNotify(ref _profileJson, value);
}
public void Accept()
{
_profileService.ImportProfile(Document.Text, ProfileModule);
_mainMessageQueue.Enqueue("Profile imported.");
Session.Close();
}
public void Cancel()
{
Session.Close();
}
}
}

View File

@ -97,6 +97,14 @@
<materialDesign:PackIcon Kind="InsertLink" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Add list condition"
ToolTip="A condition that evaluates on items in a list"
Command="{s:Action AddCondition}"
CommandParameter="List">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="FormatListBulleted" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Add group" ToolTip="A group can contain conditions and other groups" Command="{s:Action AddGroup}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="CodeParentheses" />

View File

@ -66,6 +66,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
DisplayConditionGroup.AddChild(new DisplayConditionPredicate(DisplayConditionGroup, PredicateType.Static));
else if (type == "Dynamic")
DisplayConditionGroup.AddChild(new DisplayConditionPredicate(DisplayConditionGroup, PredicateType.Dynamic));
else if (type == "List")
DisplayConditionGroup.AddChild(new DisplayConditionListPredicate(DisplayConditionGroup));
Update();
_profileEditorService.UpdateSelectedProfileElement();

View File

@ -4,10 +4,146 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions"
xmlns:converters="clr-namespace:Artemis.UI.Converters"
xmlns:utilities="clr-namespace:Artemis.UI.Utilities"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance Type=local:DisplayConditionListPredicateViewModel, IsDesignTimeCreatable=False}">
<Grid>
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
<utilities:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
</ResourceDictionary>
<ResourceDictionary Source="pack://application:,,,/Artemis.UI;component/ResourceDictionaries/DisplayConditions.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid Margin="0 3" Visibility="{Binding IsInitialized, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0"
Grid.Column="0"
Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Left"
Foreground="#E74C4C"
Width="25"
Height="25"
Command="{s:Action Delete}">
<materialDesign:PackIcon Kind="Close" Width="18" Height="18" />
</Button>
<!-- Left side, the list this predicate is targeting -->
<Button Grid.Row="0"
Grid.Column="1"
Background="#ab47bc"
BorderBrush="#ab47bc"
Style="{StaticResource DisplayConditionButton}"
ToolTip="{Binding SelectedListProperty.DisplayPropertyPath}"
Click="PropertyButton_OnClick">
<Button.ContextMenu>
<ContextMenu ItemsSource="{Binding TargetDataModel.Children}" IsOpen="{Binding TargetDataModelOpen, Mode=OneWayToSource}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource MaterialDesignMenuItem}">
<Setter Property="ItemsSource" Value="{Binding Children}" />
<Setter Property="Command" Value="{Binding Data.SelectListPropertyCommand, Source={StaticResource DataContextProxy}}" />
<Setter Property="CommandParameter" Value="{Binding}" />
<Setter Property="CommandTarget" Value="{Binding}" />
<Setter Property="IsEnabled" Value="{Binding IsMatchingFilteredTypes}" />
<Setter Property="IsSubmenuOpen" Value="{Binding IsVisualizationExpanded, Mode=TwoWay}" />
<Setter Property="HeaderTemplate" Value="{StaticResource DataModelSelectionTemplate}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Button.ContextMenu>
<Grid>
<TextBlock Text="{Binding SelectedListProperty.PropertyDescription.Name}"
Visibility="{Binding SelectedListProperty, Converter={StaticResource NullToVisibilityConverter}}" />
<TextBlock Text="« Select a list »"
FontStyle="Italic"
Visibility="{Binding SelectedListProperty, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}" />
</Grid>
</Button>
<!-- Operator -->
<Button Grid.Row="0"
Grid.Column="2"
Style="{StaticResource DisplayConditionButtonLeftClickMenu}"
Background="#7B7B7B"
BorderBrush="#7B7B7B"
Content="{Binding SelectedListOperator}"
Click="PropertyButton_OnClick">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Any" Command="{s:Action SelectListOperator}" CommandParameter="Any" />
<MenuItem Header="All" Command="{s:Action SelectListOperator}" CommandParameter="All" />
<MenuItem Header="None" Command="{s:Action SelectListOperator}" CommandParameter="None" />
<MenuItem Header="Count (NYI)" Command="{s:Action SelectListOperator}" CommandParameter="Count" IsEnabled="False"/>
</ContextMenu>
</Button.ContextMenu>
</Button>
<Button x:Name="AddChildButton"
Grid.Row="0"
Grid.Column="3"
HorizontalAlignment="Left"
Foreground="#4CE758"
Width="25"
Height="25">
<Button.Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource MaterialDesignIconForegroundButton}">
<Style.Triggers>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</Button.Style>
<materialDesign:PackIcon Kind="Add" Width="18" Height="18" />
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Add static condition"
ToolTip="A condition that compares a data model property to a static input"
Command="{s:Action AddCondition}"
CommandParameter="Static">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="FormTextarea" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Add dynamic condition"
ToolTip="A condition that compares two data model properties"
Command="{s:Action AddCondition}"
CommandParameter="Dynamic">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="InsertLink" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Add group" ToolTip="A group can contain conditions and other groups" Command="{s:Action AddGroup}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="CodeParentheses" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</Button.ContextMenu>
</Button>
</Grid>
</UserControl>
</UserControl>

View File

@ -0,0 +1,26 @@
using System.Windows;
using System.Windows.Controls;
namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
{
/// <summary>
/// Interaction logic for DisplayConditionListPredicateView.xaml
/// </summary>
public partial class DisplayConditionListPredicateView : UserControl
{
public DisplayConditionListPredicateView()
{
InitializeComponent();
}
private void PropertyButton_OnClick(object sender, RoutedEventArgs e)
{
// DataContext is not set when using left button, I don't know why but there it is
if (sender is Button button && button.ContextMenu != null)
{
button.ContextMenu.DataContext = button.DataContext;
button.ContextMenu.IsOpen = true;
}
}
}
}

View File

@ -1,18 +1,206 @@
using Artemis.Core.Models.Profile.Conditions;
using System;
using System.Collections;
using System.Linq;
using System.Threading.Tasks;
using System.Timers;
using Artemis.Core.Models.Profile.Conditions;
using Artemis.Core.Plugins.Models;
using Artemis.Core.Services;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions.Abstract;
using Artemis.UI.Shared.DataModelVisualization.Shared;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Interfaces;
using Artemis.UI.Utilities;
using Humanizer;
namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
{
public class DisplayConditionListPredicateViewModel : DisplayConditionViewModel
{
public DisplayConditionListPredicateViewModel(DisplayConditionListPredicate displayConditionListPredicate, DisplayConditionViewModel parent) : base(displayConditionListPredicate, parent)
private readonly IProfileEditorService _profileEditorService;
private readonly IDataModelVisualizationService _dataModelVisualizationService;
private readonly IDisplayConditionsVmFactory _displayConditionsVmFactory;
private bool _isInitialized;
private DataModelVisualizationViewModel _selectedListProperty;
private DataModelPropertiesViewModel _targetDataModel;
private readonly Timer _updateTimer;
public DisplayConditionListPredicateViewModel(
DisplayConditionListPredicate displayConditionListPredicate,
DisplayConditionViewModel parent,
IProfileEditorService profileEditorService,
IDataModelVisualizationService dataModelVisualizationService,
IDisplayConditionsVmFactory displayConditionsVmFactory,
ISettingsService settingsService) : base(displayConditionListPredicate, parent)
{
_profileEditorService = profileEditorService;
_dataModelVisualizationService = dataModelVisualizationService;
_displayConditionsVmFactory = displayConditionsVmFactory;
_updateTimer = new Timer(500);
SelectListPropertyCommand = new DelegateCommand(ExecuteSelectListProperty);
ShowDataModelValues = settingsService.GetSetting<bool>("ProfileEditor.ShowDataModelValues");
// Initialize async, no need to wait for it
Task.Run(Initialize);
}
public DelegateCommand SelectListPropertyCommand { get; }
public PluginSetting<bool> ShowDataModelValues { get; }
public DisplayConditionListPredicate DisplayConditionListPredicate => (DisplayConditionListPredicate) Model;
public bool IsInitialized
{
get => _isInitialized;
set => SetAndNotify(ref _isInitialized, value);
}
public bool TargetDataModelOpen { get; set; }
public DataModelPropertiesViewModel TargetDataModel
{
get => _targetDataModel;
set => SetAndNotify(ref _targetDataModel, value);
}
public DataModelVisualizationViewModel SelectedListProperty
{
get => _selectedListProperty;
set => SetAndNotify(ref _selectedListProperty, value);
}
public string SelectedListOperator => DisplayConditionListPredicate.ListOperator.Humanize();
public void SelectListOperator(string type)
{
var enumValue = Enum.Parse<ListOperator>(type);
DisplayConditionListPredicate.ListOperator = enumValue;
NotifyOfPropertyChange(nameof(SelectedListOperator));
}
public void AddCondition(string type)
{
if (type == "Static")
DisplayConditionListPredicate.AddChild(new DisplayConditionPredicate(DisplayConditionListPredicate, PredicateType.Static));
else if (type == "Dynamic")
DisplayConditionListPredicate.AddChild(new DisplayConditionPredicate(DisplayConditionListPredicate, PredicateType.Dynamic));
Update();
_profileEditorService.UpdateSelectedProfileElement();
}
public void AddGroup()
{
DisplayConditionListPredicate.AddChild(new DisplayConditionGroup(DisplayConditionListPredicate));
Update();
_profileEditorService.UpdateSelectedProfileElement();
}
public override void Delete()
{
base.Delete();
_profileEditorService.UpdateSelectedProfileElement();
}
public void Initialize()
{
// Get the data models
TargetDataModel = _dataModelVisualizationService.GetMainDataModelVisualization();
if (!_dataModelVisualizationService.GetPluginExtendsDataModel(_profileEditorService.GetCurrentModule()))
TargetDataModel.Children.Add(_dataModelVisualizationService.GetPluginDataModelVisualization(_profileEditorService.GetCurrentModule()));
TargetDataModel.UpdateRequested += TargetDataModelUpdateRequested;
Update();
_updateTimer.Start();
_updateTimer.Elapsed += OnUpdateTimerOnElapsed;
IsInitialized = true;
}
protected override void Dispose(bool disposing)
{
_updateTimer.Stop();
_updateTimer.Elapsed -= OnUpdateTimerOnElapsed;
}
private void OnUpdateTimerOnElapsed(object sender, ElapsedEventArgs e)
{
if (TargetDataModelOpen)
TargetDataModel.Update(_dataModelVisualizationService);
}
private void TargetDataModelUpdateRequested(object sender, EventArgs e)
{
TargetDataModel.ApplyTypeFilter(true, typeof(IEnumerable));
}
public void ApplyList()
{
DisplayConditionListPredicate.UpdateList(SelectedListProperty.DataModel, SelectedListProperty.PropertyPath);
_profileEditorService.UpdateSelectedProfileElement();
Update();
}
public override void Update()
{
if (TargetDataModel == null)
return;
NotifyOfPropertyChange(nameof(SelectedListOperator));
// Update the selected list property
if (DisplayConditionListPredicate.ListDataModel != null && DisplayConditionListPredicate.ListPropertyPath != null)
SelectedListProperty = TargetDataModel.GetChildByPath(DisplayConditionListPredicate.ListDataModel.PluginInfo.Guid, DisplayConditionListPredicate.ListPropertyPath);
// Ensure filtering is applied to include Enumerables only
TargetDataModel.ApplyTypeFilter(true, typeof(IEnumerable));
// Remove VMs of effects no longer applied on the layer
var toRemove = Children.Where(c => !DisplayConditionListPredicate.Children.Contains(c.Model)).ToList();
// Using RemoveRange breaks our lovely animations
foreach (var displayConditionViewModel in toRemove)
{
Children.Remove(displayConditionViewModel);
displayConditionViewModel.Dispose();
}
foreach (var childModel in Model.Children)
{
if (Children.Any(c => c.Model == childModel))
continue;
switch (childModel)
{
case DisplayConditionGroup displayConditionGroup:
Children.Add(_displayConditionsVmFactory.DisplayConditionGroupViewModel(displayConditionGroup, this));
break;
case DisplayConditionListPredicate displayConditionListPredicate:
Children.Add(_displayConditionsVmFactory.DisplayConditionListPredicateViewModel(displayConditionListPredicate, this));
break;
case DisplayConditionPredicate displayConditionPredicate:
Children.Add(_displayConditionsVmFactory.DisplayConditionPredicateViewModel(displayConditionPredicate, this));
break;
}
}
foreach (var childViewModel in Children)
childViewModel.Update();
}
private void ExecuteSelectListProperty(object context)
{
if (!(context is DataModelVisualizationViewModel dataModelVisualizationViewModel))
return;
SelectedListProperty = dataModelVisualizationViewModel;
ApplyList();
}
}
}

View File

@ -21,47 +21,6 @@
<ResourceDictionary>
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
<utilities:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
<DataTemplate x:Key="DataModelSelectionTemplate">
<StackPanel>
<StackPanel.Resources>
<DataTemplate DataType="{x:Type dataModel:DataModelPropertiesViewModel}">
<TextBlock Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" />
</DataTemplate>
<DataTemplate DataType="{x:Type dataModel:DataModelPropertyViewModel}">
<Grid ToolTip="{Binding PropertyDescription.Description}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Value description -->
<TextBlock Grid.Column="0" Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" />
<!-- Value display -->
<StackPanel Grid.Column="1" Visibility="{Binding Data.ShowDataModelValues.Value, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay, Source={StaticResource DataContextProxy}}">
<TextBlock Text="{Binding DisplayValue, Mode=OneWay}"
FontFamily="Consolas"
HorizontalAlignment="Right"
Visibility="{Binding ShowToString, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"
Margin="15 0.5 0 0" />
<TextBlock Text="null"
FontFamily="Consolas"
HorizontalAlignment="Right"
Foreground="{DynamicResource MaterialDesignCheckBoxDisabled}"
Margin="15 0.5 0 0"
Visibility="{Binding ShowNull, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
<ContentControl s:View.Model="{Binding DisplayViewModel}"
FontFamily="Consolas"
Margin="15 0.5 0 0"
Visibility="{Binding ShowViewModel, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
</StackPanel>
</Grid>
</DataTemplate>
</StackPanel.Resources>
<ContentPresenter Content="{Binding}" />
</StackPanel>
</DataTemplate>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

View File

@ -40,9 +40,14 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
private List<Type> _supportedInputTypes;
private readonly Timer _updateTimer;
public DisplayConditionPredicateViewModel(DisplayConditionPredicate displayConditionPredicate, DisplayConditionViewModel parent, IProfileEditorService profileEditorService,
IDataModelVisualizationService dataModelVisualizationService, IDataModelService dataModelService, ISettingsService settingsService, IEventAggregator eventAggregator)
: base(displayConditionPredicate, parent)
public DisplayConditionPredicateViewModel(
DisplayConditionPredicate displayConditionPredicate,
DisplayConditionViewModel parent,
IProfileEditorService profileEditorService,
IDataModelVisualizationService dataModelVisualizationService,
IDataModelService dataModelService,
ISettingsService settingsService,
IEventAggregator eventAggregator) : base(displayConditionPredicate, parent)
{
_profileEditorService = profileEditorService;
_dataModelVisualizationService = dataModelVisualizationService;

View File

@ -135,9 +135,7 @@
VerticalScrollBarVisibility="Hidden"
ScrollChanged="TimelineScrollChanged">
<Border BorderThickness="0,0,1,0" BorderBrush="{DynamicResource MaterialDesignDivider}">
<Grid>
<ContentControl s:View.Model="{Binding TreeViewModel}" />
</Grid>
<ContentControl s:View.Model="{Binding TreeViewModel}" />
</Border>
</ScrollViewer>
<materialDesign:TransitionerSlide>
@ -212,7 +210,8 @@
</ScrollViewer>
<!-- Timeline rails -->
<ScrollViewer x:Name="TimelineRailsScrollViewer" Grid.Row="1" Style="{StaticResource SvStyle}" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" ScrollChanged="TimelineScrollChanged">
<ScrollViewer x:Name="TimelineRailsScrollViewer" Grid.Row="1" Style="{StaticResource SvStyle}" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
ScrollChanged="TimelineScrollChanged">
<Grid Background="{DynamicResource MaterialDesignToolBarBackground}">
<Canvas Grid.Column="0" Panel.ZIndex="1">
<Line Canvas.Left="{Binding TimeCaretPosition}"

View File

@ -28,7 +28,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Tree
public LayerPropertyGroupViewModel LayerPropertyGroupViewModel { get; }
public async void OpenBrushSettings()
public void OpenBrushSettings()
{
try
{
@ -38,12 +38,12 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Tree
}
catch (Exception e)
{
await _dialogService.ShowExceptionDialog("An exception occured while trying to show the brush's settings window", e);
_dialogService.ShowExceptionDialog("An exception occured while trying to show the brush's settings window", e);
throw;
}
}
public async void OpenEffectSettings()
public void OpenEffectSettings()
{
try
{
@ -53,7 +53,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Tree
}
catch (Exception e)
{
await _dialogService.ShowExceptionDialog("An exception occured while trying to show the effect's settings window", e);
_dialogService.ShowExceptionDialog("An exception occured while trying to show the effect's settings window", e);
throw;
}
}

View File

@ -131,11 +131,13 @@
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ComboBox Height="26"
VerticalAlignment="Top"
ItemsSource="{Binding Profiles}"
SelectedItem="{Binding SelectedProfile}"
SelectedItem="{Binding SelectedProfile}"
ItemTemplate="{StaticResource ProfileDescriptorTemplate}">
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
@ -144,7 +146,7 @@
</ComboBox.ItemsPanel>
</ComboBox>
<Button Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
Margin="10 0"
Margin="5 0"
Grid.Column="1"
Width="26"
Height="26"
@ -153,6 +155,7 @@
<materialDesign:PackIcon Kind="Add" Height="14" Width="14" />
</Button>
<Button Style="{StaticResource MaterialDesignFloatingActionMiniDarkButton}"
Margin="5 0"
Grid.Column="2"
Width="26"
Height="26"
@ -160,6 +163,24 @@
Command="{s:Action DeleteActiveProfile}">
<materialDesign:PackIcon Kind="TrashCanOutline" Height="14" Width="14" />
</Button>
<Button Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
Margin="5 0"
Grid.Column="3"
Width="26"
Height="26"
VerticalAlignment="Top"
Command="{s:Action ExportActiveProfile}">
<materialDesign:PackIcon Kind="Export" Height="14" Width="14" />
</Button>
<Button Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
Margin="5 0 0 0"
Grid.Column="4"
Width="26"
Height="26"
VerticalAlignment="Top"
Command="{s:Action ImportProfile}">
<materialDesign:PackIcon Kind="Import" Height="14" Width="14" />
</Button>
</Grid>
<!-- Profile elements -->

View File

@ -174,6 +174,22 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
RemoveProfile(SelectedProfile);
}
public async Task ExportActiveProfile()
{
await DialogService.ShowDialog<ProfileExportViewModel>(new Dictionary<string, object>
{
{"profileDescriptor", SelectedProfile}
});
}
public async Task ImportProfile()
{
await DialogService.ShowDialog<ProfileImportViewModel>(new Dictionary<string, object>
{
{"profileModule", Module}
});
}
public void Undo()
{
// Expanded status is also undone because undoing works a bit crude, that's annoying
@ -292,7 +308,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
SelectedProfile = lastActiveProfile;
return;
}
// Create a default profile if there is none
var defaultProfile = _profileService.CreateProfileDescriptor(Module, "Default");
Profiles.Add(defaultProfile);

View File

@ -52,7 +52,7 @@ namespace Artemis.UI.Screens.Settings.Debug
_deviceService.IdentifyDevice(Device);
}
public async void OpenPluginDirectory()
public void OpenPluginDirectory()
{
try
{
@ -60,11 +60,11 @@ namespace Artemis.UI.Screens.Settings.Debug
}
catch (Exception e)
{
await _dialogService.ShowExceptionDialog("Welp, we couldn't open the device's plugin folder for you", e);
_dialogService.ShowExceptionDialog("Welp, we couldn't open the device's plugin folder for you", e);
}
}
public async void OpenImageDirectory()
public void OpenImageDirectory()
{
if (!CanOpenImageDirectory)
return;
@ -75,7 +75,7 @@ namespace Artemis.UI.Screens.Settings.Debug
}
catch (Exception e)
{
await _dialogService.ShowExceptionDialog("Welp, we couldn't open the device's image folder for you", e);
_dialogService.ShowExceptionDialog("Welp, we couldn't open the device's image folder for you", e);
}
}

View File

@ -196,7 +196,7 @@ namespace Artemis.UI.Screens.Settings
_debugService.ShowDebugger();
}
public async Task ShowLogsFolder()
public void ShowLogsFolder()
{
try
{
@ -204,11 +204,11 @@ namespace Artemis.UI.Screens.Settings
}
catch (Exception e)
{
await _dialogService.ShowExceptionDialog("Welp, we couldn\'t open the logs folder for you", e);
_dialogService.ShowExceptionDialog("Welp, we couldn\'t open the logs folder for you", e);
}
}
public async Task ShowDataFolder()
public void ShowDataFolder()
{
try
{
@ -216,7 +216,7 @@ namespace Artemis.UI.Screens.Settings
}
catch (Exception e)
{
await _dialogService.ShowExceptionDialog("Welp, we couldn\'t open the data folder for you", e);
_dialogService.ShowExceptionDialog("Welp, we couldn\'t open the data folder for you", e);
}
}
@ -240,7 +240,7 @@ namespace Artemis.UI.Screens.Settings
base.OnClose();
}
private async Task ApplyAutorun()
private void ApplyAutorun()
{
try
{
@ -254,7 +254,7 @@ namespace Artemis.UI.Screens.Settings
}
catch (Exception e)
{
await _dialogService.ShowExceptionDialog("An exception occured while trying to apply the auto run setting", e);
_dialogService.ShowExceptionDialog("An exception occured while trying to apply the auto run setting", e);
throw;
}
}

View File

@ -57,7 +57,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
_windowManager.ShowWindow(_deviceDebugVmFactory.Create(Device));
}
public async void OpenPluginDirectory()
public void OpenPluginDirectory()
{
try
{
@ -65,7 +65,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
}
catch (Exception e)
{
await _dialogService.ShowExceptionDialog("Welp, we couldn't open the device's plugin folder for you", e);
_dialogService.ShowExceptionDialog("Welp, we couldn't open the device's plugin folder for you", e);
}
}
}

View File

@ -62,7 +62,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
set => Task.Run(() => UpdateEnabled(value));
}
public async Task OpenSettings()
public void OpenSettings()
{
try
{
@ -72,12 +72,12 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
}
catch (Exception e)
{
await _dialogService.ShowExceptionDialog("An exception occured while trying to show the plugin's settings window", e);
_dialogService.ShowExceptionDialog("An exception occured while trying to show the plugin's settings window", e);
throw;
}
}
public async Task ShowLogsFolder()
public void ShowLogsFolder()
{
try
{
@ -85,16 +85,16 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
}
catch (Exception e)
{
await _dialogService.ShowExceptionDialog("Welp, we couldn\'t open the logs folder for you", e);
_dialogService.ShowExceptionDialog("Welp, we couldn\'t open the logs folder for you", e);
}
}
public async Task ShowLoadException()
public void ShowLoadException()
{
if (PluginInfo.LoadException == null)
return;
await _dialogService.ShowExceptionDialog("The plugin failed to load: " + PluginInfo.LoadException.Message, PluginInfo.LoadException);
_dialogService.ShowExceptionDialog("The plugin failed to load: " + PluginInfo.LoadException.Message, PluginInfo.LoadException);
}
private PackIconKind GetIconKind()
@ -157,7 +157,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
}
catch (Exception e)
{
_snackbarMessageQueue.Enqueue($"Failed to enable plugin {PluginInfo.Name}\r\n{e.Message}", "VIEW LOGS", async () => await ShowLogsFolder());
_snackbarMessageQueue.Enqueue($"Failed to enable plugin {PluginInfo.Name}\r\n{e.Message}", "VIEW LOGS", ShowLogsFolder);
}
finally
{

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using Artemis.Plugins.Modules.General.DataModel.Windows;
namespace Artemis.Plugins.Modules.General.DataModel
@ -8,10 +9,13 @@ namespace Artemis.Plugins.Modules.General.DataModel
public GeneralDataModel()
{
TimeDataModel = new TimeDataModel();
TestTimeList = new List<TimeDataModel>();
}
public WindowDataModel ActiveWindow { get; set; }
public TimeDataModel TimeDataModel { get; set; }
public List<TimeDataModel> TestTimeList { get; set; }
}
public class TimeDataModel : Core.Plugins.Abstract.DataModels.DataModel

View File

@ -31,6 +31,11 @@ namespace Artemis.Plugins.Modules.General
DisplayName = "General";
DisplayIcon = "AllInclusive";
ExpandsDataModel = true;
DataModel.TestTimeList.Add(new TimeDataModel {CurrentTime = DateTime.Now.AddDays(1), CurrentTimeUTC = DateTime.UtcNow.AddDays(1)});
DataModel.TestTimeList.Add(new TimeDataModel {CurrentTime = DateTime.Now.AddDays(2), CurrentTimeUTC = DateTime.UtcNow.AddDays(2)});
DataModel.TestTimeList.Add(new TimeDataModel {CurrentTime = DateTime.Now.AddDays(3), CurrentTimeUTC = DateTime.UtcNow.AddDays(3)});
DataModel.TestTimeList.Add(new TimeDataModel {CurrentTime = DateTime.Now.AddDays(4), CurrentTimeUTC = DateTime.UtcNow.AddDays(4)});
}
public override void DisablePlugin()