mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Storage - Added LiteDB to SQLite migration
This commit is contained in:
parent
70994feb32
commit
d4e4d52f84
@ -434,7 +434,6 @@ internal class ProfileService : IProfileService
|
||||
}
|
||||
|
||||
// A new GUID will be given on save
|
||||
configurationEntity.FileIconId = Guid.Empty;
|
||||
ProfileConfiguration profileConfiguration = new(category, containerEntity);
|
||||
if (nameAffix != null)
|
||||
profileConfiguration.Name = $"{profileConfiguration.Name} - {nameAffix}";
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LiteDB" Version="5.0.17" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.General;
|
||||
|
||||
public class QueuedActionEntity
|
||||
{
|
||||
public QueuedActionEntity()
|
||||
{
|
||||
Parameters = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
public Guid Id { get; set; }
|
||||
public string Type { get; set; } = string.Empty;
|
||||
public DateTimeOffset CreatedAt { get; set; }
|
||||
|
||||
public Dictionary<string, object> Parameters { get; set; }
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.General;
|
||||
|
||||
public class ReleaseEntity
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string Version { get; set; } = string.Empty;
|
||||
public DateTimeOffset? InstalledAt { get; set; }
|
||||
|
||||
public Storage.Entities.General.ReleaseEntity Migrate()
|
||||
{
|
||||
return new Storage.Entities.General.ReleaseEntity()
|
||||
{
|
||||
Id = Id,
|
||||
Version = Version,
|
||||
InstalledAt = InstalledAt ?? DateTimeOffset.Now
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.General;
|
||||
|
||||
public class ScriptConfigurationEntity
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string ScriptingProviderId { get; set; } = string.Empty;
|
||||
public string? ScriptContent { get; set; }
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Plugins;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the configuration of a plugin, each plugin has one configuration
|
||||
/// </summary>
|
||||
public class PluginEntity
|
||||
{
|
||||
public PluginEntity()
|
||||
{
|
||||
Features = new List<PluginFeatureEntity>();
|
||||
}
|
||||
|
||||
public Guid Id { get; set; }
|
||||
public bool IsEnabled { get; set; }
|
||||
|
||||
public List<PluginFeatureEntity> Features { get; set; }
|
||||
|
||||
public Artemis.Storage.Entities.Plugins.PluginEntity Migrate()
|
||||
{
|
||||
return new Artemis.Storage.Entities.Plugins.PluginEntity()
|
||||
{
|
||||
Id = Id,
|
||||
IsEnabled = IsEnabled,
|
||||
Features = Features.Select(f => f.Migrate()).ToList()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the configuration of a plugin feature, each feature has one configuration
|
||||
/// </summary>
|
||||
public class PluginFeatureEntity
|
||||
{
|
||||
public string Type { get; set; } = string.Empty;
|
||||
public bool IsEnabled { get; set; }
|
||||
|
||||
public Artemis.Storage.Entities.Plugins.PluginFeatureEntity Migrate()
|
||||
{
|
||||
return new Artemis.Storage.Entities.Plugins.PluginFeatureEntity()
|
||||
{
|
||||
Type = Type,
|
||||
IsEnabled = IsEnabled
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Plugins;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the setting of a plugin, a plugin can have multiple settings
|
||||
/// </summary>
|
||||
public class PluginSettingEntity
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid PluginGuid { get; set; }
|
||||
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Value { get; set; } = string.Empty;
|
||||
|
||||
public Artemis.Storage.Entities.Plugins.PluginSettingEntity Migrate()
|
||||
{
|
||||
return new Storage.Entities.Plugins.PluginSettingEntity
|
||||
{
|
||||
Id = Id,
|
||||
PluginGuid = PluginGuid,
|
||||
Name = Name,
|
||||
Value = Value
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.Profile.Conditions;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Abstract;
|
||||
|
||||
public abstract class RenderElementEntity
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid ParentId { get; set; }
|
||||
|
||||
public List<LayerEffectEntity> LayerEffects { get; set; } = new();
|
||||
|
||||
public IConditionEntity? DisplayCondition { get; set; }
|
||||
public TimelineEntity? Timeline { get; set; }
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.AdaptionHints;
|
||||
|
||||
public class CategoryAdaptionHintEntity : IAdaptionHintEntity
|
||||
{
|
||||
public int Category { get; set; }
|
||||
|
||||
public bool LimitAmount { get; set; }
|
||||
public int Skip { get; set; }
|
||||
public int Amount { get; set; }
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.AdaptionHints;
|
||||
|
||||
public class DeviceAdaptionHintEntity : IAdaptionHintEntity
|
||||
{
|
||||
public int DeviceType { get; set; }
|
||||
|
||||
public bool LimitAmount { get; set; }
|
||||
public int Skip { get; set; }
|
||||
public int Amount { get; set; }
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.AdaptionHints;
|
||||
|
||||
[JsonDerivedType(typeof(CategoryAdaptionHintEntity), "Category")]
|
||||
[JsonDerivedType(typeof(DeviceAdaptionHintEntity), "Device")]
|
||||
[JsonDerivedType(typeof(KeyboardSectionAdaptionHintEntity), "KeyboardSection")]
|
||||
[JsonDerivedType(typeof(SingleLedAdaptionHintEntity), "SingleLed")]
|
||||
public interface IAdaptionHintEntity;
|
||||
@ -0,0 +1,6 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.AdaptionHints;
|
||||
|
||||
public class KeyboardSectionAdaptionHintEntity : IAdaptionHintEntity
|
||||
{
|
||||
public int Section { get; set; }
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.AdaptionHints;
|
||||
|
||||
public class SingleLedAdaptionHintEntity : IAdaptionHintEntity
|
||||
{
|
||||
public int LedId { get; set; }
|
||||
|
||||
public bool LimitAmount { get; set; }
|
||||
public int Skip { get; set; }
|
||||
public int Amount { get; set; }
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Conditions;
|
||||
|
||||
public class AlwaysOnConditionEntity : IConditionEntity;
|
||||
@ -0,0 +1,12 @@
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Conditions;
|
||||
|
||||
public class EventConditionEntity : IConditionEntity
|
||||
{
|
||||
public int TriggerMode { get; set; }
|
||||
public int OverlapMode { get; set; }
|
||||
public int ToggleOffMode { get; set; }
|
||||
public DataModelPathEntity? EventPath { get; set; }
|
||||
public NodeScriptEntity? Script { get; set; }
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Conditions;
|
||||
|
||||
[JsonDerivedType(typeof(AlwaysOnConditionEntity), "AlwaysOn")]
|
||||
[JsonDerivedType(typeof(EventConditionEntity), "Event")]
|
||||
[JsonDerivedType(typeof(PlayOnceConditionEntity), "PlayOnce")]
|
||||
[JsonDerivedType(typeof(StaticConditionEntity), "Static")]
|
||||
public interface IConditionEntity;
|
||||
@ -0,0 +1,3 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Conditions;
|
||||
|
||||
public class PlayOnceConditionEntity : IConditionEntity;
|
||||
@ -0,0 +1,10 @@
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Conditions;
|
||||
|
||||
public class StaticConditionEntity : IConditionEntity
|
||||
{
|
||||
public int PlayMode { get; set; }
|
||||
public int StopMode { get; set; }
|
||||
public NodeScriptEntity? Script { get; set; }
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.DataBindings;
|
||||
|
||||
public class DataBindingEntity
|
||||
{
|
||||
public bool IsEnabled { get; set; }
|
||||
public NodeScriptEntity? NodeScript { get; set; }
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||
|
||||
public class DataModelPathEntity
|
||||
{
|
||||
public string Path { get; set; } = string.Empty;
|
||||
public string? DataModelId { get; set; }
|
||||
public string? Type { get; set; }
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.Profile.Abstract;
|
||||
using LiteDB;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||
|
||||
public class FolderEntity : RenderElementEntity
|
||||
{
|
||||
public int Order { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public bool IsExpanded { get; set; }
|
||||
public bool Suspended { get; set; }
|
||||
|
||||
[BsonRef("ProfileEntity")]
|
||||
public ProfileEntity Profile { get; set; } = null!;
|
||||
|
||||
public Guid ProfileId { get; set; }
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||
|
||||
public class KeyframeEntity
|
||||
{
|
||||
public TimeSpan Position { get; set; }
|
||||
public int Timeline { get; set; }
|
||||
public string Value { get; set; } = string.Empty;
|
||||
public int EasingFunction { get; set; }
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||
|
||||
public class LayerBrushEntity
|
||||
{
|
||||
public string ProviderId { get; set; } = string.Empty;
|
||||
public string BrushType { get; set; } = string.Empty;
|
||||
|
||||
public PropertyGroupEntity? PropertyGroup { get; set; }
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||
|
||||
public class LayerEffectEntity
|
||||
{
|
||||
public string ProviderId { get; set; } = string.Empty;
|
||||
public string EffectType { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public bool HasBeenRenamed { get; set; }
|
||||
public int Order { get; set; }
|
||||
|
||||
public PropertyGroupEntity? PropertyGroup { get; set; }
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.Profile.Abstract;
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.Profile.AdaptionHints;
|
||||
using LiteDB;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||
|
||||
public class LayerEntity : RenderElementEntity
|
||||
{
|
||||
public LayerEntity()
|
||||
{
|
||||
Leds = new List<LedEntity>();
|
||||
AdaptionHints = new List<IAdaptionHintEntity>();
|
||||
}
|
||||
|
||||
public int Order { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public bool Suspended { get; set; }
|
||||
|
||||
public List<LedEntity> Leds { get; set; }
|
||||
public List<IAdaptionHintEntity> AdaptionHints { get; set; }
|
||||
|
||||
public PropertyGroupEntity? GeneralPropertyGroup { get; set; }
|
||||
public PropertyGroupEntity? TransformPropertyGroup { get; set; }
|
||||
public LayerBrushEntity? LayerBrush { get; set; }
|
||||
|
||||
[BsonRef("ProfileEntity")]
|
||||
public ProfileEntity Profile { get; set; } = null!;
|
||||
|
||||
public Guid ProfileId { get; set; }
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||
|
||||
public class LedEntity
|
||||
{
|
||||
public string LedName { get; set; } = string.Empty;
|
||||
public string DeviceIdentifier { get; set; } = string.Empty;
|
||||
|
||||
public int? PhysicalLayout { get; set; }
|
||||
|
||||
#region LedEntityEqualityComparer
|
||||
|
||||
private sealed class LedEntityEqualityComparer : IEqualityComparer<LedEntity>
|
||||
{
|
||||
public bool Equals(LedEntity? x, LedEntity? y)
|
||||
{
|
||||
if (ReferenceEquals(x, y))
|
||||
return true;
|
||||
if (ReferenceEquals(x, null))
|
||||
return false;
|
||||
if (ReferenceEquals(y, null))
|
||||
return false;
|
||||
if (x.GetType() != y.GetType())
|
||||
return false;
|
||||
return x.LedName == y.LedName && x.DeviceIdentifier == y.DeviceIdentifier && x.PhysicalLayout == y.PhysicalLayout;
|
||||
}
|
||||
|
||||
public int GetHashCode(LedEntity obj)
|
||||
{
|
||||
return HashCode.Combine(obj.LedName, obj.DeviceIdentifier, obj.PhysicalLayout);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEqualityComparer<LedEntity> LedEntityComparer { get; } = new LedEntityEqualityComparer();
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes;
|
||||
|
||||
public class NodeConnectionEntity
|
||||
{
|
||||
public NodeConnectionEntity()
|
||||
{
|
||||
}
|
||||
|
||||
public NodeConnectionEntity(NodeConnectionEntity nodeConnectionEntity)
|
||||
{
|
||||
SourceType = nodeConnectionEntity.SourceType;
|
||||
SourceNode = nodeConnectionEntity.SourceNode;
|
||||
TargetNode = nodeConnectionEntity.TargetNode;
|
||||
SourcePinCollectionId = nodeConnectionEntity.SourcePinCollectionId;
|
||||
SourcePinId = nodeConnectionEntity.SourcePinId;
|
||||
TargetType = nodeConnectionEntity.TargetType;
|
||||
TargetPinCollectionId = nodeConnectionEntity.TargetPinCollectionId;
|
||||
TargetPinId = nodeConnectionEntity.TargetPinId;
|
||||
}
|
||||
|
||||
public string SourceType { get; set; } = string.Empty;
|
||||
public Guid SourceNode { get; set; }
|
||||
public Guid TargetNode { get; set; }
|
||||
public int SourcePinCollectionId { get; set; }
|
||||
public int SourcePinId { get; set; }
|
||||
public string TargetType { get; set; } = string.Empty;
|
||||
public int TargetPinCollectionId { get; set; }
|
||||
public int TargetPinId { get; set; }
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes;
|
||||
|
||||
public class NodeEntity
|
||||
{
|
||||
public NodeEntity()
|
||||
{
|
||||
PinCollections = new List<NodePinCollectionEntity>();
|
||||
}
|
||||
|
||||
public NodeEntity(NodeEntity nodeEntity)
|
||||
{
|
||||
Id = nodeEntity.Id;
|
||||
Type = nodeEntity.Type;
|
||||
ProviderId = nodeEntity.ProviderId;
|
||||
|
||||
Name = nodeEntity.Name;
|
||||
Description = nodeEntity.Description;
|
||||
IsExitNode = nodeEntity.IsExitNode;
|
||||
X = nodeEntity.X;
|
||||
Y = nodeEntity.Y;
|
||||
Storage = nodeEntity.Storage;
|
||||
|
||||
PinCollections = nodeEntity.PinCollections.Select(p => new NodePinCollectionEntity(p)).ToList();
|
||||
}
|
||||
|
||||
public Guid Id { get; set; }
|
||||
public string Type { get; set; } = string.Empty;
|
||||
public string ProviderId { get; set; } = string.Empty;
|
||||
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Description { get; set; } = string.Empty;
|
||||
public bool IsExitNode { get; set; }
|
||||
public double X { get; set; }
|
||||
public double Y { get; set; }
|
||||
public string Storage { get; set; } = string.Empty;
|
||||
|
||||
public List<NodePinCollectionEntity> PinCollections { get; set; }
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes;
|
||||
|
||||
public class NodePinCollectionEntity
|
||||
{
|
||||
public NodePinCollectionEntity()
|
||||
{
|
||||
}
|
||||
|
||||
public NodePinCollectionEntity(NodePinCollectionEntity nodePinCollectionEntity)
|
||||
{
|
||||
Id = nodePinCollectionEntity.Id;
|
||||
Direction = nodePinCollectionEntity.Direction;
|
||||
Amount = nodePinCollectionEntity.Amount;
|
||||
}
|
||||
|
||||
public int Id { get; set; }
|
||||
public int Direction { set; get; }
|
||||
public int Amount { get; set; }
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes;
|
||||
|
||||
public class NodeScriptEntity
|
||||
{
|
||||
public NodeScriptEntity()
|
||||
{
|
||||
Nodes = new List<NodeEntity>();
|
||||
Connections = new List<NodeConnectionEntity>();
|
||||
}
|
||||
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
public List<NodeEntity> Nodes { get; set; }
|
||||
public List<NodeConnectionEntity> Connections { get; set; }
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
using Artemis.Core;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using LiteDB;
|
||||
using Serilog;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||
|
||||
public class ProfileCategoryEntity
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public bool IsCollapsed { get; set; }
|
||||
public bool IsSuspended { get; set; }
|
||||
public int Order { get; set; }
|
||||
|
||||
public List<ProfileConfigurationEntity> ProfileConfigurations { get; set; } = new();
|
||||
|
||||
public Storage.Entities.Profile.ProfileCategoryEntity Migrate(ILogger logger, List<ProfileEntity> legacyProfiles, ILiteStorage<Guid> profileIcons)
|
||||
{
|
||||
Storage.Entities.Profile.ProfileCategoryEntity category = new()
|
||||
{
|
||||
Id = Id,
|
||||
Name = Name,
|
||||
IsCollapsed = IsCollapsed,
|
||||
IsSuspended = IsSuspended,
|
||||
Order = Order
|
||||
};
|
||||
|
||||
foreach (ProfileConfigurationEntity legacyProfileConfiguration in ProfileConfigurations)
|
||||
{
|
||||
// Find the profile
|
||||
ProfileEntity? legacyProfile = legacyProfiles.FirstOrDefault(p => p.Id == legacyProfileConfiguration.ProfileId);
|
||||
if (legacyProfile == null)
|
||||
{
|
||||
logger.Information("Profile not found for profile configuration {ProfileId}", legacyProfileConfiguration.ProfileId);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Clone to the new format via JSON, as both are serializable
|
||||
string profileJson = CoreJson.Serialize(legacyProfile);
|
||||
string configJson = CoreJson.Serialize(legacyProfileConfiguration);
|
||||
Storage.Entities.Profile.ProfileEntity? profile = CoreJson.Deserialize<Storage.Entities.Profile.ProfileEntity>(profileJson);
|
||||
Storage.Entities.Profile.ProfileConfigurationEntity? config = CoreJson.Deserialize<Storage.Entities.Profile.ProfileConfigurationEntity>(configJson);
|
||||
|
||||
if (profile == null)
|
||||
{
|
||||
logger.Information("Failed to deserialize profile JSON for profile configuration {ProfileId}", legacyProfileConfiguration.ProfileId);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (config == null)
|
||||
{
|
||||
logger.Information("Failed to deserialize profile configuration JSON for profile configuration {ProfileId}", legacyProfileConfiguration.ProfileId);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add a container
|
||||
ProfileContainerEntity container = new()
|
||||
{
|
||||
Profile = profile,
|
||||
ProfileConfiguration = config,
|
||||
};
|
||||
|
||||
// If available, download the profile icon
|
||||
if (profileIcons.Exists(legacyProfileConfiguration.FileIconId))
|
||||
{
|
||||
using MemoryStream memoryStream = new();
|
||||
profileIcons.Download(legacyProfileConfiguration.FileIconId, memoryStream);
|
||||
container.Icon = memoryStream.ToArray();
|
||||
}
|
||||
|
||||
category.ProfileConfigurations.Add(container);
|
||||
}
|
||||
|
||||
return category;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||
|
||||
public class ProfileConfigurationEntity
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string? MaterialIcon { get; set; }
|
||||
public Guid FileIconId { get; set; }
|
||||
public int IconType { get; set; }
|
||||
public bool IconFill { get; set; }
|
||||
public int Order { get; set; }
|
||||
|
||||
public bool IsSuspended { get; set; }
|
||||
public int ActivationBehaviour { get; set; }
|
||||
public NodeScriptEntity? ActivationCondition { get; set; }
|
||||
|
||||
public int HotkeyMode { get; set; }
|
||||
public ProfileConfigurationHotkeyEntity? EnableHotkey { get; set; }
|
||||
public ProfileConfigurationHotkeyEntity? DisableHotkey { get; set; }
|
||||
|
||||
public string? ModuleId { get; set; }
|
||||
|
||||
public Guid ProfileCategoryId { get; set; }
|
||||
public Guid ProfileId { get; set; }
|
||||
|
||||
public bool FadeInAndOut { get; set; }
|
||||
public int Version { get; set; }
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||
|
||||
public class ProfileConfigurationHotkeyEntity
|
||||
{
|
||||
public int? Key { get; set; }
|
||||
public int? Modifiers { get; set; }
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.General;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||
|
||||
public class ProfileEntity
|
||||
{
|
||||
public ProfileEntity()
|
||||
{
|
||||
Folders = new List<FolderEntity>();
|
||||
Layers = new List<LayerEntity>();
|
||||
ScriptConfigurations = new List<ScriptConfigurationEntity>();
|
||||
}
|
||||
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public bool IsFreshImport { get; set; }
|
||||
|
||||
public List<FolderEntity> Folders { get; set; }
|
||||
public List<LayerEntity> Layers { get; set; }
|
||||
public List<ScriptConfigurationEntity> ScriptConfigurations { get; set; }
|
||||
|
||||
public void UpdateGuid(Guid guid)
|
||||
{
|
||||
Guid oldGuid = Id;
|
||||
Id = guid;
|
||||
|
||||
FolderEntity? rootFolder = Folders.FirstOrDefault(f => f.ParentId == oldGuid);
|
||||
if (rootFolder != null)
|
||||
rootFolder.ParentId = Id;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.Profile.DataBindings;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||
|
||||
public class PropertyEntity
|
||||
{
|
||||
public string Identifier { get; set; } = string.Empty;
|
||||
public string Value { get; set; } = string.Empty;
|
||||
public bool KeyframesEnabled { get; set; }
|
||||
|
||||
public DataBindingEntity? DataBinding { get; set; }
|
||||
public List<KeyframeEntity> KeyframeEntities { get; set; } = new();
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||
|
||||
public class PropertyGroupEntity
|
||||
{
|
||||
public string Identifier { get; set; } = string.Empty;
|
||||
public List<PropertyEntity> Properties { get; set; } = new();
|
||||
public List<PropertyGroupEntity> PropertyGroups { get; set; } = new();
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||
|
||||
public class TimelineEntity
|
||||
{
|
||||
public TimeSpan StartSegmentLength { get; set; }
|
||||
public TimeSpan MainSegmentLength { get; set; }
|
||||
public TimeSpan EndSegmentLength { get; set; }
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Surface;
|
||||
|
||||
public class DeviceEntity
|
||||
{
|
||||
public DeviceEntity()
|
||||
{
|
||||
InputIdentifiers = new List<DeviceInputIdentifierEntity>();
|
||||
InputMappings = new List<InputMappingEntity>();
|
||||
Categories = new List<int>();
|
||||
}
|
||||
|
||||
public string Id { get; set; } = string.Empty;
|
||||
public string DeviceProvider { get; set; } = string.Empty;
|
||||
public float X { get; set; }
|
||||
public float Y { get; set; }
|
||||
public float Rotation { get; set; }
|
||||
public float Scale { get; set; }
|
||||
public int ZIndex { get; set; }
|
||||
public float RedScale { get; set; }
|
||||
public float GreenScale { get; set; }
|
||||
public float BlueScale { get; set; }
|
||||
public bool IsEnabled { get; set; }
|
||||
|
||||
public int PhysicalLayout { get; set; }
|
||||
public string? LogicalLayout { get; set; }
|
||||
public string? LayoutType { get; set; }
|
||||
public string? LayoutParameter { get; set; }
|
||||
|
||||
public List<DeviceInputIdentifierEntity> InputIdentifiers { get; set; }
|
||||
public List<InputMappingEntity> InputMappings { get; set; }
|
||||
public List<int> Categories { get; set; }
|
||||
|
||||
public Storage.Entities.Surface.DeviceEntity Migrate()
|
||||
{
|
||||
// All properties match, return a copy
|
||||
return new Storage.Entities.Surface.DeviceEntity()
|
||||
{
|
||||
Id = Id,
|
||||
DeviceProvider = DeviceProvider,
|
||||
X = X,
|
||||
Y = Y,
|
||||
Rotation = Rotation,
|
||||
Scale = Scale,
|
||||
ZIndex = ZIndex,
|
||||
RedScale = RedScale,
|
||||
GreenScale = GreenScale,
|
||||
BlueScale = BlueScale,
|
||||
IsEnabled = IsEnabled,
|
||||
PhysicalLayout = PhysicalLayout,
|
||||
LogicalLayout = LogicalLayout,
|
||||
LayoutType = LayoutType,
|
||||
LayoutParameter = LayoutParameter,
|
||||
InputIdentifiers = InputIdentifiers.Select(i => new Storage.Entities.Surface.DeviceInputIdentifierEntity
|
||||
{
|
||||
InputProvider = i.InputProvider,
|
||||
Identifier = i.Identifier.ToString() ?? string.Empty
|
||||
}).ToList(),
|
||||
InputMappings = InputMappings.Select(i => new Storage.Entities.Surface.InputMappingEntity
|
||||
{
|
||||
OriginalLedId = i.OriginalLedId,
|
||||
MappedLedId = i.MappedLedId
|
||||
}).ToList(),
|
||||
Categories = Categories
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class InputMappingEntity
|
||||
{
|
||||
public int OriginalLedId { get; set; }
|
||||
public int MappedLedId { get; set; }
|
||||
}
|
||||
|
||||
public class DeviceInputIdentifierEntity
|
||||
{
|
||||
public string InputProvider { get; set; } = string.Empty;
|
||||
public object Identifier { get; set; } = string.Empty;
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
namespace Artemis.Storage.Migrator.Legacy.Entities.Workshop;
|
||||
|
||||
public class EntryEntity
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public long EntryId { get; set; }
|
||||
public int EntryType { get; set; }
|
||||
|
||||
public string Author { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
public long ReleaseId { get; set; }
|
||||
public string ReleaseVersion { get; set; } = string.Empty;
|
||||
public DateTimeOffset InstalledAt { get; set; }
|
||||
|
||||
public Dictionary<string, object>? Metadata { get; set; }
|
||||
|
||||
public Storage.Entities.Workshop.EntryEntity Migrate()
|
||||
{
|
||||
// Create a copy
|
||||
return new Storage.Entities.Workshop.EntryEntity()
|
||||
{
|
||||
Id = Id,
|
||||
EntryId = EntryId,
|
||||
EntryType = EntryType,
|
||||
Author = Author,
|
||||
Name = Name,
|
||||
ReleaseId = ReleaseId,
|
||||
ReleaseVersion = ReleaseVersion,
|
||||
InstalledAt = InstalledAt,
|
||||
Metadata = Metadata ?? new Dictionary<string, object>()
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Migrations;
|
||||
|
||||
public interface IProfileMigration
|
||||
{
|
||||
int Version { get; }
|
||||
void Migrate(JsonObject configurationJson, JsonObject profileJson);
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
using LiteDB;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Migrations;
|
||||
|
||||
public interface IStorageMigration
|
||||
{
|
||||
int UserVersion { get; }
|
||||
void Apply(LiteRepository repository);
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
using LiteDB;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage;
|
||||
|
||||
public class M0020AvaloniaReset : IStorageMigration
|
||||
{
|
||||
public int UserVersion => 20;
|
||||
|
||||
public void Apply(LiteRepository repository)
|
||||
{
|
||||
repository.Database.Commit();
|
||||
|
||||
List<string> collectionNames = repository.Database.GetCollectionNames().ToList();
|
||||
foreach (string collectionName in collectionNames)
|
||||
repository.Database.DropCollection(collectionName);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes;
|
||||
using LiteDB;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage;
|
||||
|
||||
public class M0021GradientNodes : IStorageMigration
|
||||
{
|
||||
private void MigrateDataBinding(PropertyEntity property)
|
||||
{
|
||||
NodeScriptEntity? script = property.DataBinding?.NodeScript;
|
||||
NodeEntity? exitNode = script?.Nodes.FirstOrDefault(s => s.IsExitNode);
|
||||
if (script == null || exitNode == null)
|
||||
return;
|
||||
|
||||
// Create a new node at the same position of the exit node
|
||||
NodeEntity gradientNode = new()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Type = "ColorGradientNode",
|
||||
ProviderId = "Artemis.Plugins.Nodes.General.GeneralNodesProvider-d9e1ee78",
|
||||
Name = "Color Gradient",
|
||||
Description = "Outputs a color gradient with the given colors",
|
||||
X = exitNode.X,
|
||||
Y = exitNode.Y,
|
||||
Storage = property.Value // Copy the value of the property into the node storage
|
||||
};
|
||||
script.Nodes.Add(gradientNode);
|
||||
|
||||
// Move all connections of the exit node to the new node
|
||||
foreach (NodeConnectionEntity connection in script.Connections)
|
||||
{
|
||||
if (connection.SourceNode == exitNode.Id)
|
||||
{
|
||||
connection.SourceNode = gradientNode.Id;
|
||||
connection.SourcePinId++;
|
||||
}
|
||||
}
|
||||
|
||||
// Connect the data binding node to the source node
|
||||
script.Connections.Add(new NodeConnectionEntity
|
||||
{
|
||||
SourceType = "ColorGradient",
|
||||
SourceNode = exitNode.Id,
|
||||
SourcePinCollectionId = -1,
|
||||
SourcePinId = 0,
|
||||
TargetType = "ColorGradient",
|
||||
TargetNode = gradientNode.Id,
|
||||
TargetPinCollectionId = -1,
|
||||
TargetPinId = 0
|
||||
});
|
||||
|
||||
// Move the exit node to the right
|
||||
exitNode.X += 300;
|
||||
exitNode.Y += 30;
|
||||
}
|
||||
|
||||
private void MigrateDataBinding(PropertyGroupEntity? propertyGroup)
|
||||
{
|
||||
if (propertyGroup == null)
|
||||
return;
|
||||
|
||||
foreach (PropertyGroupEntity propertyGroupPropertyGroup in propertyGroup.PropertyGroups)
|
||||
MigrateDataBinding(propertyGroupPropertyGroup);
|
||||
|
||||
foreach (PropertyEntity property in propertyGroup.Properties)
|
||||
{
|
||||
if (property.Value.StartsWith("[{\"Color\":\"") && property.DataBinding?.NodeScript != null && property.DataBinding.IsEnabled)
|
||||
MigrateDataBinding(property);
|
||||
}
|
||||
}
|
||||
|
||||
public int UserVersion => 21;
|
||||
|
||||
public void Apply(LiteRepository repository)
|
||||
{
|
||||
// Find all color gradient data bindings, there's no really good way to do this so infer it from the value
|
||||
List<ProfileEntity> profiles = repository.Query<ProfileEntity>().ToList();
|
||||
foreach (ProfileEntity profileEntity in profiles)
|
||||
{
|
||||
foreach (LayerEntity layer in profileEntity.Layers.Where(le => le.LayerBrush != null))
|
||||
MigrateDataBinding(layer.LayerBrush?.PropertyGroup);
|
||||
|
||||
repository.Update(profileEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.Profile.Conditions;
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes;
|
||||
using LiteDB;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage;
|
||||
|
||||
public class M0022TransitionNodes : IStorageMigration
|
||||
{
|
||||
private void MigrateNodeScript(NodeScriptEntity? nodeScript)
|
||||
{
|
||||
if (nodeScript == null)
|
||||
return;
|
||||
|
||||
foreach (NodeEntity node in nodeScript.Nodes)
|
||||
{
|
||||
if (node.Type == "NumericEasingNode")
|
||||
node.Type = "NumericTransitionNode";
|
||||
else if (node.Type == "ColorGradientEasingNode")
|
||||
node.Type = "ColorGradientTransitionNode";
|
||||
else if (node.Type == "SKColorEasingNode")
|
||||
node.Type = "SKColorTransitionNode";
|
||||
else if (node.Type == "EasingTypeNode")
|
||||
node.Type = "EasingFunctionNode";
|
||||
}
|
||||
}
|
||||
|
||||
private void MigratePropertyGroup(PropertyGroupEntity? propertyGroup)
|
||||
{
|
||||
if (propertyGroup == null)
|
||||
return;
|
||||
|
||||
foreach (PropertyGroupEntity childPropertyGroup in propertyGroup.PropertyGroups)
|
||||
MigratePropertyGroup(childPropertyGroup);
|
||||
foreach (PropertyEntity property in propertyGroup.Properties)
|
||||
MigrateNodeScript(property.DataBinding?.NodeScript);
|
||||
}
|
||||
|
||||
private void MigrateDisplayCondition(IConditionEntity? conditionEntity)
|
||||
{
|
||||
if (conditionEntity is EventConditionEntity eventConditionEntity)
|
||||
MigrateNodeScript(eventConditionEntity.Script);
|
||||
else if (conditionEntity is StaticConditionEntity staticConditionEntity)
|
||||
MigrateNodeScript(staticConditionEntity.Script);
|
||||
}
|
||||
|
||||
public int UserVersion => 22;
|
||||
|
||||
public void Apply(LiteRepository repository)
|
||||
{
|
||||
// Migrate profile configuration display conditions
|
||||
List<ProfileCategoryEntity> categories = repository.Query<ProfileCategoryEntity>().ToList();
|
||||
foreach (ProfileCategoryEntity profileCategoryEntity in categories)
|
||||
{
|
||||
foreach (ProfileConfigurationEntity profileConfigurationEntity in profileCategoryEntity.ProfileConfigurations)
|
||||
MigrateNodeScript(profileConfigurationEntity.ActivationCondition);
|
||||
repository.Update(profileCategoryEntity);
|
||||
}
|
||||
|
||||
// Migrate profile display conditions and data bindings
|
||||
List<ProfileEntity> profiles = repository.Query<ProfileEntity>().ToList();
|
||||
foreach (ProfileEntity profileEntity in profiles)
|
||||
{
|
||||
foreach (LayerEntity layer in profileEntity.Layers)
|
||||
{
|
||||
MigratePropertyGroup(layer.LayerBrush?.PropertyGroup);
|
||||
MigratePropertyGroup(layer.GeneralPropertyGroup);
|
||||
MigratePropertyGroup(layer.TransformPropertyGroup);
|
||||
foreach (LayerEffectEntity layerEffectEntity in layer.LayerEffects)
|
||||
MigratePropertyGroup(layerEffectEntity.PropertyGroup);
|
||||
MigrateDisplayCondition(layer.DisplayCondition);
|
||||
}
|
||||
|
||||
foreach (FolderEntity folder in profileEntity.Folders)
|
||||
{
|
||||
foreach (LayerEffectEntity folderLayerEffect in folder.LayerEffects)
|
||||
MigratePropertyGroup(folderLayerEffect.PropertyGroup);
|
||||
MigrateDisplayCondition(folder.DisplayCondition);
|
||||
}
|
||||
|
||||
repository.Update(profileEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
using LiteDB;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage;
|
||||
|
||||
public class M0023LayoutProviders : IStorageMigration
|
||||
{
|
||||
public int UserVersion => 23;
|
||||
|
||||
public void Apply(LiteRepository repository)
|
||||
{
|
||||
ILiteCollection<BsonDocument> deviceEntities = repository.Database.GetCollection("DeviceEntity");
|
||||
List<BsonDocument> toUpdate = new();
|
||||
|
||||
foreach (BsonDocument bsonDocument in deviceEntities.FindAll())
|
||||
{
|
||||
if (bsonDocument.TryGetValue("CustomLayoutPath", out BsonValue customLayoutPath) && customLayoutPath.IsString && !string.IsNullOrEmpty(customLayoutPath.AsString))
|
||||
{
|
||||
bsonDocument.Add("LayoutType", new BsonValue("CustomPath"));
|
||||
bsonDocument.Add("LayoutParameter", new BsonValue(customLayoutPath.AsString));
|
||||
}
|
||||
else if (bsonDocument.TryGetValue("DisableDefaultLayout", out BsonValue disableDefaultLayout) && disableDefaultLayout.AsBoolean)
|
||||
bsonDocument.Add("LayoutType", new BsonValue("None"));
|
||||
else
|
||||
bsonDocument.Add("LayoutType", new BsonValue("Default"));
|
||||
|
||||
bsonDocument.Remove("CustomLayoutPath");
|
||||
bsonDocument.Remove("DisableDefaultLayout");
|
||||
toUpdate.Add(bsonDocument);
|
||||
}
|
||||
|
||||
deviceEntities.Update(toUpdate);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,105 @@
|
||||
using LiteDB;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage;
|
||||
|
||||
public class M0024NodeProviders : IStorageMigration
|
||||
{
|
||||
public int UserVersion => 24;
|
||||
|
||||
public void Apply(LiteRepository repository)
|
||||
{
|
||||
ILiteCollection<BsonDocument> categoryCollection = repository.Database.GetCollection("ProfileCategoryEntity");
|
||||
List<BsonDocument> categoriesToUpdate = new();
|
||||
foreach (BsonDocument profileCategoryBson in categoryCollection.FindAll())
|
||||
{
|
||||
BsonArray? profiles = profileCategoryBson["ProfileConfigurations"]?.AsArray;
|
||||
if (profiles != null)
|
||||
{
|
||||
foreach (BsonValue profile in profiles)
|
||||
profile["Version"] = 1;
|
||||
categoriesToUpdate.Add(profileCategoryBson);
|
||||
}
|
||||
}
|
||||
categoryCollection.Update(categoriesToUpdate);
|
||||
|
||||
ILiteCollection<BsonDocument> collection = repository.Database.GetCollection("ProfileEntity");
|
||||
List<BsonDocument> profilesToUpdate = new();
|
||||
foreach (BsonDocument profileBson in collection.FindAll())
|
||||
{
|
||||
BsonArray? folders = profileBson["Folders"]?.AsArray;
|
||||
BsonArray? layers = profileBson["Layers"]?.AsArray;
|
||||
|
||||
if (folders != null)
|
||||
{
|
||||
foreach (BsonValue folder in folders)
|
||||
MigrateProfileElement(folder.AsDocument);
|
||||
}
|
||||
|
||||
if (layers != null)
|
||||
{
|
||||
foreach (BsonValue layer in layers)
|
||||
{
|
||||
MigrateProfileElement(layer.AsDocument);
|
||||
MigratePropertyGroup(layer.AsDocument["GeneralPropertyGroup"].AsDocument);
|
||||
MigratePropertyGroup(layer.AsDocument["TransformPropertyGroup"].AsDocument);
|
||||
MigratePropertyGroup(layer.AsDocument["LayerBrush"]?["PropertyGroup"].AsDocument);
|
||||
}
|
||||
}
|
||||
|
||||
profilesToUpdate.Add(profileBson);
|
||||
}
|
||||
|
||||
collection.Update(profilesToUpdate);
|
||||
}
|
||||
|
||||
private void MigrateProfileElement(BsonDocument profileElement)
|
||||
{
|
||||
BsonArray? layerEffects = profileElement["LayerEffects"]?.AsArray;
|
||||
if (layerEffects != null)
|
||||
{
|
||||
foreach (BsonValue layerEffect in layerEffects)
|
||||
MigratePropertyGroup(layerEffect.AsDocument["PropertyGroup"].AsDocument);
|
||||
}
|
||||
|
||||
BsonValue? displayCondition = profileElement["DisplayCondition"];
|
||||
if (displayCondition != null)
|
||||
MigrateNodeScript(displayCondition.AsDocument["Script"].AsDocument);
|
||||
}
|
||||
|
||||
private void MigratePropertyGroup(BsonDocument? propertyGroup)
|
||||
{
|
||||
if (propertyGroup == null || propertyGroup.Keys.Count == 0)
|
||||
return;
|
||||
|
||||
BsonArray? properties = propertyGroup["Properties"]?.AsArray;
|
||||
BsonArray? propertyGroups = propertyGroup["PropertyGroups"]?.AsArray;
|
||||
|
||||
if (properties != null)
|
||||
{
|
||||
foreach (BsonValue property in properties)
|
||||
MigrateNodeScript(property.AsDocument["DataBinding"]?["NodeScript"]?.AsDocument);
|
||||
}
|
||||
|
||||
if (propertyGroups != null)
|
||||
{
|
||||
foreach (BsonValue childPropertyGroup in propertyGroups)
|
||||
MigratePropertyGroup(childPropertyGroup.AsDocument);
|
||||
}
|
||||
}
|
||||
|
||||
private void MigrateNodeScript(BsonDocument? nodeScript)
|
||||
{
|
||||
if (nodeScript == null || nodeScript.Keys.Count == 0)
|
||||
return;
|
||||
|
||||
BsonArray? nodes = nodeScript["Nodes"]?.AsArray;
|
||||
if (nodes == null)
|
||||
return;
|
||||
|
||||
foreach (BsonValue node in nodes)
|
||||
{
|
||||
node.AsDocument["Type"] = node.AsDocument["Type"]?.AsString?.Replace("Artemis.VisualScripting.Nodes", "Artemis.Plugins.Nodes.General.Nodes");
|
||||
node.AsDocument["ProviderId"] = "Artemis.Plugins.Nodes.General.GeneralNodesProvider-d9e1ee78";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
using LiteDB;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage;
|
||||
|
||||
public class M0025NodeProvidersProfileConfig : IStorageMigration
|
||||
{
|
||||
public int UserVersion => 25;
|
||||
|
||||
public void Apply(LiteRepository repository)
|
||||
{
|
||||
ILiteCollection<BsonDocument> categoryCollection = repository.Database.GetCollection("ProfileCategoryEntity");
|
||||
List<BsonDocument> toUpdate = new();
|
||||
foreach (BsonDocument profileCategoryBson in categoryCollection.FindAll())
|
||||
{
|
||||
BsonArray? profiles = profileCategoryBson["ProfileConfigurations"]?.AsArray;
|
||||
if (profiles != null)
|
||||
{
|
||||
foreach (BsonValue profile in profiles)
|
||||
{
|
||||
profile["Version"] = 2;
|
||||
MigrateNodeScript(profile["ActivationCondition"]?.AsDocument);
|
||||
}
|
||||
toUpdate.Add(profileCategoryBson);
|
||||
}
|
||||
}
|
||||
|
||||
categoryCollection.Update(toUpdate);
|
||||
}
|
||||
|
||||
private void MigrateNodeScript(BsonDocument? nodeScript)
|
||||
{
|
||||
if (nodeScript == null || nodeScript.Keys.Count == 0)
|
||||
return;
|
||||
|
||||
BsonArray? nodes = nodeScript["Nodes"]?.AsArray;
|
||||
if (nodes == null)
|
||||
return;
|
||||
|
||||
foreach (BsonValue node in nodes)
|
||||
{
|
||||
node.AsDocument["Type"] = node.AsDocument["Type"]?.AsString?.Replace("Artemis.VisualScripting.Nodes", "Artemis.Plugins.Nodes.General.Nodes");
|
||||
node.AsDocument["ProviderId"] = "Artemis.Plugins.Nodes.General.GeneralNodesProvider-d9e1ee78";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,227 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using LiteDB;
|
||||
using Serilog;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage;
|
||||
|
||||
public class M0026NodeStorage : IStorageMigration
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public M0026NodeStorage(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public int UserVersion => 26;
|
||||
|
||||
public void Apply(LiteRepository repository)
|
||||
{
|
||||
ILiteCollection<BsonDocument> categoryCollection = repository.Database.GetCollection("ProfileCategoryEntity");
|
||||
List<BsonDocument> toUpdate = new();
|
||||
foreach (BsonDocument profileCategoryBson in categoryCollection.FindAll())
|
||||
{
|
||||
BsonArray? profiles = profileCategoryBson["ProfileConfigurations"]?.AsArray;
|
||||
if (profiles != null)
|
||||
{
|
||||
foreach (BsonValue profile in profiles)
|
||||
{
|
||||
profile["Version"] = 4;
|
||||
MigrateNodeScript(profile["ActivationCondition"]?.AsDocument);
|
||||
}
|
||||
|
||||
toUpdate.Add(profileCategoryBson);
|
||||
}
|
||||
}
|
||||
|
||||
categoryCollection.Update(toUpdate);
|
||||
|
||||
ILiteCollection<BsonDocument> collection = repository.Database.GetCollection("ProfileEntity");
|
||||
List<BsonDocument> profilesToUpdate = new();
|
||||
foreach (BsonDocument profileBson in collection.FindAll())
|
||||
{
|
||||
BsonArray? folders = profileBson["Folders"]?.AsArray;
|
||||
BsonArray? layers = profileBson["Layers"]?.AsArray;
|
||||
|
||||
if (folders != null)
|
||||
{
|
||||
foreach (BsonValue folder in folders)
|
||||
MigrateProfileElement(folder.AsDocument);
|
||||
}
|
||||
|
||||
if (layers != null)
|
||||
{
|
||||
foreach (BsonValue layer in layers)
|
||||
{
|
||||
MigrateProfileElement(layer.AsDocument);
|
||||
MigratePropertyGroup(layer.AsDocument["GeneralPropertyGroup"].AsDocument);
|
||||
MigratePropertyGroup(layer.AsDocument["TransformPropertyGroup"].AsDocument);
|
||||
MigratePropertyGroup(layer.AsDocument["LayerBrush"]?["PropertyGroup"].AsDocument);
|
||||
}
|
||||
}
|
||||
|
||||
profilesToUpdate.Add(profileBson);
|
||||
}
|
||||
|
||||
collection.Update(profilesToUpdate);
|
||||
}
|
||||
|
||||
private void MigrateProfileElement(BsonDocument profileElement)
|
||||
{
|
||||
BsonArray? layerEffects = profileElement["LayerEffects"]?.AsArray;
|
||||
if (layerEffects != null)
|
||||
{
|
||||
foreach (BsonValue layerEffect in layerEffects)
|
||||
MigratePropertyGroup(layerEffect.AsDocument["PropertyGroup"].AsDocument);
|
||||
}
|
||||
|
||||
BsonValue? displayCondition = profileElement["DisplayCondition"];
|
||||
if (displayCondition != null)
|
||||
MigrateNodeScript(displayCondition.AsDocument["Script"].AsDocument);
|
||||
}
|
||||
|
||||
private void MigratePropertyGroup(BsonDocument? propertyGroup)
|
||||
{
|
||||
if (propertyGroup == null || propertyGroup.Keys.Count == 0)
|
||||
return;
|
||||
|
||||
BsonArray? properties = propertyGroup["Properties"]?.AsArray;
|
||||
BsonArray? propertyGroups = propertyGroup["PropertyGroups"]?.AsArray;
|
||||
|
||||
if (properties != null)
|
||||
{
|
||||
foreach (BsonValue property in properties)
|
||||
MigrateNodeScript(property.AsDocument["DataBinding"]?["NodeScript"]?.AsDocument);
|
||||
}
|
||||
|
||||
if (propertyGroups != null)
|
||||
{
|
||||
foreach (BsonValue childPropertyGroup in propertyGroups)
|
||||
MigratePropertyGroup(childPropertyGroup.AsDocument);
|
||||
}
|
||||
}
|
||||
|
||||
private void MigrateNodeScript(BsonDocument? nodeScript)
|
||||
{
|
||||
if (nodeScript == null || nodeScript.Keys.Count == 0)
|
||||
return;
|
||||
|
||||
BsonArray? nodes = nodeScript["Nodes"]?.AsArray;
|
||||
if (nodes == null)
|
||||
return;
|
||||
|
||||
foreach (BsonValue node in nodes)
|
||||
{
|
||||
// Migrate the storage of the node
|
||||
node["Storage"] = MigrateNodeStorageJson(node.AsDocument["Storage"]?.AsString, _logger);
|
||||
}
|
||||
}
|
||||
|
||||
private static string? MigrateNodeStorageJson(string? json, ILogger logger)
|
||||
{
|
||||
if (string.IsNullOrEmpty(json))
|
||||
return json;
|
||||
|
||||
try
|
||||
{
|
||||
JsonDocument jsonDocument = JsonDocument.Parse(json);
|
||||
if (jsonDocument.RootElement.ValueKind != JsonValueKind.Object)
|
||||
return json;
|
||||
|
||||
JsonObject? jsonObject = JsonObject.Create(jsonDocument.RootElement);
|
||||
if (jsonObject == null)
|
||||
return json;
|
||||
|
||||
if (jsonObject["$type"] != null && jsonObject["$values"] != null)
|
||||
{
|
||||
JsonArray? values = jsonObject["$values"]?.AsArray();
|
||||
if (values != null)
|
||||
{
|
||||
foreach (JsonNode? jsonNode in values.ToList())
|
||||
{
|
||||
if (jsonNode is JsonObject childObject)
|
||||
ConvertToSystemTextJson(childObject);
|
||||
}
|
||||
|
||||
return values.ToJsonString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ConvertToSystemTextJson(jsonObject);
|
||||
}
|
||||
|
||||
return jsonObject.ToJsonString();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error(e, "Failed to migrate node storage JSON");
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ConvertToSystemTextJson(JsonObject jsonObject)
|
||||
{
|
||||
FilterType(jsonObject);
|
||||
|
||||
// Recursively convert all JSON arrays from {$type: "xyz", $values: []} to []
|
||||
foreach ((string? key, JsonNode? value) in jsonObject.ToDictionary())
|
||||
{
|
||||
if (value is not JsonObject obj)
|
||||
continue;
|
||||
|
||||
// if there is a $type and a $values, replace the entire node with $values regardless of the value of $type
|
||||
if (obj["$type"] != null && obj["$values"] != null)
|
||||
{
|
||||
JsonArray? values = obj["$values"]?.AsArray();
|
||||
if (values != null)
|
||||
{
|
||||
obj.Remove("$values");
|
||||
jsonObject[key] = values;
|
||||
foreach (JsonNode? jsonNode in values.ToList())
|
||||
{
|
||||
if (jsonNode is JsonObject childObject)
|
||||
ConvertToSystemTextJson(childObject);
|
||||
}
|
||||
}
|
||||
|
||||
obj.Remove("$type");
|
||||
}
|
||||
else
|
||||
{
|
||||
ConvertToSystemTextJson(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void FilterType(JsonObject jsonObject)
|
||||
{
|
||||
// Replace or remove $type depending on whether there's a matching JsonDerivedType
|
||||
// This could be done with reflection but that would mean this migration automatically gains new behaviour over time.
|
||||
JsonNode? type = jsonObject["$type"];
|
||||
if (type != null)
|
||||
{
|
||||
// Adaption Hints
|
||||
if (type.GetValue<string>() == "Artemis.Storage.Entities.Profile.AdaptionHints.CategoryAdaptionHintEntity, Artemis.Storage")
|
||||
jsonObject["$type"] = "Category";
|
||||
else if (type.GetValue<string>() == "Artemis.Storage.Entities.Profile.AdaptionHints.DeviceAdaptionHintEntity, Artemis.Storage")
|
||||
jsonObject["$type"] = "Device";
|
||||
else if (type.GetValue<string>() == "Artemis.Storage.Entities.Profile.AdaptionHints.KeyboardSectionAdaptionHintEntity, Artemis.Storage")
|
||||
jsonObject["$type"] = "KeyboardSection";
|
||||
else if (type.GetValue<string>() == "Artemis.Storage.Entities.Profile.AdaptionHints.SingleLedAdaptionHintEntity, Artemis.Storage")
|
||||
jsonObject["$type"] = "SingleLed";
|
||||
// Conditions
|
||||
else if (type.GetValue<string>() == "Artemis.Storage.Entities.Profile.Conditions.AlwaysOnConditionEntity, Artemis.Storage")
|
||||
jsonObject["$type"] = "AlwaysOn";
|
||||
else if (type.GetValue<string>() == "Artemis.Storage.Entities.Profile.Conditions.EventConditionEntity, Artemis.Storage")
|
||||
jsonObject["$type"] = "Event";
|
||||
else if (type.GetValue<string>() == "Artemis.Storage.Entities.Profile.Conditions.PlayOnceConditionEntity, Artemis.Storage")
|
||||
jsonObject["$type"] = "PlayOnce";
|
||||
else if (type.GetValue<string>() == "Artemis.Storage.Entities.Profile.Conditions.StaticConditionEntity, Artemis.Storage")
|
||||
jsonObject["$type"] = "Static";
|
||||
else
|
||||
jsonObject.Remove("$type");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
using LiteDB;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage;
|
||||
|
||||
public class M0027Namespace : IStorageMigration
|
||||
{
|
||||
public int UserVersion => 27;
|
||||
|
||||
public void Apply(LiteRepository repository)
|
||||
{
|
||||
ILiteCollection<BsonDocument> collection = repository.Database.GetCollection("ProfileEntity");
|
||||
List<BsonDocument> profilesToUpdate = new();
|
||||
|
||||
foreach (BsonDocument profileBson in collection.FindAll())
|
||||
{
|
||||
MigrateDocument(profileBson);
|
||||
profilesToUpdate.Add(profileBson);
|
||||
}
|
||||
|
||||
collection.Update(profilesToUpdate);
|
||||
}
|
||||
|
||||
private void MigrateDocument(BsonDocument document)
|
||||
{
|
||||
foreach ((string? key, BsonValue? value) in document)
|
||||
{
|
||||
if (key == "_type")
|
||||
{
|
||||
document[key] = document[key].AsString
|
||||
.Replace("Artemis.Storage.Entities.Profile", "Artemis.Storage.Migrator.Legacy.Entities.Profile")
|
||||
.Replace(", Artemis.Storage", ", Artemis.Storage.Migrator");
|
||||
}
|
||||
else if (value.IsDocument)
|
||||
MigrateDocument(value.AsDocument);
|
||||
else if (value.IsArray)
|
||||
{
|
||||
foreach (BsonValue bsonValue in value.AsArray)
|
||||
{
|
||||
if (bsonValue.IsDocument)
|
||||
MigrateDocument(bsonValue.AsDocument);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
using Artemis.Storage.Migrator.Legacy.Migrations;
|
||||
using LiteDB;
|
||||
using Serilog;
|
||||
|
||||
namespace Artemis.Storage.Migrator.Legacy;
|
||||
|
||||
public static class StorageMigrationService
|
||||
{
|
||||
public static void ApplyPendingMigrations(ILogger logger, LiteRepository repository, IList<IStorageMigration> migrations)
|
||||
{
|
||||
foreach (IStorageMigration storageMigration in migrations.OrderBy(m => m.UserVersion))
|
||||
{
|
||||
if (repository.Database.UserVersion >= storageMigration.UserVersion)
|
||||
continue;
|
||||
|
||||
logger.Information("Applying storage migration {storageMigration} to update DB from v{oldVersion} to v{newVersion}",
|
||||
storageMigration.GetType().Name, repository.Database.UserVersion, storageMigration.UserVersion);
|
||||
|
||||
repository.Database.BeginTrans();
|
||||
try
|
||||
{
|
||||
storageMigration.Apply(repository);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
repository.Database.Rollback();
|
||||
throw;
|
||||
}
|
||||
|
||||
repository.Database.Commit();
|
||||
repository.Database.UserVersion = storageMigration.UserVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,16 @@
|
||||
using Artemis.Core.DryIoc;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.DryIoc;
|
||||
using Artemis.Storage.Migrator.Legacy;
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.General;
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.Plugins;
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.Surface;
|
||||
using Artemis.Storage.Migrator.Legacy.Entities.Workshop;
|
||||
using Artemis.Storage.Migrator.Legacy.Migrations.Storage;
|
||||
using DryIoc;
|
||||
using LiteDB;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Serilog;
|
||||
|
||||
namespace Artemis.Storage.Migrator;
|
||||
|
||||
@ -8,12 +18,125 @@ class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Container container = new Container(rules => rules
|
||||
using Container container = new(rules => rules
|
||||
.WithMicrosoftDependencyInjectionRules()
|
||||
.WithConcreteTypeDynamicRegistrations()
|
||||
.WithoutThrowOnRegisteringDisposableTransient());
|
||||
|
||||
container.RegisterCore();
|
||||
container.Resolve<ArtemisDbContext>().Database.EnsureCreated();
|
||||
|
||||
ILogger logger = container.Resolve<ILogger>();
|
||||
ArtemisDbContext dbContext = container.Resolve<ArtemisDbContext>();
|
||||
logger.Information("Applying pending migrations...");
|
||||
dbContext.Database.Migrate();
|
||||
logger.Information("Pending migrations applied");
|
||||
|
||||
if (!File.Exists(Path.Combine(Constants.DataFolder, "database.db")))
|
||||
{
|
||||
logger.Information("No legacy database found, nothing to migrate");
|
||||
return;
|
||||
}
|
||||
|
||||
logger.Information("Migrating legacy database...");
|
||||
|
||||
try
|
||||
{
|
||||
MigrateLegacyDatabase(logger, dbContext);
|
||||
// After a successful migration, keep the legacy database around for a while
|
||||
File.Move(Path.Combine(Constants.DataFolder, "database.db"), Path.Combine(Constants.DataFolder, "legacy.db"));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error(e, "Failed to migrate legacy database");
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(Path.Combine(Constants.DataFolder, "temp.db"));
|
||||
}
|
||||
|
||||
logger.Information("Legacy database migrated");
|
||||
}
|
||||
|
||||
private static void MigrateLegacyDatabase(ILogger logger, ArtemisDbContext dbContext)
|
||||
{
|
||||
// Copy the database before using it, we're going to make some modifications to it and we don't want to mess up the original
|
||||
string databasePath = Path.Combine(Constants.DataFolder, "database.db");
|
||||
string tempPath = Path.Combine(Constants.DataFolder, "temp.db");
|
||||
File.Copy(databasePath, tempPath, true);
|
||||
|
||||
using LiteRepository repository = new($"FileName={tempPath}");
|
||||
|
||||
// Apply pending LiteDB migrations, this includes a migration that transforms namespaces to Artemis.Storage.Migrator
|
||||
StorageMigrationService.ApplyPendingMigrations(
|
||||
logger,
|
||||
repository,
|
||||
[
|
||||
new M0020AvaloniaReset(),
|
||||
new M0021GradientNodes(),
|
||||
new M0022TransitionNodes(),
|
||||
new M0023LayoutProviders(),
|
||||
new M0024NodeProviders(),
|
||||
new M0025NodeProvidersProfileConfig(),
|
||||
new M0026NodeStorage(logger),
|
||||
new M0027Namespace(),
|
||||
]
|
||||
);
|
||||
|
||||
// Devices
|
||||
if (!dbContext.Devices.Any())
|
||||
{
|
||||
logger.Information("Migrating devices");
|
||||
List<DeviceEntity> legacyDevices = repository.Query<DeviceEntity>().Include(s => s.InputIdentifiers).ToList();
|
||||
dbContext.Devices.AddRange(legacyDevices.Select(l => l.Migrate()));
|
||||
dbContext.SaveChanges();
|
||||
}
|
||||
|
||||
// Entries
|
||||
if (!dbContext.Entries.Any())
|
||||
{
|
||||
logger.Information("Migrating entries");
|
||||
List<EntryEntity> legacyEntries = repository.Query<EntryEntity>().ToList();
|
||||
dbContext.Entries.AddRange(legacyEntries.Select(l => l.Migrate()));
|
||||
dbContext.SaveChanges();
|
||||
}
|
||||
|
||||
// Plugins
|
||||
if (!dbContext.Plugins.Any())
|
||||
{
|
||||
logger.Information("Migrating plugins");
|
||||
List<PluginEntity> legacyPlugins = repository.Query<PluginEntity>().ToList();
|
||||
dbContext.Plugins.AddRange(legacyPlugins.Select(l => l.Migrate()));
|
||||
dbContext.SaveChanges();
|
||||
}
|
||||
|
||||
// PluginSettings
|
||||
if (!dbContext.PluginSettings.Any())
|
||||
{
|
||||
logger.Information("Migrating plugin settings");
|
||||
List<PluginSettingEntity> legacyPluginSettings = repository.Query<PluginSettingEntity>().ToList();
|
||||
dbContext.PluginSettings.AddRange(legacyPluginSettings.Select(l => l.Migrate()));
|
||||
dbContext.SaveChanges();
|
||||
}
|
||||
|
||||
// ProfileCategories
|
||||
if (!dbContext.ProfileCategories.Any())
|
||||
{
|
||||
logger.Information("Migrating profile categories");
|
||||
List<ProfileCategoryEntity> legacyProfileCategories = repository.Query<ProfileCategoryEntity>().ToList();
|
||||
ILiteStorage<Guid> profileIcons = repository.Database.GetStorage<Guid>("profileIcons");
|
||||
List<ProfileEntity> legacyProfiles = repository.Query<ProfileEntity>().ToList();
|
||||
dbContext.ProfileCategories.AddRange(legacyProfileCategories.Select(l => l.Migrate(logger, legacyProfiles, profileIcons)));
|
||||
dbContext.SaveChanges();
|
||||
}
|
||||
|
||||
// Releases
|
||||
if (!dbContext.Releases.Any())
|
||||
{
|
||||
logger.Information("Migrating releases");
|
||||
List<ReleaseEntity> legacyReleases = repository.Query<ReleaseEntity>().ToList();
|
||||
dbContext.Releases.AddRange(legacyReleases.Select(l => l.Migrate()));
|
||||
dbContext.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,6 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LiteDB" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
|
||||
<PackageReference Include="Serilog" />
|
||||
<PackageReference Include="System.Text.Json" />
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using Artemis.Storage.Entities.Profile.Nodes;
|
||||
using Serilog.Core;
|
||||
|
||||
namespace Artemis.Storage.Entities.Profile;
|
||||
|
||||
@ -8,7 +7,6 @@ public class ProfileConfigurationEntity
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string? MaterialIcon { get; set; }
|
||||
public Guid FileIconId { get; set; }
|
||||
public int IconType { get; set; }
|
||||
public bool IconFill { get; set; }
|
||||
public int Order { get; set; }
|
||||
|
||||
@ -59,20 +59,27 @@ public partial class ProfileConfigurationIcon : UserControl, IDisposable
|
||||
|
||||
private void LoadFromBitmap(Core.ProfileConfigurationIcon configurationIcon, Stream stream)
|
||||
{
|
||||
_stream = stream;
|
||||
if (!configurationIcon.Fill)
|
||||
try
|
||||
{
|
||||
Content = new Image {Source = new Bitmap(stream)};
|
||||
return;
|
||||
}
|
||||
_stream = stream;
|
||||
if (!configurationIcon.Fill)
|
||||
{
|
||||
Content = new Image {Source = new Bitmap(stream)};
|
||||
return;
|
||||
}
|
||||
|
||||
Content = new Border
|
||||
Content = new Border
|
||||
{
|
||||
Background = TextElement.GetForeground(this),
|
||||
VerticalAlignment = VerticalAlignment.Stretch,
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
OpacityMask = new ImageBrush(new Bitmap(stream))
|
||||
};
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Background = TextElement.GetForeground(this),
|
||||
VerticalAlignment = VerticalAlignment.Stretch,
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
OpacityMask = new ImageBrush(new Bitmap(stream))
|
||||
};
|
||||
Content = new MaterialIcon {Kind = MaterialIconKind.QuestionMark};
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDetachedFromLogicalTree(object? sender, LogicalTreeAttachmentEventArgs e)
|
||||
|
||||
@ -25,7 +25,6 @@
|
||||
<PackageVersion Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageVersion Include="IdentityModel" Version="6.2.0" />
|
||||
<PackageVersion Include="JetBrains.Annotations" Version="2023.3.0" />
|
||||
<PackageVersion Include="LiteDB" Version="5.0.17" />
|
||||
<PackageVersion Include="Markdown.Avalonia.Tight" Version="11.0.2" />
|
||||
<PackageVersion Include="Material.Icons.Avalonia" Version="2.1.0" />
|
||||
<PackageVersion Include="McMaster.NETCore.Plugins" Version="1.4.0" />
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user