- add lib.tools and lib.logging

master
Simon G 5 years ago
parent 930db02a93
commit 14b7901b25
  1. 17
      Lib.Logging/Exceptions/LogNotInitializedException.cs
  2. 9
      Lib.Logging/Factories/ILogFactory.cs
  3. 46
      Lib.Logging/Interfaces/ILog.cs
  4. 17
      Lib.Logging/Interfaces/ILogComponent.cs
  5. 34
      Lib.Logging/Interfaces/ILogMessage.cs
  6. 37
      Lib.Logging/Interfaces/LogLevels.cs
  7. 13
      Lib.Logging/Lib.Logging.csproj
  8. 218
      Lib.Logging/Log.cs
  9. 33
      Lib.Logging/LogComponentAttribute.cs
  10. 41
      Lib.Logging/LogMessage.cs
  11. 28
      Lib.Logging/Loggers/ConsoleLogger.cs
  12. 13
      Lib.Logging/Loggers/Factories/IConsoleLoggerFactory.cs
  13. 13
      Lib.Logging/Loggers/Factories/IFileLoggerFactory.cs
  14. 14
      Lib.Logging/Loggers/Factories/ILoggerInitializerFactory.cs
  15. 80
      Lib.Logging/Loggers/FileLogger.cs
  16. 11
      Lib.Logging/Loggers/Interfaces/IConsoleLogger.cs
  17. 11
      Lib.Logging/Loggers/Interfaces/IFileLogger.cs
  18. 22
      Lib.Logging/Loggers/Interfaces/ILogger.cs
  19. 13
      Lib.Logging/Loggers/Interfaces/ILoggerInitializer.cs
  20. 53
      Lib.Logging/Loggers/LoggerInitializer.cs
  21. 12
      Lib.Logging/Properties/AssemblyInfo.cs
  22. 29
      Lib.Tools/Enumerables.cs
  23. 9
      Lib.Tools/Lib.Tools.csproj
  24. 10
      Lib.Tools/Versions.cs
  25. 12
      Mystify.sln
  26. 14
      Mystify/Enumerables.cs
  27. 1
      Mystify/Mystify.csproj
  28. 1
      Mystify/ViewModels/ControllableSelectionViewModel.cs
  29. 1
      Mystify/ViewModels/MainWindowViewModel.cs

@ -0,0 +1,17 @@
// Author: Simon Gockner
// Created: 2020-09-12
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
namespace Lib.Logging.Exceptions
{
public class LogNotInitializedException : Exception
{
public LogNotInitializedException()
: base("Log is not initialized yet.")
{
}
}
}

@ -0,0 +1,9 @@
using Lib.Logging.Interfaces;
namespace Lib.Logging.Factories
{
public interface ILogFactory
{
ILog Create();
}
}

@ -0,0 +1,46 @@
// Author: Gockner, Simon
// Created: 2019-09-26
// Copyright(c) 2019 SimonG. All Rights Reserved.
using System;
using System.Threading.Tasks;
using Lib.Logging.Loggers.Interfaces;
namespace Lib.Logging.Interfaces
{
/// <summary>
/// The main logging interface
/// </summary>
public interface ILog : IAsyncDisposable
{
/// <summary>
/// Initialize the <see cref="ILog"/>
/// </summary>
/// <returns>True if successful, false if not</returns>
bool InitializeLog();
/// <summary>
/// Set the <see cref="LogLevels"/> of the current <see cref="ILog"/> instance
/// </summary>
/// <param name="logLevel">The <see cref="LogLevels"/></param>
void SetLogLevel(LogLevels logLevel);
/// <summary>
/// Add an <see cref="ILogger"/> to the <see cref="ILog"/>
/// </summary>
/// <param name="logger">The <see cref="ILogger"/></param>
void AddLogger(ILogger logger);
/// <summary>
/// Remove an <see cref="ILogger"/> from the <see cref="ILog"/>
/// </summary>
/// <param name="logger">The <see cref="ILogger"/></param>
void RemoveLogger(ILogger logger);
/// <summary>
/// Write a header to all loggers
/// </summary>
/// <returns>A <see cref="Task"/> to wait on</returns>
Task WriteLogHeader<T>();
}
}

@ -0,0 +1,17 @@
// Author: Gockner, Simon
// Created: 2019-09-26
// Copyright(c) 2019 SimonG. All Rights Reserved.
namespace Lib.Logging.Interfaces
{
/// <summary>
/// The <see cref="ILogComponent"/>
/// </summary>
public interface ILogComponent
{
/// <summary>
/// The <see cref="Component"/>
/// </summary>
string Component { get; }
}
}

@ -0,0 +1,34 @@
// Author: Gockner, Simon
// Created: 2019-09-27
// Copyright(c) 2019 SimonG. All Rights Reserved.
using System;
namespace Lib.Logging.Interfaces
{
/// <summary>
/// An interface that is used to handle log messages
/// </summary>
public interface ILogMessage
{
/// <summary>
/// The <see cref="LogLevels"/> of the <see cref="ILogMessage"/>
/// </summary>
LogLevels LogLevel { get; set; }
/// <summary>
/// The <see cref="Timestamp"/> of the <see cref="ILogMessage"/>
/// </summary>
DateTime Timestamp { get; set; }
/// <summary>
/// The <see cref="ILogComponent"/> of the <see cref="ILogMessage"/>
/// </summary>
ILogComponent? Component { get; set; }
/// <summary>
/// The <see cref="Message"/> of the <see cref="ILogMessage"/>
/// </summary>
string? Message { get; set; }
}
}

@ -0,0 +1,37 @@
// Author: Gockner, Simon
// Created: 2019-09-26
// Copyright(c) 2019 SimonG. All Rights Reserved.
namespace Lib.Logging.Interfaces
{
/// <summary>
/// The available <see cref="LogLevels"/>
/// </summary>
public enum LogLevels
{
/// <summary>
/// No logging
/// </summary>
None,
/// <summary>
/// Error logging
/// </summary>
Error,
/// <summary>
/// Default logging
/// </summary>
Default,
/// <summary>
/// Advanced logging
/// </summary>
Advanced,
/// <summary>
/// Debug logging
/// </summary>
Debug
}
}

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<Nullable>enable</Nullable>
<LangVersion>9</LangVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Lib.Tools\Lib.Tools.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,218 @@
// Author: Gockner, Simon
// Created: 2019-09-26
// Copyright(c) 2019 SimonG. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using Lib.Logging.Exceptions;
using Lib.Logging.Interfaces;
using Lib.Logging.Loggers.Interfaces;
using Lib.Tools;
namespace Lib.Logging
{
/// <summary>
/// The main logging class
/// </summary>
public class Log : ILog
{
/// <summary>
/// Constructor for <see cref="Log"/>
/// </summary>
public Log() => Loggers = new List<ILogger>();
/// <summary>
/// <see cref="List{T}"/> of <see cref="ILogger"/>s that are subscribed to this <see cref="Log"/>
/// </summary>
protected static List<ILogger>? Loggers { get; private set; }
/// <summary>
/// The <see cref="LogLevels"/> of this logging instance
/// </summary>
protected static LogLevels LogLevel { get; private set; } = LogLevels.Default; //TODO: Move LogLevel to ILogger? Allows to set logLevel separately for each ILogger
/// <summary>
/// Initialize the <see cref="ILog"/>
/// </summary>
/// <returns>True if successful, false if not</returns>
public bool InitializeLog()
{
return true;
}
/// <summary>
/// Set the <see cref="LogLevels"/> of the current <see cref="Log"/> instance
/// </summary>
/// <param name="logLevel">The <see cref="LogLevels"/></param>
public void SetLogLevel(LogLevels logLevel)
{
LogLevel = logLevel;
LogLevelChanged?.Invoke(this, LogLevel);
}
/// <summary>
/// Add an <see cref="ILogger"/> to the <see cref="Log"/>
/// </summary>
/// <param name="logger">The <see cref="ILogger"/></param>
public void AddLogger(ILogger logger) => Loggers?.Add(logger);
/// <summary>
/// Remove an <see cref="ILogger"/> from the <see cref="Log"/>
/// </summary>
/// <param name="logger">The <see cref="ILogger"/></param>
public void RemoveLogger(ILogger logger) => Loggers?.Remove(logger);
/// <summary>
/// Write a given <see cref="Exception"/> to the set <see cref="ILogger"/>s
/// </summary>
/// <param name="ex">The <see cref="Exception"/></param>
/// <typeparam name="T">The <see cref="Type"/> of the caller</typeparam>
public static async Task Write<T>(Exception ex)
{
ILogComponent component = GetDefaultComponentFromType<T>();
await Write(component, LogLevels.Error, ex.Message);
await Write(component, LogLevels.Error, "");
await Write(component, LogLevels.Error, ex.StackTrace);
}
/// <summary>
/// Write a given <see cref="Exception"/> to the set <see cref="ILogger"/>s
/// </summary>
/// <param name="component">The <see cref="ILogComponent"/></param>
/// <param name="ex">The <see cref="Exception"/></param>
public static async Task Write(ILogComponent component, Exception ex)
{
await Write(component, LogLevels.Error, ex.Message);
await Write(component, LogLevels.Error, "");
await Write(component, LogLevels.Error, ex.StackTrace);
}
/// <summary>
/// Write a given <see cref="AggregateException"/> to the set <see cref="ILogger"/>s
/// </summary>
/// <param name="ex">The <see cref="AggregateException"/></param>
/// <typeparam name="T">The <see cref="Type"/> of the caller</typeparam>
public static async Task Write<T>(AggregateException ex)
{
ILogComponent component = GetDefaultComponentFromType<T>();
await Write(component, LogLevels.Error, ex.Message);
await Write(component, LogLevels.Error, "");
await Write(component, LogLevels.Error, ex.StackTrace);
await Write(component, LogLevels.Error, "");
foreach (var innerException in ex.InnerExceptions)
{
await Write(component, innerException);
await Write(component, LogLevels.Error, "");
}
}
/// <summary>
/// Write a given <see cref="string"/> with the <see cref="LogLevels.Default"/> to the set <see cref="ILogger"/>s
/// </summary>
/// <param name="line"></param>
/// <typeparam name="T">The <see cref="Type"/> of the caller</typeparam>
public static async Task Write<T>(string line)
{
ILogComponent component = GetDefaultComponentFromType<T>();
await Write(component, LogLevels.Default, line);
}
/// <summary>
/// Write a given <see cref="string"/> with the <see cref="ILogComponent"/> of the calling <see cref="Assembly"/> and the <see cref="LogLevels"/> to the set <see cref="ILogger"/>s
/// </summary>
/// <param name="logLevel">The <see cref="LogLevels"/></param>
/// <param name="line">The given <see cref="string"/></param>
/// <typeparam name="T">The <see cref="Type"/> of the caller</typeparam>
public static async Task Write<T>(LogLevels logLevel, string line)
{
ILogComponent component = GetDefaultComponentFromType<T>();
await Write(component, logLevel, line);
}
/// <summary>
/// Write a given <see cref="string"/> with the <see cref="ILogComponent"/> and the <see cref="LogLevels"/> to the set <see cref="ILogger"/>s
/// </summary>
/// <param name="component">The <see cref="ILogComponent"/></param>
/// <param name="logLevel">The <see cref="LogLevels"/></param>
/// <param name="line">The given <see cref="string"/></param>
/// <exception cref="LogNotInitializedException">Log is not initialized yet</exception>
public static async Task Write(ILogComponent component, LogLevels logLevel, string line)
{
if (logLevel > LogLevel) //logLevel of the message can't be higher than the set LogLevel
return;
ILogMessage message = new LogMessage()
{
LogLevel = logLevel,
Timestamp = DateTime.Now,
Component = component,
Message = line
};
if (Loggers == null)
throw new LogNotInitializedException();
foreach (var logger in Loggers)
{
await logger.Write(message);
}
}
/// <summary>
/// Get the default <see cref="ILogComponent"/> for the given <see cref="Assembly"/>
/// </summary>
/// <typeparam name="T">The <see cref="Type"/></typeparam>
/// <returns></returns>
protected static ILogComponent GetDefaultComponentFromType<T>()
{
Assembly assembly = Assembly.GetAssembly(typeof(T));
LogComponentAttribute attribute = assembly.GetCustomAttribute<LogComponentAttribute>();
return attribute ?? new LogComponentAttribute("UNKNOWN");
}
/// <summary>
/// Write a header to all loggers
/// </summary>
/// <returns>A <see cref="Task"/> to wait on</returns>
public async Task WriteLogHeader<T>()
{
await Write<T>($"Mystify {Versions.GetVersion()}");
await Write<T>($"User: {Environment.UserName}");
await Write<T>($"Date: {DateTime.Today:dd.MM.yyyy}");
await Write<T>($"OS: {Environment.OSVersion}");
await Write<T>($"CLR-Version: {Environment.Version}");
await Write<T>("");
}
/// <summary>
/// <see cref="DisposeAsync"/> the <see cref="Log"/>
/// </summary>
public async ValueTask DisposeAsync()
{
if (Loggers != null)
{
foreach (var logger in Loggers)
{
await logger.DisposeAsync();
}
Loggers.Clear();
}
LogLevel = LogLevels.None;
}
/// <summary>
/// Event that is fired when <see cref="SetLogLevel"/> is called
/// <para><see cref="EventArgs"/> is the newly set <see cref="LogLevels"/></para>
/// </summary>
public static event EventHandler<LogLevels>? LogLevelChanged;
}
}

@ -0,0 +1,33 @@
// Author: Gockner, Simon
// Created: 2019-09-26
// Copyright(c) 2019 SimonG. All Rights Reserved.
using System;
using Lib.Logging.Interfaces;
namespace Lib.Logging
{
/// <summary>
/// The <see cref="ILogComponent"/> attribute
/// </summary>
[AttributeUsage(AttributeTargets.Assembly)]
public class LogComponentAttribute : Attribute, ILogComponent
{
/// <summary>
/// <see cref="LogComponentAttribute"/> constructor
/// </summary>
/// <param name="component">The <see cref="Component"/></param>
public LogComponentAttribute(string component) => Component = component;
/// <summary>
/// The <see cref="Component"/>
/// </summary>
public string Component { get; }
/// <summary>
/// Returns the <see cref="Component"/> of this <see cref="ILogComponent"/>
/// </summary>
/// <returns>The <see cref="Component"/></returns>
public override string ToString() => Component;
}
}

@ -0,0 +1,41 @@
// Author: Gockner, Simon
// Created: 2019-09-27
// Copyright(c) 2019 SimonG. All Rights Reserved.
using System;
using Lib.Logging.Interfaces;
namespace Lib.Logging
{
/// <summary>
/// Implementation of <see cref="ILogMessage"/>
/// </summary>
public class LogMessage : ILogMessage
{
/// <summary>
/// The <see cref="LogLevels"/> of the <see cref="LogMessage"/>
/// </summary>
public LogLevels LogLevel { get; set; }
/// <summary>
/// The <see cref="Timestamp"/> of the <see cref="LogMessage"/>
/// </summary>
public DateTime Timestamp { get; set; }
/// <summary>
/// The <see cref="ILogComponent"/> of the <see cref="LogMessage"/>
/// </summary>
public ILogComponent? Component { get; set; }
/// <summary>
/// The <see cref="Message"/> of the <see cref="LogMessage"/>
/// </summary>
public string? Message { get; set; }
/// <summary>
/// Builds the <see cref="LogMessage"/> out of all parts and returns it as a <see cref="string"/>
/// </summary>
/// <returns>The <see cref="LogMessage"/> as a <see cref="string"/></returns>
public override string ToString() => $"{Timestamp:u}: [{Component}] {Message}\n";
}
}

@ -0,0 +1,28 @@
// Author: Gockner, Simon
// Created: 2019-09-26
// Copyright(c) 2019 SimonG. All Rights Reserved.
using System;
using System.Threading.Tasks;
using Lib.Logging.Interfaces;
using Lib.Logging.Loggers.Interfaces;
namespace Lib.Logging.Loggers
{
/// <summary>
/// An <see cref="ILogger"/> that writes log messages to the <see cref="Console"/>
/// </summary>
public class ConsoleLogger : IConsoleLogger
{
/// <summary>
/// Write the given <see cref="string"/> to the <see cref="Console"/>
/// </summary>
/// <param name="message">The <see cref="ILogMessage"/></param>
public async Task Write(ILogMessage message) => await Task.Run(() => Console.Write(message.ToString()));
/// <summary>
/// <see cref="DisposeAsync"/> the <see cref="ConsoleLogger"/>
/// </summary>
public async ValueTask DisposeAsync() => await Task.Run(Console.Clear);
}
}

@ -0,0 +1,13 @@
// Author: Gockner, Simon
// Created: 2019-11-24
// Copyright(c) 2019 SimonG. All Rights Reserved.
using Lib.Logging.Loggers.Interfaces;
namespace Lib.Logging.Loggers.Factories
{
public interface IConsoleLoggerFactory
{
IConsoleLogger Create();
}
}

@ -0,0 +1,13 @@
// Author: Gockner, Simon
// Created: 2019-11-24
// Copyright(c) 2019 SimonG. All Rights Reserved.
using Lib.Logging.Loggers.Interfaces;
namespace Lib.Logging.Loggers.Factories
{
public interface IFileLoggerFactory
{
IFileLogger Create(string filePath, string fileName);
}
}

@ -0,0 +1,14 @@
// Author: Simon Gockner
// Created: 2020-09-14
// Copyright(c) 2020 SimonG. All Rights Reserved.
using Lib.Logging.Interfaces;
using Lib.Logging.Loggers.Interfaces;
namespace Lib.Logging.Loggers.Factories
{
public interface ILoggerInitializerFactory
{
ILoggerInitializer Create(ILog log);
}
}

@ -0,0 +1,80 @@
// Author: Gockner, Simon
// Created: 2019-09-26
// Copyright(c) 2019 SimonG. All Rights Reserved.
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Lib.Logging.Interfaces;
using Lib.Logging.Loggers.Interfaces;
namespace Lib.Logging.Loggers
{
/// <summary>
/// An <see cref="ILogger"/> that writes log messages to a set file
/// </summary>
public class FileLogger : IFileLogger
{
private readonly StreamWriter _fileWriter;
private readonly Timer _timer;
private readonly SemaphoreSlim _lockObject = new SemaphoreSlim(1);
/// <summary>
/// Constructor for <see cref="FileLogger"/>
/// </summary>
/// <param name="filePath">The directory of the LogFile</param>
/// <param name="fileName">The path of the LogFile</param>
public FileLogger(string filePath, string fileName)
{
Directory.CreateDirectory(filePath);
_fileWriter = new StreamWriter(Path.Combine(filePath, fileName), true);
_timer = new Timer(TimerCallback, null, 0, 1000);
}
/// <summary>
/// Write the given <see cref="string"/> to the file
/// </summary>
/// <param name="message">The <see cref="ILogMessage"/></param>
public async Task Write(ILogMessage message)
{
await _lockObject.WaitAsync();
try
{
await _fileWriter.WriteAsync(message.ToString());
}
finally
{
_lockObject.Release();
}
}
private async void TimerCallback(object state) => await Flush();
private async Task Flush()
{
await _lockObject.WaitAsync();
try
{
await _fileWriter.FlushAsync();
}
finally
{
_lockObject.Release();
}
}
/// <summary>
/// <see cref="DisposeAsync"/> the <see cref="FileLogger"/>
/// </summary>
public async ValueTask DisposeAsync()
{
await _timer.DisposeAsync();
await Flush();
await _fileWriter.DisposeAsync();
_lockObject.Dispose();
}
}
}

@ -0,0 +1,11 @@
// Author: Gockner, Simon
// Created: 2019-11-24
// Copyright(c) 2019 SimonG. All Rights Reserved.
namespace Lib.Logging.Loggers.Interfaces
{
public interface IConsoleLogger : ILogger
{
}
}

@ -0,0 +1,11 @@
// Author: Gockner, Simon
// Created: 2019-11-24
// Copyright(c) 2019 SimonG. All Rights Reserved.
namespace Lib.Logging.Loggers.Interfaces
{
public interface IFileLogger : ILogger
{
}
}

@ -0,0 +1,22 @@
// Author: Gockner, Simon
// Created: 2019-09-26
// Copyright(c) 2019 SimonG. All Rights Reserved.
using System;
using System.Threading.Tasks;
using Lib.Logging.Interfaces;
namespace Lib.Logging.Loggers.Interfaces
{
/// <summary>
/// Base class for loggers
/// </summary>
public interface ILogger : IAsyncDisposable
{
/// <summary>
/// Write the given <see cref="ILogMessage"/>
/// </summary>
/// <param name="message">The <see cref="ILogMessage"/></param>
Task Write(ILogMessage message);
}
}

@ -0,0 +1,13 @@
// Author: Simon Gockner
// Created: 2020-09-14
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
namespace Lib.Logging.Loggers.Interfaces
{
public interface ILoggerInitializer : IAsyncDisposable
{
bool Init();
}
}

@ -0,0 +1,53 @@
// Author: Simon Gockner
// Created: 2020-09-14
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.IO;
using System.Threading.Tasks;
using Lib.Logging.Interfaces;
using Lib.Logging.Loggers.Factories;
using Lib.Logging.Loggers.Interfaces;
namespace Lib.Logging.Loggers
{
public class LoggerInitializer : ILoggerInitializer
{
private readonly string _logFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Mystify", "Logs");
private readonly string _logFileName = $"Mystify_Log_{DateTime.Now:yyyy_MM_dd}_{DateTime.Now:hh_mm_ss}.txt";
private readonly ILog _log;
private readonly IFileLoggerFactory _fileLoggerFactory;
private readonly IConsoleLoggerFactory _consoleLoggerFactory;
private IFileLogger? _fileLogger;
private IConsoleLogger? _consoleLogger;
public LoggerInitializer(ILog log, IFileLoggerFactory fileLoggerFactory, IConsoleLoggerFactory consoleLoggerFactory)
{
_log = log;
_fileLoggerFactory = fileLoggerFactory;
_consoleLoggerFactory = consoleLoggerFactory;
}
public bool Init()
{
_fileLogger = _fileLoggerFactory.Create(_logFilePath, _logFileName);
_log.AddLogger(_fileLogger);
_consoleLogger = _consoleLoggerFactory.Create();
_log.AddLogger(_consoleLogger);
return true;
}
public async ValueTask DisposeAsync()
{
if (_fileLogger != null)
await _fileLogger.DisposeAsync();
if (_consoleLogger != null)
await _consoleLogger.DisposeAsync();
}
}
}

@ -0,0 +1,12 @@
// Author: Simon Gockner
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using Lib.Logging;
[assembly:LogComponent("LOGGING")]
namespace Lib.Logging.Properties
{
}

@ -0,0 +1,29 @@
// Author: Gockner, Simon
// Created: 2020-11-20
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
namespace Lib.Tools
{
public static class Enumerables
{
public static ObservableCollection<T> ToObservableCollection<T>(this IEnumerable<T> enumerable) => new ObservableCollection<T>(enumerable);
public static ObservableCollection<T> ToObservableCollectionOfType<T>(this IEnumerable enumerable) => enumerable.Cast<T>().ToObservableCollection();
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
{
IEnumerable<T> list = enumerable.ToList();
foreach (T item in list)
{
action(item);
}
return list;
}
}
}

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>9</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,10 @@
using System;
using System.Reflection;
namespace Lib.Tools
{
public static class Versions
{
public static Version? GetVersion() => Assembly.GetEntryAssembly()?.GetName().Version;
}
}

@ -10,6 +10,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lib.Midi", "Lib.Midi\Lib.Mi
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lib.Driver", "Lib.Driver\Lib.Driver.csproj", "{3C246E60-EC2B-41FE-AB1C-96B8C4FD9136}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lib.Driver", "Lib.Driver\Lib.Driver.csproj", "{3C246E60-EC2B-41FE-AB1C-96B8C4FD9136}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lib.Logging", "Lib.Logging\Lib.Logging.csproj", "{43547EFB-2525-41C6-846B-927C0AA058F7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lib.Tools", "Lib.Tools\Lib.Tools.csproj", "{4E283FDE-3E28-49F6-9FCF-529D8E82FBB9}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -36,5 +40,13 @@ Global
{3C246E60-EC2B-41FE-AB1C-96B8C4FD9136}.Debug|Any CPU.Build.0 = Debug|Any CPU {3C246E60-EC2B-41FE-AB1C-96B8C4FD9136}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3C246E60-EC2B-41FE-AB1C-96B8C4FD9136}.Release|Any CPU.ActiveCfg = Release|Any CPU {3C246E60-EC2B-41FE-AB1C-96B8C4FD9136}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3C246E60-EC2B-41FE-AB1C-96B8C4FD9136}.Release|Any CPU.Build.0 = Release|Any CPU {3C246E60-EC2B-41FE-AB1C-96B8C4FD9136}.Release|Any CPU.Build.0 = Release|Any CPU
{43547EFB-2525-41C6-846B-927C0AA058F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{43547EFB-2525-41C6-846B-927C0AA058F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{43547EFB-2525-41C6-846B-927C0AA058F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{43547EFB-2525-41C6-846B-927C0AA058F7}.Release|Any CPU.Build.0 = Release|Any CPU
{4E283FDE-3E28-49F6-9FCF-529D8E82FBB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4E283FDE-3E28-49F6-9FCF-529D8E82FBB9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4E283FDE-3E28-49F6-9FCF-529D8E82FBB9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4E283FDE-3E28-49F6-9FCF-529D8E82FBB9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

@ -1,14 +0,0 @@
// Author: Gockner, Simon
// Created: 2021-04-14
// Copyright(c) 2021 SimonG. All Rights Reserved.
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Mystify
{
public static class Enumerables
{
public static ObservableCollection<T> ToObservableCollection<T>(this IEnumerable<T> enumerable) => new(enumerable);
}
}

@ -19,5 +19,6 @@
<ProjectReference Include="..\Lib.Driver\Lib.Driver.csproj" /> <ProjectReference Include="..\Lib.Driver\Lib.Driver.csproj" />
<ProjectReference Include="..\Lib.Midi\Lib.Midi.csproj" /> <ProjectReference Include="..\Lib.Midi\Lib.Midi.csproj" />
<ProjectReference Include="..\Lib.NotifyIcon\Lib.NotifyIcon.csproj" /> <ProjectReference Include="..\Lib.NotifyIcon\Lib.NotifyIcon.csproj" />
<ProjectReference Include="..\Lib.Tools\Lib.Tools.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -8,6 +8,7 @@ using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Windows.Input; using System.Windows.Input;
using Lib.Audio.Interfaces; using Lib.Audio.Interfaces;
using Lib.Tools;
using Mystify.Views; using Mystify.Views;
using ReactiveUI; using ReactiveUI;

@ -9,6 +9,7 @@ using System.Linq;
using System.Windows.Input; using System.Windows.Input;
using Avalonia.Controls; using Avalonia.Controls;
using Lib.Driver; using Lib.Driver;
using Lib.Tools;
using Mystify.Views; using Mystify.Views;
using ReactiveUI; using ReactiveUI;

Loading…
Cancel
Save