diff --git a/.editorconfig b/.editorconfig index 2e7f584..949cd61 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,62 +1,127 @@ -# EditorConfig is awesome:http://EditorConfig.org - -# top-most EditorConfig file root = true -# Don't use tabs for indentation. [*] indent_style = space -end_of_line = crlf - -# Dotnet code style settings: -[*.{cs,vb}] -# Sort using and Import directives with System.* appearing first -dotnet_sort_system_directives_first = true -# Avoid "this." and "Me." if not necessary -dotnet_style_qualification_for_field = false : warning -dotnet_style_qualification_for_property = false : warning -dotnet_style_qualification_for_method = false : warning -dotnet_style_qualification_for_event = false : warning - -# Use language keywords instead of framework type names for type references -dotnet_style_predefined_type_for_locals_parameters_members = true : suggestion -dotnet_style_predefined_type_for_member_access = true : suggestion - -# Suggest more modern language features when available -dotnet_style_object_initializer = true : suggestion -dotnet_style_collection_initializer = true : suggestion -dotnet_style_coalesce_expression = true : suggestion -dotnet_style_null_propagation = true : suggestion -dotnet_style_explicit_tuple_names = true : suggestion - -# CSharp code style settings: +indent_size = 4 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + + [*.cs] -# Prefer "var" everywhere -csharp_style_var_for_built_in_types = true : warning -csharp_style_var_when_type_is_apparent = true : warning -csharp_style_var_elsewhere = true : suggestion - -# Prefer method-like constructs to have a block body -csharp_style_expression_bodied_methods = false : suggestion -csharp_style_expression_bodied_constructors = false : suggestion -csharp_style_expression_bodied_operators = false : suggestion - -# Prefer property-like constructs to have an expression-body -csharp_style_expression_bodied_properties = true : none -csharp_style_expression_bodied_indexers = false : suggestion -csharp_style_expression_bodied_accessors = false : suggestion - -# Suggest more modern language features when available -csharp_style_pattern_matching_over_is_with_cast_check = true : suggestion -csharp_style_pattern_matching_over_as_with_null_check = true : suggestion -csharp_style_inlined_variable_declaration = true : suggestion -csharp_style_throw_expression = true : suggestion -csharp_style_conditional_delegate_call = true : suggestion - -# Newline settings -csharp_new_line_before_open_brace = all -csharp_new_line_before_else = true -csharp_new_line_before_catch = true -csharp_new_line_before_finally = true + +csharp_prefer_braces = true:silent +dotnet_style_prefer_auto_properties = true:silent + +dotnet_style_explicit_tuple_names = true:error +dotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion + +# naming + +dotnet_naming_rule.public_members_must_be_capitalized.symbols = public_symbols +dotnet_naming_symbols.public_symbols.applicable_kinds = property,method,field,event,delegate +dotnet_naming_symbols.public_symbols.applicable_accessibilities = public +dotnet_naming_symbols.public_symbols.required_modifiers = readonly + +dotnet_naming_rule.public_members_must_be_capitalized.style = first_word_upper_case_style +dotnet_naming_style.first_word_upper_case_style.capitalization = first_word_upper + +dotnet_naming_rule.public_members_must_be_capitalized.severity = warning + +# this + +dotnet_style_qualification_for_field = false:error +dotnet_style_qualification_for_property = false:error +dotnet_style_qualification_for_method = false:error +dotnet_style_qualification_for_event = false:error + +dotnet_style_predefined_type_for_locals_parameters_members = true:error +dotnet_style_predefined_type_for_member_access = true:error + +# access modifiers +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent +dotnet_style_require_accessibility_modifiers = always:error +dotnet_style_readonly_field = true:warning + +# brackets for operators + +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:suggestion +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:suggestion +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggestion +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:warning + +# object initializers + +dotnet_style_object_initializer = true:warning +dotnet_style_collection_initializer = true:warning + +# conditionals + +dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_return = false:suggestion + +# null checks + +dotnet_style_coalesce_expression = true:silent +dotnet_style_null_propagation = true:silent +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent + +# var vs explicit type + +csharp_style_var_for_built_in_types = true:error +csharp_style_var_when_type_is_apparent = true:error +csharp_style_var_elsewhere = true:suggestion + +# expressions + +csharp_style_expression_bodied_methods = false:suggestion +csharp_style_expression_bodied_constructors = false:suggestion +csharp_style_expression_bodied_operators = false:suggestion +csharp_style_expression_bodied_properties = true:suggestion +csharp_style_expression_bodied_indexers = when_on_single_line:silent +csharp_style_expression_bodied_accessors = false:warning + +csharp_style_pattern_matching_over_is_with_cast_check = true:silent +csharp_style_pattern_matching_over_as_with_null_check = true:silent +csharp_style_inlined_variable_declaration = true:silent + +csharp_prefer_simple_default_expression = true:silent +csharp_style_deconstructed_variable_declaration = true:silent +csharp_style_pattern_local_over_anonymous_function = true:warning +csharp_style_throw_expression = true:silent +csharp_style_conditional_delegate_call = true:silent + +# whitespace + +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true csharp_new_line_before_members_in_object_initializers = true -csharp_new_line_before_members_in_anonymous_types = true \ No newline at end of file +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true + +# indents + +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels= flush_left + +# spaces + +csharp_space_after_cast = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_parentheses =false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_around_binary_operators = before_and_after +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false + +# wrapping + +csharp_preserve_single_line_statements = false +csharp_preserve_single_line_blocks = true diff --git a/.gitignore b/.gitignore index 4458e3f..4d97422 100644 --- a/.gitignore +++ b/.gitignore @@ -22,8 +22,9 @@ bld/ [Bb]in/ [Oo]bj/ -# Visual Studio 2015 cache/options directory +# Visual Studio/ -Code cache/options directory .vs/ +.vscode/ # MSTest test Results [Tt]est[Rr]esult*/ @@ -226,3 +227,5 @@ ModelManifest.xml # Merge *.orig + +!Maple.Log \ No newline at end of file diff --git a/src/Maple.Localization/Properties/Resources.en.Designer.cs b/.gitmodules similarity index 100% rename from src/Maple.Localization/Properties/Resources.en.Designer.cs rename to .gitmodules diff --git a/.nuget/NuGet.config b/.nuget/NuGet.config new file mode 100644 index 0000000..d39766b --- /dev/null +++ b/.nuget/NuGet.config @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.vsconfig b/.vsconfig new file mode 100644 index 0000000..a447280 --- /dev/null +++ b/.vsconfig @@ -0,0 +1,26 @@ +{ + "version": "1.0", + "components": [ + "Microsoft.VisualStudio.Component.CoreEditor", + "Microsoft.VisualStudio.Workload.CoreEditor", + "Microsoft.NetCore.Component.Runtime.3.1", + "Microsoft.NetCore.Component.SDK", + "Microsoft.VisualStudio.Component.NuGet", + "Microsoft.VisualStudio.Component.Roslyn.Compiler", + "Microsoft.VisualStudio.Component.Roslyn.LanguageServices", + "Microsoft.VisualStudio.Component.FSharp", + "Microsoft.NetCore.Component.DevelopmentTools", + "Microsoft.Net.ComponentGroup.DevelopmentPrerequisites", + "Microsoft.Component.MSBuild", + "Microsoft.VisualStudio.Component.TextTemplating", + "Microsoft.VisualStudio.Component.SQL.CLR", + "Microsoft.VisualStudio.Component.ManagedDesktop.Core", + "Microsoft.VisualStudio.Component.IntelliCode", + "Microsoft.Net.ComponentGroup.TargetingPacks.Common", + "Microsoft.VisualStudio.Component.DiagnosticTools", + "Microsoft.VisualStudio.Component.ManagedDesktop.Prerequisites", + "Microsoft.VisualStudio.Component.Debugger.JustInTime", + "Microsoft.VisualStudio.Workload.ManagedDesktop", + "Microsoft.VisualStudio.Component.Git", + ] +} diff --git a/Maple.ruleset b/Maple.ruleset new file mode 100644 index 0000000..0c325fe --- /dev/null +++ b/Maple.ruleset @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/Maple.sln b/Maple.sln index a9926ba..5dc6789 100644 --- a/Maple.sln +++ b/Maple.sln @@ -1,28 +1,21 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27130.2010 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28803.352 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D65C950A-327A-496D-A49C-B45E8F97C610}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig + .vsconfig = .vsconfig .XamlStyler = .XamlStyler src\Resources\Art_Of_Escapism_-_Universe_Words.mp3 = src\Resources\Art_Of_Escapism_-_Universe_Words.mp3 src\Resources\client_secret.json = src\Resources\client_secret.json src\Resources\SharedAssemblyInfo.cs = src\Resources\SharedAssemblyInfo.cs EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Maple", "src\Maple\Maple.csproj", "{FBD5595B-6859-4E8E-BDFA-C3169EF34985}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Maple", "src\Maple\Maple.csproj", "{FBD5595B-6859-4E8E-BDFA-C3169EF34985}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Maple.Core", "src\Maple.Core\Maple.Core.csproj", "{21FA5854-0692-42E2-924E-A38CF3C7FF71}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Maple.Data", "src\Maple.Data\Maple.Data.csproj", "{B3CD46BE-3C08-4BAE-AE60-A6D84A62400C}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Maple.Localization", "src\Maple.Localization\Maple.Localization.csproj", "{A073FC92-90E3-4541-8B52-6F7293187871}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Maple.Youtube", "src\Maple.Youtube\Maple.Youtube.csproj", "{B5BE546F-8D9F-4FB9-B235-AF05FD553F9E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Maple.Test", "src\Maple.Test\Maple.Test.csproj", "{60F95B05-E714-4E0F-BA97-44711EC74210}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Maple.Youtube", "src\Maple.Youtube\Maple.Youtube.csproj", "{B5BE546F-8D9F-4FB9-B235-AF05FD553F9E}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Cake", "Cake", "{E463B2A9-3556-4651-8EEA-0239E20B5393}" ProjectSection(SolutionItems) = preProject @@ -31,42 +24,54 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Cake", "Cake", "{E463B2A9-3 Cake\tools\packages.config = Cake\tools\packages.config EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Maple.Domain", "src\Maple.Domain\Maple.Domain.csproj", "{9D7D05A6-8271-4836-A7BB-5B2ABECCBD81}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Maple.Domain", "src\Maple.Domain\Maple.Domain.csproj", "{9D7D05A6-8271-4836-A7BB-5B2ABECCBD81}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {FBD5595B-6859-4E8E-BDFA-C3169EF34985}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FBD5595B-6859-4E8E-BDFA-C3169EF34985}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FBD5595B-6859-4E8E-BDFA-C3169EF34985}.Debug|x64.ActiveCfg = Debug|Any CPU + {FBD5595B-6859-4E8E-BDFA-C3169EF34985}.Debug|x64.Build.0 = Debug|Any CPU + {FBD5595B-6859-4E8E-BDFA-C3169EF34985}.Debug|x86.ActiveCfg = Debug|Any CPU + {FBD5595B-6859-4E8E-BDFA-C3169EF34985}.Debug|x86.Build.0 = Debug|Any CPU {FBD5595B-6859-4E8E-BDFA-C3169EF34985}.Release|Any CPU.ActiveCfg = Release|Any CPU {FBD5595B-6859-4E8E-BDFA-C3169EF34985}.Release|Any CPU.Build.0 = Release|Any CPU - {21FA5854-0692-42E2-924E-A38CF3C7FF71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {21FA5854-0692-42E2-924E-A38CF3C7FF71}.Debug|Any CPU.Build.0 = Debug|Any CPU - {21FA5854-0692-42E2-924E-A38CF3C7FF71}.Release|Any CPU.ActiveCfg = Release|Any CPU - {21FA5854-0692-42E2-924E-A38CF3C7FF71}.Release|Any CPU.Build.0 = Release|Any CPU - {B3CD46BE-3C08-4BAE-AE60-A6D84A62400C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B3CD46BE-3C08-4BAE-AE60-A6D84A62400C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B3CD46BE-3C08-4BAE-AE60-A6D84A62400C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B3CD46BE-3C08-4BAE-AE60-A6D84A62400C}.Release|Any CPU.Build.0 = Release|Any CPU - {A073FC92-90E3-4541-8B52-6F7293187871}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A073FC92-90E3-4541-8B52-6F7293187871}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A073FC92-90E3-4541-8B52-6F7293187871}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A073FC92-90E3-4541-8B52-6F7293187871}.Release|Any CPU.Build.0 = Release|Any CPU + {FBD5595B-6859-4E8E-BDFA-C3169EF34985}.Release|x64.ActiveCfg = Release|Any CPU + {FBD5595B-6859-4E8E-BDFA-C3169EF34985}.Release|x64.Build.0 = Release|Any CPU + {FBD5595B-6859-4E8E-BDFA-C3169EF34985}.Release|x86.ActiveCfg = Release|Any CPU + {FBD5595B-6859-4E8E-BDFA-C3169EF34985}.Release|x86.Build.0 = Release|Any CPU {B5BE546F-8D9F-4FB9-B235-AF05FD553F9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B5BE546F-8D9F-4FB9-B235-AF05FD553F9E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B5BE546F-8D9F-4FB9-B235-AF05FD553F9E}.Debug|x64.ActiveCfg = Debug|Any CPU + {B5BE546F-8D9F-4FB9-B235-AF05FD553F9E}.Debug|x64.Build.0 = Debug|Any CPU + {B5BE546F-8D9F-4FB9-B235-AF05FD553F9E}.Debug|x86.ActiveCfg = Debug|Any CPU + {B5BE546F-8D9F-4FB9-B235-AF05FD553F9E}.Debug|x86.Build.0 = Debug|Any CPU {B5BE546F-8D9F-4FB9-B235-AF05FD553F9E}.Release|Any CPU.ActiveCfg = Release|Any CPU {B5BE546F-8D9F-4FB9-B235-AF05FD553F9E}.Release|Any CPU.Build.0 = Release|Any CPU - {60F95B05-E714-4E0F-BA97-44711EC74210}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {60F95B05-E714-4E0F-BA97-44711EC74210}.Debug|Any CPU.Build.0 = Debug|Any CPU - {60F95B05-E714-4E0F-BA97-44711EC74210}.Release|Any CPU.ActiveCfg = Release|Any CPU - {60F95B05-E714-4E0F-BA97-44711EC74210}.Release|Any CPU.Build.0 = Release|Any CPU + {B5BE546F-8D9F-4FB9-B235-AF05FD553F9E}.Release|x64.ActiveCfg = Release|Any CPU + {B5BE546F-8D9F-4FB9-B235-AF05FD553F9E}.Release|x64.Build.0 = Release|Any CPU + {B5BE546F-8D9F-4FB9-B235-AF05FD553F9E}.Release|x86.ActiveCfg = Release|Any CPU + {B5BE546F-8D9F-4FB9-B235-AF05FD553F9E}.Release|x86.Build.0 = Release|Any CPU {9D7D05A6-8271-4836-A7BB-5B2ABECCBD81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9D7D05A6-8271-4836-A7BB-5B2ABECCBD81}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9D7D05A6-8271-4836-A7BB-5B2ABECCBD81}.Debug|x64.ActiveCfg = Debug|Any CPU + {9D7D05A6-8271-4836-A7BB-5B2ABECCBD81}.Debug|x64.Build.0 = Debug|Any CPU + {9D7D05A6-8271-4836-A7BB-5B2ABECCBD81}.Debug|x86.ActiveCfg = Debug|Any CPU + {9D7D05A6-8271-4836-A7BB-5B2ABECCBD81}.Debug|x86.Build.0 = Debug|Any CPU {9D7D05A6-8271-4836-A7BB-5B2ABECCBD81}.Release|Any CPU.ActiveCfg = Release|Any CPU {9D7D05A6-8271-4836-A7BB-5B2ABECCBD81}.Release|Any CPU.Build.0 = Release|Any CPU + {9D7D05A6-8271-4836-A7BB-5B2ABECCBD81}.Release|x64.ActiveCfg = Release|Any CPU + {9D7D05A6-8271-4836-A7BB-5B2ABECCBD81}.Release|x64.Build.0 = Release|Any CPU + {9D7D05A6-8271-4836-A7BB-5B2ABECCBD81}.Release|x86.ActiveCfg = Release|Any CPU + {9D7D05A6-8271-4836-A7BB-5B2ABECCBD81}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/license.md b/license.md index 8864d4a..15bc72f 100644 --- a/license.md +++ b/license.md @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017 +Copyright (c) 2019 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Maple.Core/Commands/AsyncCommand.cs b/src/Maple.Core/Commands/AsyncCommand.cs deleted file mode 100644 index da88d30..0000000 --- a/src/Maple.Core/Commands/AsyncCommand.cs +++ /dev/null @@ -1,155 +0,0 @@ -using System; -using System.ComponentModel; -using System.Runtime.CompilerServices; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Input; - -namespace Maple.Core -{ - // source: https://msdn.microsoft.com/en-us/magazine/dn630647.aspx?f=255&MSPPError=-2147217396 - // Async Programming : Patterns for Asynchronous MVVM Applications: Commands by Stephen Cleary - public class AsyncCommand : AsyncCommandBase, INotifyPropertyChanged - { - private readonly Func> _command; - private readonly CancelAsyncCommand _cancelCommand; - private readonly Func _canExecute = null; - - private NotifyTaskCompletion _execution; - - public event PropertyChangedEventHandler PropertyChanged; - - public ICommand CancelCommand => _cancelCommand; - - public NotifyTaskCompletion Execution - { - get { return _execution; } - private set - { - _execution = value; - OnPropertyChanged(); - } - } - - public AsyncCommand(Func> command) - { - _command = command ?? throw new ArgumentNullException(nameof(command)); - _cancelCommand = new CancelAsyncCommand(); - } - - public AsyncCommand(Func> command, Func canExecuteEvaluator) - : this(command) - { - _canExecute = canExecuteEvaluator ?? throw new ArgumentNullException(nameof(canExecuteEvaluator)); - } - - public override bool CanExecute(object parameter) - { - return (Execution == null || Execution.IsCompleted) - && (_canExecute?.Invoke() ?? true); - } - - public override async Task ExecuteAsync(object parameter) - { - _cancelCommand.NotifyCommandStarting(); - - Execution = new NotifyTaskCompletion(_command(_cancelCommand.Token)); - RaiseCanExecuteChanged(); - - await Execution.TaskCompletion.ConfigureAwait(true); - _cancelCommand.NotifyCommandFinished(); - RaiseCanExecuteChanged(); - } - - protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - private sealed class CancelAsyncCommand : ICommand - { - private CancellationTokenSource _cts = new CancellationTokenSource(); - private bool _commandExecuting; - - public CancellationToken Token { get { return _cts.Token; } } - - public void NotifyCommandStarting() - { - _commandExecuting = true; - if (!_cts.IsCancellationRequested) - return; - - _cts = new CancellationTokenSource(); - RaiseCanExecuteChanged(); - } - - public void NotifyCommandFinished() - { - _commandExecuting = false; - RaiseCanExecuteChanged(); - } - - bool ICommand.CanExecute(object parameter) - { - return _commandExecuting && !_cts.IsCancellationRequested; - } - - void ICommand.Execute(object parameter) - { - _cts.Cancel(); - RaiseCanExecuteChanged(); - } - - public event EventHandler CanExecuteChanged - { - add { CommandManager.RequerySuggested += value; } - remove { CommandManager.RequerySuggested -= value; } - } - - private void RaiseCanExecuteChanged() - { - CommandManager.InvalidateRequerySuggested(); - } - } - } - - public static class AsyncCommand - { - public static AsyncCommand Create(Func command) - { - return new AsyncCommand(async _ => - { - await command().ConfigureAwait(true); - return null; - }); - } - - public static AsyncCommand Create(Func command, Func canExecute) - { - return new AsyncCommand(async _ => - { - await command().ConfigureAwait(true); - return null; - }, canExecute); - } - - public static AsyncCommand Create(Func> command, Func canExecute) - { - return new AsyncCommand(_ => command(), canExecute); - } - - public static AsyncCommand Create(Func command, Func canExecute) - { - return new AsyncCommand(async token => - { - await command(token).ConfigureAwait(true); - return null; - }, canExecute); - } - - public static AsyncCommand Create(Func> command, Func canExecute) - { - return new AsyncCommand(command, canExecute); - } - } -} diff --git a/src/Maple.Core/Commands/AsyncCommandBase.cs b/src/Maple.Core/Commands/AsyncCommandBase.cs deleted file mode 100644 index 7fb6fa4..0000000 --- a/src/Maple.Core/Commands/AsyncCommandBase.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Threading.Tasks; -using System.Windows.Input; - -namespace Maple.Core -{ - public abstract class AsyncCommandBase : IAsyncCommand - { - public abstract bool CanExecute(object parameter); - public abstract Task ExecuteAsync(object parameter); - - public async void Execute(object parameter) - { - await ExecuteAsync(parameter).ConfigureAwait(true); - } - - public event EventHandler CanExecuteChanged - { - add { CommandManager.RequerySuggested += value; } - remove { CommandManager.RequerySuggested -= value; } - } - - protected void RaiseCanExecuteChanged() - { - CommandManager.InvalidateRequerySuggested(); - } - } -} diff --git a/src/Maple.Core/Commands/IAsyncCommand.cs b/src/Maple.Core/Commands/IAsyncCommand.cs deleted file mode 100644 index 4734e7c..0000000 --- a/src/Maple.Core/Commands/IAsyncCommand.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Threading.Tasks; -using System.Windows.Input; - -namespace Maple.Core -{ - public interface IAsyncCommand : ICommand - { - Task ExecuteAsync(object parameter); - } -} diff --git a/src/Maple.Core/Commands/Obsolete/AsyncRelayCommand.cs b/src/Maple.Core/Commands/Obsolete/AsyncRelayCommand.cs deleted file mode 100644 index a25020b..0000000 --- a/src/Maple.Core/Commands/Obsolete/AsyncRelayCommand.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; -using System.Diagnostics; -using System.Threading.Tasks; -using System.Windows.Input; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - [Obsolete] - public class AsyncRelayCommand : ICommand - { - private readonly Func _canExecute = null; - private readonly Func _execute = null; - private Task _task; - - /// - /// Occurs when changes occur that affect whether or not the command should execute. - /// - public event EventHandler CanExecuteChanged - { - add { CommandManager.RequerySuggested += value; } - remove { CommandManager.RequerySuggested -= value; } - } - - /// - /// Initializes a new instance of the class. - /// - /// The method to execute. - /// methodToExecute - public AsyncRelayCommand(Func methodToExecute) - { - _execute = methodToExecute ?? throw new ArgumentNullException(nameof(methodToExecute), $"{nameof(methodToExecute)} {Resources.IsRequired}"); - } - - /// - /// Initializes a new instance of the class. - /// - /// The method to execute. - /// The can execute evaluator. - /// canExecuteEvaluator - public AsyncRelayCommand(Func methodToExecute, Func canExecuteEvaluator) : this(methodToExecute) - { - _canExecute = canExecuteEvaluator ?? throw new ArgumentNullException(nameof(canExecuteEvaluator), $"{nameof(canExecuteEvaluator)} {Resources.IsRequired}"); - } - - /// - /// Defines the method that determines whether the command can execute in its current state. - /// - /// Data used by the command. If the command does not require data to be passed, this object can be set to null. - /// - /// true if this command can be executed; otherwise, false. - /// - [DebuggerStepThrough] - public bool CanExecute(object parameter) - { - return parameter is T obj - ? _task == null - ? _canExecute(obj) - : _task.IsCompleted == true && _canExecute(obj) - : false; - } - - /// - /// Defines the method to be called when the command is invoked. - /// - /// Data used by the command. If the command does not require data to be passed, this object can be set to null. - [DebuggerStepThrough] - public async void Execute(object parameter) - { - _task = _execute((T)parameter); - - await _task.ConfigureAwait(true); - } - } - - [Obsolete] - public class AsyncRelayCommand : ICommand - { - private readonly Func _canExecute = null; - private readonly Func _execute = null; - private Task _task; - - /// - /// Occurs when changes occur that affect whether or not the command should execute. - /// - public event EventHandler CanExecuteChanged - { - add { CommandManager.RequerySuggested += value; } - remove { CommandManager.RequerySuggested -= value; } - } - - /// - /// Initializes a new instance of the class. - /// - /// The method to execute. - /// methodToExecute - public AsyncRelayCommand(Func methodToExecute) - { - _execute = methodToExecute ?? throw new ArgumentNullException(nameof(methodToExecute), $"{nameof(methodToExecute)} {Resources.IsRequired}"); - } - - /// - /// Initializes a new instance of the class. - /// - /// The method to execute. - /// The can execute evaluator. - /// canExecuteEvaluator - public AsyncRelayCommand(Func methodToExecute, Func canExecuteEvaluator) : this(methodToExecute) - { - _canExecute = canExecuteEvaluator ?? throw new ArgumentNullException(nameof(canExecuteEvaluator), $"{nameof(canExecuteEvaluator)} {Resources.IsRequired}"); - } - - /// - /// Defines the method that determines whether the command can execute in its current state. - /// - /// Data used by the command. If the command does not require data to be passed, this object can be set to null. - /// - /// true if this command can be executed; otherwise, false. - /// - [DebuggerStepThrough] - public bool CanExecute(object parameter) - { - return _task == null - ? _canExecute() - : _task?.IsCompleted == true && _canExecute(); - } - - /// - /// Defines the method to be called when the command is invoked. - /// - /// Data used by the command. If the command does not require data to be passed, this object can be set to null. - [DebuggerStepThrough] - public async void Execute(object parameter) - { - _task = _execute(); - - await _task.ConfigureAwait(true); - } - } -} diff --git a/src/Maple.Core/Commands/RelayCommand.cs b/src/Maple.Core/Commands/RelayCommand.cs deleted file mode 100644 index f5e5b5d..0000000 --- a/src/Maple.Core/Commands/RelayCommand.cs +++ /dev/null @@ -1,133 +0,0 @@ -using System; -using System.Diagnostics; -using System.Windows.Input; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - public class RelayCommand : ICommand - { - private readonly Action _execute = null; - private readonly Func _canExecute = null; - - /// - /// Occurs when changes occur that affect whether or not the command should execute. - /// - public event EventHandler CanExecuteChanged - { - add { CommandManager.RequerySuggested += value; } - remove { CommandManager.RequerySuggested -= value; } - } - - /// - /// Initializes a new instance of the class. - /// - /// The method to execute. - /// methodToExecute - public RelayCommand(Action methodToExecute) - { - _execute = methodToExecute ?? throw new ArgumentNullException(nameof(methodToExecute), $"{nameof(methodToExecute)} {Resources.IsRequired}"); - } - - /// - /// Initializes a new instance of the class. - /// - /// The method to execute. - /// The can execute evaluator. - /// canExecuteEvaluator - public RelayCommand(Action methodToExecute, Func canExecuteEvaluator) - : this(methodToExecute) - { - _canExecute = canExecuteEvaluator ?? throw new ArgumentNullException(nameof(canExecuteEvaluator), $"{nameof(canExecuteEvaluator)} {Resources.IsRequired}"); - } - - /// - /// Defines the method that determines whether the command can execute in its current state. - /// - /// Data used by the command. If the command does not require data to be passed, this object can be set to null. - /// - /// true if this command can be executed; otherwise, false. - /// - public bool CanExecute(object parameter) - { - return _canExecute == null ? true : _canExecute.Invoke(); - } - - /// - /// Defines the method to be called when the command is invoked. - /// - /// Data used by the command. If the command does not require data to be passed, this object can be set to null. - [DebuggerStepThrough] - public void Execute(object parameter) - { - _execute(); - } - } - - public class RelayCommand : ICommand - { - private readonly Action _execute = null; - private readonly Predicate _canExecute = null; - - /// - /// Initializes a new instance of the class. - /// - /// The execute. - public RelayCommand(Action execute) - { - _execute = execute ?? throw new ArgumentNullException(nameof(execute), $"{nameof(execute)} {Resources.IsRequired}"); - } - - /// - /// Initializes a new instance of the class. - /// - /// The execute. - /// The can execute. - /// execute - public RelayCommand(Action execute, Predicate canExecute) - : this(execute) - { - _canExecute = canExecute ?? throw new ArgumentNullException(nameof(canExecute), $"{nameof(canExecute)} {Resources.IsRequired}"); - } - - /// - /// Defines the method that determines whether the command can execute in its current state. - /// - /// Data used by the command. If the command does not require data to be passed, this object can be set to null. - /// - /// true if this command can be executed; otherwise, false. - /// - public bool CanExecute(object parameter) - { - if (_canExecute == null) - return true; - - if (parameter == null && typeof(T).IsValueType) - return _canExecute.Invoke(default(T)); - - if (parameter == null || parameter is T) - return (_canExecute.Invoke((T)parameter)); - - return false; - } - - /// - /// Occurs when changes occur that affect whether or not the command should execute. - /// - public event EventHandler CanExecuteChanged - { - add { CommandManager.RequerySuggested += value; } - remove { CommandManager.RequerySuggested -= value; } - } - - /// - /// Defines the method to be called when the command is invoked. - /// - /// Data used by the command. If the command does not require data to be passed, this object can be set to null. - [DebuggerStepThrough] - public void Execute(object parameter) - { - _execute((T)parameter); - } - } -} diff --git a/src/Maple.Core/DiagnosticReport.cs b/src/Maple.Core/DiagnosticReport.cs deleted file mode 100644 index 889713b..0000000 --- a/src/Maple.Core/DiagnosticReport.cs +++ /dev/null @@ -1,499 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; -using Microsoft.Win32; -using Humanizer; - -namespace Maple.Core -{ - - /// - /// A helper class for generating a report containing details related to - /// System, Process, Assemblies, Network and Environment - /// on which the application executes. - /// - public static class DiagnosticReport - { - private const char Pipe = '|'; - private const char Dot = '.'; - private const char Dash = '-'; - private const char Space = ' '; - private const char Colon = ':'; - private static readonly string NewLine = Environment.NewLine; - private static readonly string LinePrefix = Pipe + "\t"; - - private static readonly Action[] Actions = - { - AddSystem, - AddProcess, - AddDrives, - AddAssemblies, - AddNetworking - }; - - private static readonly string[] SystemHeaders = - { - "OS", - "64Bit OS", - "CLR Runtime", - "FQDN", - "Machine Name", - "Installed RAM", - "CPU", - "CPU Core Count", - "User", - "System Directory", - "Current Directory" - }; - - private static readonly string[] ProcessHeaders = - { - "Id", - "Name", - "Started", - "Loaded In", - "Optimized", - "64Bit Process", - "Large Address Aware", - "Module Name", - "Module File Name", - "Product Name", - "Original File Name", - "File Name", - "File Version", - "Product Version", - "Language", - "Copyright", - "WorkingSet", - "Interactive", - "CommandLine" - }; - - private static readonly string[] DrivesHeaders = - { - "Name", "Type", "Format", "Label", "Capacity(GB)", "Free(GB)", "Available(GB)" - }; - - private static readonly string[] AssemblyHeaders = - { - "Name", "GAC", "64Bit", "Optimized", "Framework", "Location", "CodeBase" - }; - - /// - /// Returns the details related to System, Process, Assemblies - /// and Environment on which the application executes. - /// - public static string Generate(DiagnosticReportType type = DiagnosticReportType.Full) - { - try - { - return GenerateImpl(type); - } - catch (Exception e) - { - return $"Unable to generate the Diagnostic Report. Error:{NewLine}\t{e}"; - } - } - - private static string GenerateImpl(DiagnosticReportType type) - { - var sw = Stopwatch.StartNew(); - - var builder = new StringBuilder(); - for (var i = 0; i < Actions.Length; i++) - { - var enabled = ((int)type & (1 << i)) != 0; - if (enabled) { Actions[i](builder); } - } - - sw.Stop(); - - builder.Insert(0, $"/{NewLine}{Pipe}Diagnostic Report generated at: {DateTime.Now:dd-MM-yyyy HH:mm:ss.fff} in: {sw.Elapsed.TotalMilliseconds} milliseconds.{NewLine}"); - builder.Append('\\'); - return builder.ToString(); - } - - private static void AddSystem(StringBuilder builder) - { - var maxHeaderLength = SystemHeaders.Max(h => h.Length); - var formatter = "{0,-" + (maxHeaderLength + 1) + "}"; - - var sectionIndex = builder.Length; - Format(SystemHeaders[0], Environment.OSVersion); - Format(SystemHeaders[1], Environment.Is64BitOperatingSystem); - Format(SystemHeaders[2], Environment.Version); - Format(SystemHeaders[4], Environment.MachineName); - Format(SystemHeaders[3], NetworkHelper.GetFQDN()); - Format(SystemHeaders[8], Environment.UserDomainName + "\\" + Environment.UserName); - Format(SystemHeaders[6], GetProcessorName()); - Format(SystemHeaders[7], Environment.ProcessorCount); - Format(SystemHeaders[5], GetInstalledMemoryInGigaBytes()); - Format(SystemHeaders[9], Environment.SystemDirectory); - Format(SystemHeaders[10], Environment.CurrentDirectory); - - var maxLineLength = GetMaximumLineLength(builder, sectionIndex); - builder.Insert(sectionIndex, GetSeperator("System", maxLineLength)); - - void Format(string key, object value) - { - builder - .Append(LinePrefix) - .Append(Dot) - .Append(Space) - .AppendFormat(formatter, key) - .Append(Colon) - .Append(Space) - .AppendLine(value.ToString()); - } - } - - private static void AddDrives(StringBuilder builder) - { - var values = new List(); - - foreach (var d in DriveInfo.GetDrives()) - { - var row = new string[7]; - row[0] = d.Name; - row[1] = d.DriveType.ToString(); - - var dashString = Dash.ToString(); - string driveFormat = dashString, volumeLabel = dashString; - double capacity = 0, free = 0, available = 0; - - if (d.IsReady) - { - - driveFormat = d.DriveFormat; - volumeLabel = d.VolumeLabel; - capacity = d.TotalSize.Bytes().Gigabytes; - free = d.TotalFreeSpace.Bytes().Gigabytes; - available = d.AvailableFreeSpace.Bytes().Gigabytes; - } - - row[2] = driveFormat; - row[3] = volumeLabel; - row[4] = capacity.ToString("N0"); - row[5] = free.ToString("N0"); - row[6] = available.ToString("N0"); - - values.Add(row); - } - - WrapInTable(builder, DrivesHeaders, values); - } - - private static void AddNetworking(StringBuilder builder) - { - var result = ProcessHelper.ExecuteAsync("ipconfig", "/all").Result; - - var sectionIndex = builder.Length; - foreach (var entry in result.StandardOutput) - { - var entryLength = entry.Length; - if (entryLength == 0) { continue; } - - builder.Append(LinePrefix); - - var firstChar = entry[0]; - if (firstChar != Space) - { - // Add extra line between the new title and the previous - // lines only if it's not the first title - if (!entry.Equals("Windows IP Configuration", StringComparison.Ordinal)) - { - builder.AppendLine().Append(LinePrefix); - } - - if (entry[entryLength - 1] == Colon) { entryLength = entryLength - 1; } - - builder.Append(Dot).Append(Space); - for (var k = 0; k < entryLength; k++) { builder.Append(entry[k]); } - - builder.AppendLine().Append(LinePrefix); - - builder.Append(Space).Append(Space); - for (var j = 0; j < entryLength; j++) { builder.Append(Dash); } - } - else - { - builder.Append(Space).Append(Space); - - if (entryLength > 4) - { - if (entry[3] == Space) - { - builder.Append(Space).Append(Space); - } - else - { - builder.Append(Dot).Append(Space); - } - - for (var i = 3; i < entryLength; i++) - { - builder.Append(entry[i]); - } - - } - else - { - builder.Append("[Invalid Data]"); - } - } - - builder.AppendLine(); - } - - var maxLineLength = GetMaximumLineLength(builder, sectionIndex); - builder.Insert(sectionIndex, GetSeperator("Networking", maxLineLength)); - } - - private static void AddProcess(StringBuilder builder) - { - var maxHeaderLength = ProcessHeaders.Max(h => h.Length); - var formatter = "{0,-" + (maxHeaderLength + 1) + "}"; - - var sectionIndex = builder.Length; - using (var p = Process.GetCurrentProcess()) - { - var pVerInfo = p.MainModule.FileVersionInfo; - Format(ProcessHeaders[0], p.Id); - Format(ProcessHeaders[1], p.ProcessName); - Format(ProcessHeaders[2], p.StartTime.ToString("dd-MM-yyyy HH:mm:ss.fff")); - Format(ProcessHeaders[3], ApplicationHelper.GetProcessStartupDuration()); - Format(ProcessHeaders[17], Environment.UserInteractive); - Format(ProcessHeaders[4], IsOptimized()); - Format(ProcessHeaders[5], Environment.Is64BitProcess); - Format(ProcessHeaders[6], ApplicationHelper.IsProcessLargeAddressAware()); - Format(ProcessHeaders[16], Environment.WorkingSet.Bytes().Humanize()); - Format(ProcessHeaders[12], pVerInfo.FileVersion); - Format(ProcessHeaders[13], pVerInfo.ProductVersion); - Format(ProcessHeaders[14], pVerInfo.Language); - Format(ProcessHeaders[15], pVerInfo.LegalCopyright); - Format(ProcessHeaders[10], pVerInfo.OriginalFilename); - Format(ProcessHeaders[11], pVerInfo.FileName); - Format(ProcessHeaders[7], p.MainModule.ModuleName); - Format(ProcessHeaders[8], p.MainModule.FileName); - Format(ProcessHeaders[9], pVerInfo.ProductName); - - var cmdArgs = Environment.GetCommandLineArgs(); - Format(ProcessHeaders[18], cmdArgs[0]); - - for (var i = 1; i < cmdArgs.Length; i++) - { - builder - .Append(LinePrefix) - .Append(Space).Append(Space) - .AppendFormat(formatter, string.Empty) - .Append(Space).Append(Space) - .AppendLine(cmdArgs[i]); - } - - var maxLineLength = GetMaximumLineLength(builder, sectionIndex); - builder.Insert(sectionIndex, GetSeperator("Process", maxLineLength)); - - void Format(string key, object value) - { - builder - .Append(LinePrefix) - .Append(Dot) - .Append(Space) - .AppendFormat(formatter, key) - .Append(Colon) - .Append(Space) - .AppendLine(value.ToString()); - } - - string IsOptimized() - { - var executingAssembly = Assembly.GetEntryAssembly(); - return executingAssembly == null - ? "N/A - Assembly was called from Unmanaged code." - : executingAssembly.IsOptimized().ToString(); - } - } - } - - private static void AddAssemblies(StringBuilder builder) - { - var sectionIndex = builder.Length; - - var maxHeaderLength = AssemblyHeaders.Max(h => h.Length); - - var nameFormatter = "{0}{1:D3}{2} {3,-" + (maxHeaderLength + 1) + "}: {4}{5}"; - var formatter = "{0,-" + (maxHeaderLength + 1) + "}"; - - var assCounter = 1; - AppDomain.CurrentDomain.GetAssemblies() - .Where(ass => !ass.IsDynamic) - .OrderByDescending(o => o.GlobalAssemblyCache) - .ForEach(x => - { - builder.AppendFormat(nameFormatter, LinePrefix, assCounter, Pipe, AssemblyHeaders[0], x.FullName, NewLine); - - Format(AssemblyHeaders[1], x.GlobalAssemblyCache); - Format(AssemblyHeaders[2], !x.Is32Bit()); - Format(AssemblyHeaders[3], x.IsOptimized()); - Format(AssemblyHeaders[4], x.GetFrameworkVersion()); - Format(AssemblyHeaders[5], x.Location); - Format(AssemblyHeaders[6], x.CodeBase); - assCounter++; - }); - - var maxLineLength = GetMaximumLineLength(builder, sectionIndex); - builder.Insert(sectionIndex, GetSeperator("Assemblies", maxLineLength)); - - void Format(string key, object value) - { - builder - .Append(LinePrefix) - .Append(Space).Append(Space).Append(Space) - .Append(Dot) - .Append(Space) - .AppendFormat(formatter, key) - .Append(Colon) - .Append(Space) - .AppendLine(value.ToString()); - } - } - - private static void WrapInTable(StringBuilder builder, string[] columnHeaders, List values) - { - foreach (var row in values) - { - if (row.Length != columnHeaders.Length) - { - throw new InvalidDataException("There should be a corresponding data for every column header"); - } - } - - // initialize cellLengths first based on length of the headers - var cellLengths = new int[columnHeaders.Length]; - for (var i = 0; i < columnHeaders.Length; i++) - { - var headerLength = columnHeaders[i].Length; - cellLengths[i] = headerLength; - } - - foreach (var row in values) - { - for (var i = 0; i < columnHeaders.Length; i++) - { - var cellVal = row[i]; - if (cellVal.Length > cellLengths[i]) - { - cellLengths[i] = cellVal.Length; - } - } - } - - for (var i = 0; i < cellLengths.Length; i++) - { - cellLengths[i] = cellLengths[i] + 2; - } - - var headerBuilder = new StringBuilder(); - - // insert headers - headerBuilder.Append(LinePrefix); - for (var i = 0; i < columnHeaders.Length; i++) - { - var headerVal = columnHeaders[i]; - var formatter = "{0} {1,-" + (cellLengths[i] - 2) + "} "; - headerBuilder.AppendFormat(formatter, Pipe, headerVal); - } - headerBuilder.Append(Pipe).AppendLine(); - - // insert headers underline - headerBuilder.Append(LinePrefix); - for (var i = 0; i < columnHeaders.Length; i++) - { - headerBuilder.Append(Pipe).Append(new string(Dash, cellLengths[i])); - } - - var maxLineLengthInHeader = GetMaximumLineLength(headerBuilder); - var beginAndEnd = $"{LinePrefix} {new string(Dash, maxLineLengthInHeader - LinePrefix.Length - 2)}{NewLine}"; - headerBuilder.Insert(0, beginAndEnd); - - var beginPos = builder.Length; - - // insert row values - builder.Append(Pipe).AppendLine(); - foreach (var row in values) - { - builder.Append(LinePrefix); - for (var j = 0; j < row.Length; j++) - { - var formatter = "{0} {1,-" + (cellLengths[j] - 2) + "} "; - builder.AppendFormat(formatter, Pipe, row[j]); - } - builder.Append(Pipe).AppendLine(); - } - - builder.Insert(beginPos, headerBuilder.ToString()); - builder.Append(beginAndEnd); - - var maxLineLength = GetMaximumLineLength(builder, beginPos); - builder.Insert(beginPos, GetSeperator("Drives", maxLineLength)); - } - - private static int GetMaximumLineLength(StringBuilder builder, int start = 0) - { - if (start >= builder.Length) { throw new IndexOutOfRangeException(); } - - int maxLength = 0, tmpLength = 0; - var prevChar = '\0'; - - for (var i = start; i < builder.Length; i++) - { - var currChar = builder[i]; - - if (currChar == '\n') - { - if (prevChar == '\r') { --tmpLength; } - if (maxLength < tmpLength) { maxLength = tmpLength; } - tmpLength = 0; - } - else { tmpLength++; } - - prevChar = currChar; - } - return maxLength; - } - - /// - /// Returns the full CPU name using the registry. - /// See - /// - /// The CPU Name - private static string GetProcessorName() - { - var key = Registry.LocalMachine.OpenSubKey(@"HARDWARE\DESCRIPTION\System\CentralProcessor\0\"); - return key?.GetValue("ProcessorNameString").ToString() ?? "Not Found"; - } - - private static string GetInstalledMemoryInGigaBytes() - { - GetPhysicallyInstalledSystemMemory(out var installedMemoryKb); - return installedMemoryKb.Bytes().Humanize(); - } - - private static string GetSeperator(string title, int count) - { - return $"{Pipe}{NewLine}{Pipe}{title}{Pipe}{new string(Dot, count - title.Length)}{NewLine}{Pipe}{NewLine}"; - } - - /// - /// - /// - [DllImport("kernel32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool GetPhysicallyInstalledSystemMemory(out long totalMemoryInKilobytes); - } -} diff --git a/src/Maple.Core/DiagnosticReportType.cs b/src/Maple.Core/DiagnosticReportType.cs deleted file mode 100644 index 7537fd2..0000000 --- a/src/Maple.Core/DiagnosticReportType.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; - -namespace Maple.Core -{ - /// - /// Represents the different types of report which can - /// be generated by . - /// - /// Reports can be mixed as: - /// - /// DiagnosticReportType.System | DiagnosticReportType.Process - /// - /// - /// - [Flags] - public enum DiagnosticReportType - { - /// - /// Includes details about the System. - /// - System = 1, - - /// - /// Includes details about the Process. - /// - Process = 2, - - /// - /// Includes details about the Drives. - /// - Drives = 4, - - /// - /// Includes details about the referenced Assemblies. - /// - Assemblies = 8, - - /// - /// Includes details about the Networking. - /// - Networking = 16, - - /// - /// Generates the full report. - /// - Full = System | Process | Drives | Assemblies | Networking - } -} diff --git a/src/Maple.Core/DispatcherFactory.cs b/src/Maple.Core/DispatcherFactory.cs deleted file mode 100644 index 792347d..0000000 --- a/src/Maple.Core/DispatcherFactory.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Windows.Threading; - -namespace Maple.Core -{ - public static class DispatcherFactory - { - /// - /// Gets the dispatcher. - /// - /// - public static Dispatcher GetDispatcher() - { - return Dispatcher.CurrentDispatcher; - } - - /// - /// Invokes the specified action. - /// - /// The action. - public static void Invoke(Action action) - { - var dispatcher = GetDispatcher(); - - if (dispatcher.CheckAccess()) - action(); - else - dispatcher.BeginInvoke(action); - } - - /// - /// Invokes the specified action. - /// - /// - /// The action. - /// The parameter. - /// The priority. - public static void Invoke(Action action, T parameter, DispatcherPriority priority = DispatcherPriority.Normal) - { - var dispatcher = GetDispatcher(); - - if (dispatcher.CheckAccess()) - action?.Invoke(parameter); - else - dispatcher.BeginInvoke(action, priority, parameter); - } - } -} diff --git a/src/Maple.Core/DynamicDictionary.cs b/src/Maple.Core/DynamicDictionary.cs deleted file mode 100644 index 471ce19..0000000 --- a/src/Maple.Core/DynamicDictionary.cs +++ /dev/null @@ -1,219 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Dynamic; - -namespace Maple.Core -{ - /// - /// Provides an abstraction for an object to be used dynamically as a key value pair - /// where the property is the key and value is an . - /// - public sealed class DynamicDictionary : DynamicObject, IDictionary - { - private readonly IDictionary _dictionary; - - /// - /// Creates a new instance of . - /// - /// - /// The flag indicating whether keys should be treated regardless of the case. - /// - [DebuggerStepThrough] - public DynamicDictionary(bool ignoreCase = true) - { - _dictionary = new Dictionary( - ignoreCase ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal); - } - - /// - /// Add the given to this instance. - /// - /// - public void Add(KeyValuePair item) - { - _dictionary.Add(item); - } - - /// - /// Removes all the items from this instance. - /// - public void Clear() - { - _dictionary.Clear(); - } - - /// - /// Determines whether this instance contains the given . - /// - public bool Contains(KeyValuePair item) - { - return _dictionary.Contains(item); - } - - /// - /// Copies the elements of this instance to the given , starting at a particular . - /// - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - _dictionary.CopyTo(array, arrayIndex); - } - - /// - /// Removes the given from this instance. - /// - public bool Remove(KeyValuePair item) - { - return _dictionary.Remove(item); - } - - /// - /// Gets the number of elements contained in this instance. - /// - public int Count => _dictionary.Keys.Count; - - /// - /// Determines whether this instance is Read-Only. - /// - public bool IsReadOnly => _dictionary.IsReadOnly; - - /// - /// Returns an enumerator that iterates through the keys and values of this instance. - /// - public IEnumerator> GetEnumerator() - { - return _dictionary.GetEnumerator(); - } - - /// - /// Returns an enumerator that iterates through the keys and values of this instance. - /// - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// Determines whether this instance contains an element with the given . - /// - public bool ContainsKey(string key) - { - return _dictionary.ContainsKey(key); - } - - /// - /// Adds an element for the given and associated to this instance. - /// - public void Add(string key, object value) - { - _dictionary.Add(key, value); - } - - /// - /// Removes the element with the given from this instance. - /// - public bool Remove(string key) - { - return _dictionary.Remove(key); - } - - /// - /// Attempts to get the value associated to the given . - /// - public bool TryGetValue(string key, out object value) - { - return _dictionary.TryGetValue(key, out value); - } - - /// - /// Gets or sets the value stored against the given . - /// If the given does not exist, NULL is returned. - /// - public object this[string key] - { - get - { - _dictionary.TryGetValue(key, out var result); - return result; - } - - set { _dictionary[key] = value; } - } - - /// - /// Gets an containing the keys of this instance. - /// - public ICollection Keys => _dictionary.Keys; - - /// - /// Gets an containing the values of this instance. - /// - public ICollection Values => _dictionary.Values; - - /// - /// Attempts to get the member. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public override bool TryGetMember(GetMemberBinder binder, out object result) - { - if (_dictionary.ContainsKey(binder.Name)) - { - result = _dictionary[binder.Name]; - return true; - } - - if (base.TryGetMember(binder, out result)) - { - return true; - } - - // always return null if not found. - result = null; - return true; - } - - /// - /// Attempts to set the member. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public override bool TrySetMember(SetMemberBinder binder, object result) - { - if (!_dictionary.ContainsKey(binder.Name)) { _dictionary.Add(binder.Name, result); } - else { _dictionary[binder.Name] = result; } - return true; - } - - /// - /// Attempts to invoke the member. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) - { - if (_dictionary.ContainsKey(binder.Name) && _dictionary[binder.Name] is Delegate) - { - var del = (Delegate)_dictionary[binder.Name]; - result = del.DynamicInvoke(args); - return true; - } - - return base.TryInvokeMember(binder, args, out result); - } - - /// - /// Attempts to delete the member. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public override bool TryDeleteMember(DeleteMemberBinder binder) - { - if (_dictionary.ContainsKey(binder.Name)) - { - _dictionary.Remove(binder.Name); - return true; - } - - return base.TryDeleteMember(binder); - } - } -} diff --git a/src/Maple.Core/Ensure.cs b/src/Maple.Core/Ensure.cs deleted file mode 100644 index 84c7945..0000000 --- a/src/Maple.Core/Ensure.cs +++ /dev/null @@ -1,241 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - /// - /// Helper class that will exceptions when conditions are not satisfied. - /// - public static class Ensure - { - /// - /// Ensures that the given expression is . - /// - /// Type of exception to throw - /// Condition to test/ensure - /// Message for the exception - /// - /// Thrown when TException is . - /// - [DebuggerStepThrough] - public static void That(bool condition, string message = default(string)) - where TException : Exception - { - if (!condition) - { - if (string.IsNullOrEmpty(message)) - message = Resources.ExceptionMessageFalseCondition; - - throw (TException)Activator.CreateInstance(typeof(TException), message); - } - } - - /// - /// Ensures given is . - /// - /// Condition to test - /// Message for the exception - /// - /// Thrown when is . - /// - [DebuggerStepThrough] - public static void That(bool condition, string message = default(string)) - { - if (string.IsNullOrEmpty(message)) - message = Resources.ExceptionMessageFalseCondition; - - That(condition, message); - } - - /// - /// Ensures given is . - /// - /// Type of exception to throw - /// Condition to test - /// Message for the exception - /// - /// Thrown when is . - /// - [DebuggerStepThrough] - public static void Not(bool condition, string message = default(string)) - where TException : Exception - { - if (string.IsNullOrEmpty(message)) - message = Resources.ExceptionMessageTrueCondition; - - That(!condition, message); - } - - /// - /// Ensures given is . - /// - /// Condition to test - /// Message for the exception - /// - /// Thrown when is . - /// - [DebuggerStepThrough] - public static void Not(bool condition, string message = default(string)) - { - if (string.IsNullOrEmpty(message)) - message = Resources.ExceptionMessageFalseCondition; - - Not(condition, message); - } - - /// - /// Ensures given is not null. - /// - /// Type of the given . - /// Value of the to check for reference. - /// Name of the argument. - /// - /// Thrown when is null - /// - /// The . - [DebuggerStepThrough] - public static T NotNull(T value, string argName) - where T : class - { - if (argName.IsNullOrEmptyOrWhiteSpace()) - { - argName = "Invalid"; - } - - That(value != null, argName); - return value; - } - - /// - /// Ensures given objects are equal. - /// - /// Type of objects to compare for equality - /// The left item - /// The right item - /// Message for the exception - /// - /// Thrown when not equal to - /// - /// Null values will cause an exception to be thrown - [DebuggerStepThrough] - public static void Equal(T left, T right, string message = default(string)) - { - if (string.IsNullOrEmpty(message)) - message = Resources.ExceptionMessageEqualValues; - - That(left.Equals(right), message); - } - - /// - /// Ensures given objects are not equal. - /// - /// Type of objects to compare for equality - /// The left item - /// The right item - /// Message for the exception - /// - /// Thrown when equal to - /// - /// Null values will cause an exception to be thrown - [DebuggerStepThrough] - public static void NotEqual(T left, T right, string message = default(string)) - { - if (string.IsNullOrEmpty(message)) - message = Resources.ExceptionMessageNotEqualValues; - - That(!left.Equals(right), message); - } - - /// - /// Ensures a given is not null or empty. - /// - /// Collection type. - /// Collection to check. - /// Message for the exception - /// The evaluated collection. - /// - /// Thrown when is null. - /// - /// - /// Thrown when is empty. - /// - [DebuggerStepThrough] - public static ICollection NotNullOrEmpty(ICollection collection, string message = default(string)) - { - if (string.IsNullOrEmpty(message)) - message = Resources.ExceptionMessageCollectionNullOrEmpty; - - NotNull(collection, nameof(collection)); - Not(!collection.Any(), message); - return collection; - } - - /// - /// Ensures the given string is not or empty or whitespace. - /// - /// String to check. - /// Message for the exception - /// Value to return if it is not null, empty or whitespace. - /// - /// Thrown when is null or empty or whitespace. - /// - [DebuggerStepThrough] - public static string NotNullOrEmptyOrWhiteSpace(string value, string message = default(string)) - { - if (string.IsNullOrEmpty(message)) - message = Resources.ExceptionMessageStringNullEmpyOrWhiteSpace; - - That(value.IsNotNullOrEmptyOrWhiteSpace(), message); - return value; - } - - /// - /// Ensures given exists. - /// - /// DirectoryInfo object representing the directory to check for existence. - /// DirectoryInfo to return if the directory exists. - /// - /// Thrown when is null. - /// - /// - /// Thrown when is not found. - /// - /// - /// A device such as a disk drive is not ready. - /// - [DebuggerStepThrough] - public static DirectoryInfo Exists(DirectoryInfo directoryInfo) - { - NotNull(directoryInfo, nameof(directoryInfo)); - - directoryInfo.Refresh(); - That(directoryInfo.Exists, Resources.ExceptionMessageMissingDirectory + directoryInfo.FullName); - return directoryInfo; - } - - /// - /// Ensures given exists. - /// - /// FileInfo object representing the file to check for existence. - /// FileInfo to return if the file exists. - /// - /// Thrown when is null. - /// - /// - /// Thrown when does not exist. - /// - [DebuggerStepThrough] - public static FileInfo Exists(FileInfo fileInfo) - { - NotNull(fileInfo, nameof(fileInfo)); - - fileInfo.Refresh(); - That(fileInfo.Exists, Resources.ExceptionMessageMissingFile + fileInfo.FullName); - return fileInfo; - } - } -} diff --git a/src/Maple.Core/EventAggregator/DefaultMessageProxy.cs b/src/Maple.Core/EventAggregator/DefaultMessageProxy.cs deleted file mode 100644 index e09e254..0000000 --- a/src/Maple.Core/EventAggregator/DefaultMessageProxy.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Maple.Core -{ - /// - /// Default "pass through" proxy. - /// - /// Does nothing other than deliver the message. - /// - public sealed class DefaultMessageProxy : IMapleMessageProxy - { - public void Deliver(IMapleMessage message, IMapleMessageSubscription subscription) - { - subscription.Deliver(message); - } - } -} diff --git a/src/Maple.Core/EventAggregator/Interfaces/IMapleMessage.cs b/src/Maple.Core/EventAggregator/Interfaces/IMapleMessage.cs deleted file mode 100644 index 6e413ff..0000000 --- a/src/Maple.Core/EventAggregator/Interfaces/IMapleMessage.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Maple.Core -{ - /// - /// A TinyMessage to be published/delivered by TinyMessenger - /// - public interface IMapleMessage - { - /// - /// The sender of the message, or null if not supported by the message implementation. - /// - object Sender { get; } - } -} diff --git a/src/Maple.Core/EventAggregator/Interfaces/IMapleMessageProxy.cs b/src/Maple.Core/EventAggregator/Interfaces/IMapleMessageProxy.cs deleted file mode 100644 index 1ff9f98..0000000 --- a/src/Maple.Core/EventAggregator/Interfaces/IMapleMessageProxy.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Maple.Core -{ - /// - /// Message proxy definition. - /// - /// A message proxy can be used to intercept/alter messages and/or - /// marshall delivery actions onto a particular thread. - /// - public interface IMapleMessageProxy - { - void Deliver(IMapleMessage message, IMapleMessageSubscription subscription); - } -} diff --git a/src/Maple.Core/EventAggregator/Interfaces/IMapleMessageSubscription.cs b/src/Maple.Core/EventAggregator/Interfaces/IMapleMessageSubscription.cs deleted file mode 100644 index fac12b4..0000000 --- a/src/Maple.Core/EventAggregator/Interfaces/IMapleMessageSubscription.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace Maple.Core -{ - /// - /// Represents a message subscription - /// - public interface IMapleMessageSubscription - { - /// - /// Token returned to the subscribed to reference this subscription - /// - SubscriptionToken SubscriptionToken { get; } - - /// - /// Whether delivery should be attempted. - /// - /// Message that may potentially be delivered. - /// True - ok to send, False - should not attempt to send - bool ShouldAttemptDelivery(IMapleMessage message); - - /// - /// Deliver the message - /// - /// Message to deliver - void Deliver(IMapleMessage message); - } -} diff --git a/src/Maple.Core/EventAggregator/Interfaces/IMessenger.cs b/src/Maple.Core/EventAggregator/Interfaces/IMessenger.cs deleted file mode 100644 index 49beff9..0000000 --- a/src/Maple.Core/EventAggregator/Interfaces/IMessenger.cs +++ /dev/null @@ -1,139 +0,0 @@ -using System; - -namespace Maple.Core -{ - /// - /// Messenger hub responsible for taking subscriptions/publications and delivering of messages. - /// - public interface IMessenger - { - /// - /// Subscribe to a message type with the given destination and delivery action. - /// All references are held with WeakReferences - /// - /// All messages of this type will be delivered. - /// - /// Type of message - /// Action to invoke when message is delivered - /// TinyMessageSubscription used to unsubscribing - SubscriptionToken Subscribe(Action deliveryAction) where TMessage : class, IMapleMessage; - - /// - /// Subscribe to a message type with the given destination and delivery action. - /// Messages will be delivered via the specified proxy. - /// All references (apart from the proxy) are held with WeakReferences - /// - /// All messages of this type will be delivered. - /// - /// Type of message - /// Action to invoke when message is delivered - /// Proxy to use when delivering the messages - /// TinyMessageSubscription used to unsubscribing - SubscriptionToken Subscribe(Action deliveryAction, IMapleMessageProxy proxy) where TMessage : class, IMapleMessage; - - /// - /// Subscribe to a message type with the given destination and delivery action. - /// - /// All messages of this type will be delivered. - /// - /// Type of message - /// Action to invoke when message is delivered - /// Use strong references to destination and deliveryAction - /// TinyMessageSubscription used to unsubscribing - SubscriptionToken Subscribe(Action deliveryAction, bool useStrongReferences) where TMessage : class, IMapleMessage; - - /// - /// Subscribe to a message type with the given destination and delivery action. - /// Messages will be delivered via the specified proxy. - /// - /// All messages of this type will be delivered. - /// - /// Type of message - /// Action to invoke when message is delivered - /// Use strong references to destination and deliveryAction - /// Proxy to use when delivering the messages - /// TinyMessageSubscription used to unsubscribing - SubscriptionToken Subscribe(Action deliveryAction, bool useStrongReferences, IMapleMessageProxy proxy) where TMessage : class, IMapleMessage; - - /// - /// Subscribe to a message type with the given destination and delivery action with the given filter. - /// All references are held with WeakReferences - /// - /// Only messages that "pass" the filter will be delivered. - /// - /// Type of message - /// Action to invoke when message is delivered - /// TinyMessageSubscription used to unsubscribing - SubscriptionToken Subscribe(Action deliveryAction, Func messageFilter) where TMessage : class, IMapleMessage; - - /// - /// Subscribe to a message type with the given destination and delivery action with the given filter. - /// Messages will be delivered via the specified proxy. - /// All references (apart from the proxy) are held with WeakReferences - /// - /// Only messages that "pass" the filter will be delivered. - /// - /// Type of message - /// Action to invoke when message is delivered - /// Proxy to use when delivering the messages - /// TinyMessageSubscription used to unsubscribing - SubscriptionToken Subscribe(Action deliveryAction, Func messageFilter, IMapleMessageProxy proxy) where TMessage : class, IMapleMessage; - - /// - /// Subscribe to a message type with the given destination and delivery action with the given filter. - /// All references are held with WeakReferences - /// - /// Only messages that "pass" the filter will be delivered. - /// - /// Type of message - /// Action to invoke when message is delivered - /// Use strong references to destination and deliveryAction - /// TinyMessageSubscription used to unsubscribing - SubscriptionToken Subscribe(Action deliveryAction, Func messageFilter, bool useStrongReferences) where TMessage : class, IMapleMessage; - - /// - /// Subscribe to a message type with the given destination and delivery action with the given filter. - /// Messages will be delivered via the specified proxy. - /// All references are held with WeakReferences - /// - /// Only messages that "pass" the filter will be delivered. - /// - /// Type of message - /// Action to invoke when message is delivered - /// Use strong references to destination and deliveryAction - /// Proxy to use when delivering the messages - /// TinyMessageSubscription used to unsubscribing - SubscriptionToken Subscribe(Action deliveryAction, Func messageFilter, bool useStrongReferences, IMapleMessageProxy proxy) where TMessage : class, IMapleMessage; - - /// - /// Unsubscribe from a particular message type. - /// - /// Does not throw an exception if the subscription is not found. - /// - /// Type of message - /// Subscription token received from Subscribe - void Unsubscribe(SubscriptionToken subscriptionToken) where TMessage : class, IMapleMessage; - - /// - /// Publish a message to any subscribers - /// - /// Type of message - /// Message to deliver - void Publish(TMessage message) where TMessage : class, IMapleMessage; - - /// - /// Publish a message to any subscribers asynchronously - /// - /// Type of message - /// Message to deliver - void PublishAsync(TMessage message) where TMessage : class, IMapleMessage; - - /// - /// Publish a message to any subscribers asynchronously - /// - /// Type of message - /// Message to deliver - /// AsyncCallback called on completion - void PublishAsync(TMessage message, AsyncCallback callback) where TMessage : class, IMapleMessage; - } -} diff --git a/src/Maple.Core/EventAggregator/Interfaces/ISubscriberErrorHandler.cs b/src/Maple.Core/EventAggregator/Interfaces/ISubscriberErrorHandler.cs deleted file mode 100644 index 689116e..0000000 --- a/src/Maple.Core/EventAggregator/Interfaces/ISubscriberErrorHandler.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace Maple.Core -{ - public interface ISubscriberErrorHandler - { - void Handle(IMapleMessage message, Exception exception); - } -} diff --git a/src/Maple.Core/EventAggregator/MapleMessenger.cs b/src/Maple.Core/EventAggregator/MapleMessenger.cs deleted file mode 100644 index c00fd6c..0000000 --- a/src/Maple.Core/EventAggregator/MapleMessenger.cs +++ /dev/null @@ -1,174 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - public sealed partial class MapleMessenger : IMessenger - { - private readonly object _SubscriptionsPadlock = new object(); - private readonly List _subscriptions = new List(); - - private readonly IMapleMessageProxy _mapleMessageProxy; - private readonly ITranslationProvider _translationProvider; - private readonly ILoggingService _log; - - public MapleMessenger(ITranslationProvider translationProvider, ILoggingService log, IMapleMessageProxy mapleMessageProxy) - { - _translationProvider = translationProvider ?? throw new ArgumentNullException(nameof(translationProvider), $"{nameof(translationProvider)} {Resources.IsRequired}"); - _log = log ?? throw new ArgumentNullException(nameof(log), $"{nameof(log)} {Resources.IsRequired}"); - _mapleMessageProxy = mapleMessageProxy ?? throw new ArgumentNullException(nameof(mapleMessageProxy), $"{nameof(mapleMessageProxy)} {Resources.IsRequired}"); - } - - public SubscriptionToken Subscribe(Action deliveryAction) - where TMessage : class, IMapleMessage - { - return AddSubscriptionInternal(deliveryAction, (m) => true, true, _mapleMessageProxy); - } - - public SubscriptionToken Subscribe(Action deliveryAction, IMapleMessageProxy proxy) - where TMessage : class, IMapleMessage - { - return AddSubscriptionInternal(deliveryAction, (m) => true, true, proxy); - } - - public SubscriptionToken Subscribe(Action deliveryAction, bool useStrongReferences) - where TMessage : class, IMapleMessage - { - return AddSubscriptionInternal(deliveryAction, (m) => true, useStrongReferences, _mapleMessageProxy); - } - - public SubscriptionToken Subscribe(Action deliveryAction, bool useStrongReferences, IMapleMessageProxy proxy) - where TMessage : class, IMapleMessage - { - return AddSubscriptionInternal(deliveryAction, (m) => true, useStrongReferences, proxy); - } - - public SubscriptionToken Subscribe(Action deliveryAction, Func messageFilter) - where TMessage : class, IMapleMessage - { - return AddSubscriptionInternal(deliveryAction, messageFilter, true, _mapleMessageProxy); - } - - public SubscriptionToken Subscribe(Action deliveryAction, Func messageFilter, IMapleMessageProxy proxy) - where TMessage : class, IMapleMessage - { - return AddSubscriptionInternal(deliveryAction, messageFilter, true, proxy); - } - - public SubscriptionToken Subscribe(Action deliveryAction, Func messageFilter, bool useStrongReferences) - where TMessage : class, IMapleMessage - { - return AddSubscriptionInternal(deliveryAction, messageFilter, useStrongReferences, _mapleMessageProxy); - } - - public SubscriptionToken Subscribe(Action deliveryAction, Func messageFilter, bool useStrongReferences, IMapleMessageProxy proxy) - where TMessage : class, IMapleMessage - { - return AddSubscriptionInternal(deliveryAction, messageFilter, useStrongReferences, proxy); - } - - public void Unsubscribe(SubscriptionToken subscriptionToken) - where TMessage : class, IMapleMessage - { - RemoveSubscriptionInternal(subscriptionToken); - } - - public void Publish(TMessage message) - where TMessage : class, IMapleMessage - { - PublishInternal(message); - } - - public void PublishAsync(TMessage message) - where TMessage : class, IMapleMessage - { - PublishAsyncInternal(message, null); - } - - public void PublishAsync(TMessage message, AsyncCallback callback) - where TMessage : class, IMapleMessage - { - PublishAsyncInternal(message, callback); - } - - private SubscriptionToken AddSubscriptionInternal(Action deliveryAction, Func messageFilter, bool strongReference, IMapleMessageProxy proxy) - where TMessage : class, IMapleMessage - { - if (deliveryAction == null) - throw new ArgumentNullException(nameof(deliveryAction), $"{nameof(deliveryAction)} {Resources.IsRequired}"); - - if (messageFilter == null) - throw new ArgumentNullException(nameof(messageFilter), $"{nameof(messageFilter)} {Resources.IsRequired}"); - - if (proxy == null) - throw new ArgumentNullException(nameof(proxy), $"{nameof(proxy)} {Resources.IsRequired}"); - - lock (_SubscriptionsPadlock) - { - var subscriptionToken = new SubscriptionToken(this, typeof(TMessage)); - - IMapleMessageSubscription subscription; - if (strongReference) - subscription = new StrongMapleMessageSubscription(_translationProvider, subscriptionToken, deliveryAction, messageFilter); - else - subscription = new WeakMapleMessageSubscription(_translationProvider, subscriptionToken, deliveryAction, messageFilter); - - _subscriptions.Add(new SubscriptionItem(proxy, subscription)); - - return subscriptionToken; - } - } - - private void RemoveSubscriptionInternal(SubscriptionToken subscriptionToken) - where TMessage : class, IMapleMessage - { - if (subscriptionToken == null) - throw new ArgumentNullException(nameof(subscriptionToken), $"{nameof(subscriptionToken)} {Resources.IsRequired}"); - - lock (_SubscriptionsPadlock) - { - var currentlySubscribed = (from sub in _subscriptions - where ReferenceEquals(sub.Subscription.SubscriptionToken, subscriptionToken) - select sub).ToList(); - - currentlySubscribed.ForEach(sub => _subscriptions.Remove(sub)); - } - } - - private void PublishInternal(TMessage message) - where TMessage : class, IMapleMessage - { - if (message == null) - throw new ArgumentNullException(nameof(message), $"{nameof(message)} {Resources.IsRequired}"); - - List currentlySubscribed; - lock (_SubscriptionsPadlock) - { - currentlySubscribed = (from sub in _subscriptions - where sub.Subscription.ShouldAttemptDelivery(message) - select sub).ToList(); - } - - currentlySubscribed.ForEach(sub => - { - try - { - sub.Proxy.Deliver(message, sub.Subscription); - } - catch (Exception exception) - { - _log.Error(message, exception); - } - }); - } - - private void PublishAsyncInternal(TMessage message, AsyncCallback callback) - where TMessage : class, IMapleMessage - { - ((Action)(() => { PublishInternal(message); })).BeginInvoke(callback, null); - } - } -} diff --git a/src/Maple.Core/EventAggregator/MapleMessengerSubscriptionException.cs b/src/Maple.Core/EventAggregator/MapleMessengerSubscriptionException.cs deleted file mode 100644 index 0b91ea1..0000000 --- a/src/Maple.Core/EventAggregator/MapleMessengerSubscriptionException.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Runtime.Serialization; - -namespace Maple.Core -{ - /// - /// Thrown when an exceptions occurs while subscribing to a message type - /// - [Serializable] - public class MapleMessengerSubscriptionException : Exception - { - private const string ERROR_TEXT = "Unable to add subscription for {0} : {1}"; - - public MapleMessengerSubscriptionException(Type messageType, string reason) - : base(string.Format(ERROR_TEXT, messageType, reason)) - { - } - - public MapleMessengerSubscriptionException(Type messageType, string reason, Exception innerException) - : base(string.Format(ERROR_TEXT, messageType, reason), innerException) - { - } - - public MapleMessengerSubscriptionException() - { - } - - public MapleMessengerSubscriptionException(string message) : base(message) - { - } - - public MapleMessengerSubscriptionException(string message, Exception innerException) : base(message, innerException) - { - } - - protected MapleMessengerSubscriptionException(SerializationInfo serializationInfo, StreamingContext streamingContext) - : base(serializationInfo, streamingContext) - { - } - } -} diff --git a/src/Maple.Core/EventAggregator/Messages/CancellableGenericMapleMessage.cs b/src/Maple.Core/EventAggregator/Messages/CancellableGenericMapleMessage.cs deleted file mode 100644 index e93d7b9..0000000 --- a/src/Maple.Core/EventAggregator/Messages/CancellableGenericMapleMessage.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - /// - /// Basic "cancellable" generic message - /// - /// Content type to store - public class CancellableGenericMapleMessage : MapleMessageBase - { - /// - /// Cancel action - /// - public Action Cancel { get; protected set; } - - /// - /// Contents of the message - /// - public TContent Content { get; protected set; } - - /// - /// Create a new instance of the CancellableGenericTinyMessage class. - /// - /// Message sender (usually "this") - /// Contents of the message - /// Action to call for cancellation - public CancellableGenericMapleMessage(object sender, TContent content, Action cancelAction) - : base(sender) - { - Content = content; - Cancel = cancelAction ?? throw new ArgumentNullException(nameof(cancelAction), $"{nameof(cancelAction)} {Resources.IsRequired}"); - } - } -} diff --git a/src/Maple.Core/EventAggregator/Messages/GenericMapleMessage.cs b/src/Maple.Core/EventAggregator/Messages/GenericMapleMessage.cs deleted file mode 100644 index f5861b5..0000000 --- a/src/Maple.Core/EventAggregator/Messages/GenericMapleMessage.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Maple.Core -{ - /// - /// Generic message with user specified content - /// - /// Content type to store - public class GenericMapleMessage : MapleMessageBase - { - /// - /// Contents of the message - /// - public TContent Content { get; protected set; } - - public GenericMapleMessage(object sender, TContent content) - : base(sender) - { - Content = content; - } - } -} diff --git a/src/Maple.Core/EventAggregator/Messages/MapleMessageBase.cs b/src/Maple.Core/EventAggregator/Messages/MapleMessageBase.cs deleted file mode 100644 index b043fef..0000000 --- a/src/Maple.Core/EventAggregator/Messages/MapleMessageBase.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - /// - /// Base class for messages that provides weak refrence storage of the sender - /// - public abstract class MapleMessageBase : IMapleMessage - { - /// - /// Store a WeakReference to the sender just in case anyone is daft enough to - /// keep the message around and prevent the sender from being collected. - /// - private WeakReference _sender; - public object Sender - { - get - { - return _sender?.Target; - } - } - - protected MapleMessageBase(object sender) - { - if (sender == null) - throw new ArgumentNullException(nameof(sender), $"{nameof(sender)} {Resources.IsRequired}"); - - _sender = new WeakReference(sender); - } - } -} diff --git a/src/Maple.Core/EventAggregator/SubscriptionToken.cs b/src/Maple.Core/EventAggregator/SubscriptionToken.cs deleted file mode 100644 index 5eaaf0b..0000000 --- a/src/Maple.Core/EventAggregator/SubscriptionToken.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; - -namespace Maple.Core -{ - /// - /// Represents an active subscription to a message - /// - public sealed class SubscriptionToken : IDisposable - { - private readonly WeakReference _hub; - private readonly Type _messageType; - - public SubscriptionToken(IMessenger hub, Type messageType) - { - if (hub == null) - throw new ArgumentNullException(nameof(hub)); - - if (!typeof(IMapleMessage).IsAssignableFrom(messageType)) - throw new ArgumentOutOfRangeException(nameof(messageType)); - - _hub = new WeakReference(hub); - _messageType = messageType; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (disposing) - { - // free managed resources - if (_hub.IsAlive && _hub.Target is IMessenger hub) - { - var unsubscribeMethod = typeof(IMessenger).GetMethod("Unsubscribe", new Type[] { typeof(SubscriptionToken) }); - unsubscribeMethod = unsubscribeMethod.MakeGenericMethod(_messageType); - unsubscribeMethod.Invoke(hub, new object[] { this }); - } - } - // free native resources if there are any. - } - } -} diff --git a/src/Maple.Core/EventAggregator/Subscriptions/StrongMapleMessageSubscription.cs b/src/Maple.Core/EventAggregator/Subscriptions/StrongMapleMessageSubscription.cs deleted file mode 100644 index d8583bf..0000000 --- a/src/Maple.Core/EventAggregator/Subscriptions/StrongMapleMessageSubscription.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - internal class StrongMapleMessageSubscription : IMapleMessageSubscription - where TMessage : class, IMapleMessage - { - private readonly ITranslationProvider _translationProvider; - - protected Action DeliveryAction { get; set; } - protected Func MessageFilter { get; set; } - - public SubscriptionToken SubscriptionToken { get; } - - public bool ShouldAttemptDelivery(IMapleMessage message) - { - if (message == null) - return false; - - if (!(typeof(TMessage).IsAssignableFrom(message.GetType()))) - return false; - - return MessageFilter.Invoke(message as TMessage); - } - - public void Deliver(IMapleMessage message) - { - if (!(message is TMessage)) - throw new ArgumentException("Message is not the correct type"); // TODO translate - - DeliveryAction.Invoke(message as TMessage); - } - - public StrongMapleMessageSubscription(ITranslationProvider translationProvider, SubscriptionToken subscriptionToken, Action deliveryAction, Func messageFilter) - { - SubscriptionToken = subscriptionToken ?? throw new ArgumentNullException(nameof(subscriptionToken), $"{nameof(subscriptionToken)} {Resources.IsRequired}"); - DeliveryAction = deliveryAction ?? throw new ArgumentNullException(nameof(deliveryAction), $"{nameof(deliveryAction)} {Resources.IsRequired}"); - MessageFilter = messageFilter ?? throw new ArgumentNullException(nameof(messageFilter), $"{nameof(messageFilter)} {Resources.IsRequired}"); - - _translationProvider = translationProvider ?? throw new ArgumentNullException(nameof(translationProvider), $"{nameof(translationProvider)} {Resources.IsRequired}"); - } - } -} diff --git a/src/Maple.Core/EventAggregator/Subscriptions/SubscriptionItem.cs b/src/Maple.Core/EventAggregator/Subscriptions/SubscriptionItem.cs deleted file mode 100644 index f493e8c..0000000 --- a/src/Maple.Core/EventAggregator/Subscriptions/SubscriptionItem.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Maple.Core -{ - internal class SubscriptionItem - { - public IMapleMessageProxy Proxy { get; private set; } - public IMapleMessageSubscription Subscription { get; private set; } - - public SubscriptionItem(IMapleMessageProxy proxy, IMapleMessageSubscription subscription) - { - Proxy = proxy; - Subscription = subscription; - } - } -} diff --git a/src/Maple.Core/EventAggregator/Subscriptions/WeakMapleMessageSubscription.cs b/src/Maple.Core/EventAggregator/Subscriptions/WeakMapleMessageSubscription.cs deleted file mode 100644 index 316d7b5..0000000 --- a/src/Maple.Core/EventAggregator/Subscriptions/WeakMapleMessageSubscription.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - internal class WeakMapleMessageSubscription : IMapleMessageSubscription - where TMessage : class, IMapleMessage - { - private readonly ITranslationProvider _translationProvider; - - protected WeakReference DeliveryAction { get; set; } - protected WeakReference MessageFilter { get; set; } - - public SubscriptionToken SubscriptionToken { get; } - - public bool ShouldAttemptDelivery(IMapleMessage message) - { - if (message == null) - return false; - - if (!(typeof(TMessage).IsAssignableFrom(message.GetType()))) - return false; - - if (!DeliveryAction.IsAlive) - return false; - - if (!MessageFilter.IsAlive) - return false; - - return ((Func)MessageFilter.Target).Invoke(message as TMessage); - } - - public void Deliver(IMapleMessage message) - { - if (!(message is TMessage)) - throw new ArgumentException("Message is not the correct type"); // TODO translate - - if (!DeliveryAction.IsAlive) - return; - - ((Action)DeliveryAction.Target).Invoke(message as TMessage); - } - - public WeakMapleMessageSubscription(ITranslationProvider translationProvider, SubscriptionToken subscriptionToken, Action deliveryAction, Func messageFilter) - { - if (deliveryAction == null) - throw new ArgumentNullException(nameof(deliveryAction), $"{nameof(deliveryAction)} {Resources.IsRequired}"); - - if (messageFilter == null) - throw new ArgumentNullException(nameof(messageFilter), $"{nameof(messageFilter)} {Resources.IsRequired}"); - - _translationProvider = translationProvider ?? throw new ArgumentNullException(nameof(translationProvider), $"{nameof(translationProvider)} {Resources.IsRequired}"); - - SubscriptionToken = subscriptionToken ?? throw new ArgumentNullException(nameof(subscriptionToken), $"{nameof(subscriptionToken)} {Resources.IsRequired}"); - DeliveryAction = new WeakReference(deliveryAction); - MessageFilter = new WeakReference(messageFilter); - } - } -} diff --git a/src/Maple.Core/Extensions/AssemblyExtensions.cs b/src/Maple.Core/Extensions/AssemblyExtensions.cs deleted file mode 100644 index 1bf6bf5..0000000 --- a/src/Maple.Core/Extensions/AssemblyExtensions.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.Versioning; - -namespace Maple.Core -{ - /// - /// A set of extension methods for . - /// - public static class AssemblyExtensions - { - /// - /// Obtains the .NET framework version against which the has been built. - /// - /// The assembly - /// The .NET framework version - public static string GetFrameworkVersion(this Assembly assembly) - { - var targetFrameAttribute = assembly.GetCustomAttributes(true) - .OfType().FirstOrDefault(); - - if (targetFrameAttribute == null) { return ".NET 2, 3 or 3.5"; } - - return targetFrameAttribute.FrameworkName; - } - - /// - /// Obtains the location from which the was loaded. - /// - /// - /// The CodeBase is a URL to the place where the file was found, while the Location is - /// the path from where it was actually loaded. For example, if the assembly was downloaded from the - /// web, its CodeBase may start with “http://”, but its Location may start with “C:\”. - /// If the file was shadow copied, the Location would be the path to the copy of the file in the - /// shadow-copy directory. - /// - /// - /// Note that the CodeBase is not guaranteed to be set for assemblies in the GAC. - /// Location will always be set for assemblies loaded from disk however. - /// - /// - /// - /// The assembly for which location is returned - /// The location as - public static DirectoryInfo GetAssemblyLocation(this Assembly assembly) - { - // ReSharper disable once AssignNullToNotNullAttribute - return new DirectoryInfo(Path.GetDirectoryName(assembly.Location)); - } - - /// - /// Obtains the location from which the was found. - /// - /// - /// The CodeBase is a URL to the place where the file was found, while the Location is - /// the path from where it was actually loaded. For example, if the assembly was downloaded from the - /// web, its CodeBase may start with “http://”, but its Location may start with “C:\”. - /// If the file was shadow copied, the Location would be the path to the copy of the file in the - /// shadow-copy directory. - /// - /// - /// Note that the CodeBase is not guaranteed to be set for assemblies in the GAC. - /// Location will always be set for assemblies loaded from disk however. - /// - /// - /// - /// The assembly for which location is returned - /// The location as - public static DirectoryInfo GetAssemblyCodeBase(this Assembly assembly) - { - var uri = new Uri(assembly.CodeBase); - // ReSharper disable once AssignNullToNotNullAttribute - return new DirectoryInfo(Path.GetDirectoryName(uri.LocalPath)); - } - - /// - /// Determines whether the given has been compiled in Release mode. - /// Credit to: - /// - /// The assembly to examine - /// True if the is optimized otherwise False - public static bool IsOptimized(this Assembly assembly) - { - var attributes = assembly.GetCustomAttributes(typeof(DebuggableAttribute), false); - - if (attributes.Length == 0) { return true; } - - foreach (Attribute attr in attributes) - { - if (attr is DebuggableAttribute) - { - var d = attr as DebuggableAttribute; - // FYI - // "Run time Optimizer is enabled: " + !d.IsJITOptimizerDisabled - // "Run time Tracking is enabled: " + d.IsJITTrackingEnabled - if (d.IsJITOptimizerDisabled) { return false; } - return true; - } - } - return false; - } - - /// - /// Gets the flag indicating whether the given is 32-bit. - /// - public static bool Is32Bit(this Assembly assembly) - { - Ensure.NotNull(assembly, nameof(assembly)); - var location = assembly.Location; - if (location.IsNullOrEmptyOrWhiteSpace()) { location = assembly.CodeBase; } - - var uri = new Uri(location); - Ensure.That(uri.IsFile, "Assembly location is not a file."); - - var assemblyName = AssemblyName.GetAssemblyName(uri.LocalPath); - return assemblyName.ProcessorArchitecture == ProcessorArchitecture.X86; - } - - /// - /// Queries the assembly's headers to find if it is LARGEADDRESSAWARE. - /// The method is equivalent to running DumpBin on the assembly. - /// - public static bool IsAssemblyLargeAddressAware(Assembly assembly) - { - return ApplicationHelper.IsLargeAddressAware(assembly.Location); - } - } -} diff --git a/src/Maple.Core/Extensions/EventExtension.cs b/src/Maple.Core/Extensions/EventExtension.cs deleted file mode 100644 index fc1f532..0000000 --- a/src/Maple.Core/Extensions/EventExtension.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; - -namespace Maple.Core -{ - /// - /// - /// - public static class EventExtension - { - /// - /// Raises the specified thus. - /// - /// The handler. - /// The thus. - public static void Raise(this EventHandler handler, object thus) - { - handler?.Invoke(thus, EventArgs.Empty); - } - } -} diff --git a/src/Maple.Core/Extensions/GenericExtensions.cs b/src/Maple.Core/Extensions/GenericExtensions.cs deleted file mode 100644 index 43efc07..0000000 --- a/src/Maple.Core/Extensions/GenericExtensions.cs +++ /dev/null @@ -1,241 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Dynamic; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; -using System.Runtime.Serialization; - -namespace Maple.Core -{ - /// - /// A set of extension methods for generic types. - /// - public static class GenericExtensions - { - /// - /// This dictionary caches the delegates for each 'to-clone' type. - /// - private static readonly Dictionary CachedIlShallow = new Dictionary(); - private static readonly Dictionary CachedIlDeep = new Dictionary(); - private static LocalBuilder _localBuilder; - - /// - /// Converts the given to a . - /// - public static DynamicDictionary ToDynamic(this T @object, bool inherit = true) - { - var dynDic = new DynamicDictionary(); - foreach (var property in @object.GetType().GetInstanceProperties(inherit)) - { - dynDic.Add(property.Name, property.GetValue(@object, null)); - } - - return dynDic; - } - - /// - /// Returns True if has the default value of . - /// - /// The object to check for default. - /// True if has default or null value otherwise False. - public static bool IsDefault(this T @object) - { - return EqualityComparer.Default.Equals(@object, default(T)); - } - - /// - /// Returns an uninitialized instance of the without calling any of its constructor(s). - /// - /// - /// - /// Because the new instance of the object is initialized to zero and no constructors are run, - /// the object might not represent a state that is regarded as valid by that object. - /// The current method should only be used for deserialization when the user intends to immediately - /// populate all fields. It does not create an uninitialized string, - /// since creating an empty instance of an immutable type serves no purpose. - /// - /// Generic Type - /// An instance of type - /// with all its non-static fields initialized to its default value. - /// - public static T GetUninitializedInstance() - { - return (T)FormatterServices.GetUninitializedObject(typeof(T)); - } - - /// - /// Gets all the private, public, inherited instance property names for the given . - /// - /// This method can be used to return both a public or non-public property names - /// and supports instances of . - /// - /// Object to get properties from - /// The flag indicating whether inherited properties should be included or not - /// The flag indicating whether private properties should be included or not - /// - public static string[] GetPropertyNames(this T @object, bool inherit = true, bool includePrivate = true) - { - if (@object is IDynamicMetaObjectProvider expando) - { - var dic = (IDictionary)expando; - return dic.Keys.ToArray(); - } - - return @object.GetType() - .GetInstanceProperties(inherit, includePrivate) - .Select(p => p.Name).ToArray(); - } - - /// - /// Generic cloning method that clones an object using IL. - /// Only the first call of a certain type will hold back performance. - /// After the first call, the compiled IL is executed. - /// - /// Type of object to clone - /// Object to clone - /// Cloned object - public static T CloneShallowUsingIl(this T @object) - { - var type = typeof(T); - if (!CachedIlShallow.TryGetValue(type, out var myExec)) - { - // Create ILGenerator (both DM declarations work) - var dymMethod = new DynamicMethod("DoClone", type, new[] { type }, Assembly.GetExecutingAssembly().ManifestModule, true); - var cInfo = @object.GetType().GetConstructor(new Type[] { }); - var generator = dymMethod.GetILGenerator(); - - generator.Emit(OpCodes.Newobj, cInfo); - generator.Emit(OpCodes.Stloc_0); - foreach (var field in @object.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) - { - generator.Emit(OpCodes.Ldloc_0); - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, field); - generator.Emit(OpCodes.Stfld, field); - } - generator.Emit(OpCodes.Ldloc_0); - generator.Emit(OpCodes.Ret); - myExec = dymMethod.CreateDelegate(typeof(Func)); - CachedIlShallow.Add(type, myExec); - } - return ((Func)myExec)(@object); - } - - /// - /// Performs a deep copy of the object using the by generating IL. - /// Only the first call for a certain type will have impact on performance; After the first call, the compiled IL is executed. - /// - /// - /// The type of object being cloned. - /// The object instance to clone. - /// the cloned object - public static T CloneDeepUsingIl(this T myObject) - { - var type = typeof(T); - if (!CachedIlDeep.TryGetValue(type, out var myExec)) - { - // Create ILGenerator (both DM declarations work) - var dymMethod = new DynamicMethod("DoClone", type, new[] { type }, Assembly.GetExecutingAssembly().ManifestModule, true); - var cInfo = myObject.GetType().GetConstructor(new Type[] { }); - var generator = dymMethod.GetILGenerator(); - - generator.Emit(OpCodes.Newobj, cInfo); - generator.Emit(OpCodes.Stloc_0); - - foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) - { - if (field.FieldType.IsValueType || field.FieldType == typeof(string)) - { - CopyValueType(generator, field); - } - else if (field.FieldType.IsClass) - { - CopyReferenceType(generator, field); - } - } - generator.Emit(OpCodes.Ldloc_0); - generator.Emit(OpCodes.Ret); - myExec = dymMethod.CreateDelegate(typeof(Func)); - CachedIlDeep.Add(type, myExec); - } - return ((Func)myExec)(myObject); - } - - private static void CopyValueType(ILGenerator generator, FieldInfo field) - { - generator.Emit(OpCodes.Ldloc_0); - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, field); - generator.Emit(OpCodes.Stfld, field); - } - - private static void CopyReferenceType(ILGenerator generator, FieldInfo field) - { - // We have a reference type. - _localBuilder = generator.DeclareLocal(field.FieldType); - if (field.FieldType.GetInterface("IEnumerable") != null) - { - // We have a list type (generic). - if (field.FieldType.IsGenericType) - { - // Get argument of list type - var argType = field.FieldType.GetGenericArguments()[0]; - // Check that it has a constructor that accepts another IEnumerable. - var genericType = typeof(IEnumerable<>).MakeGenericType(argType); - - var ci = field.FieldType.GetConstructor(new[] { genericType }); - if (ci != null) - { - // It has! (Like the List<> class) - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, field); - generator.Emit(OpCodes.Newobj, ci); - generator.Emit(OpCodes.Stloc, _localBuilder); - PlaceNewTempObjInClone(generator, field); - } - } - } - else - { - CreateNewTempObject(generator, field.FieldType); - PlaceNewTempObjInClone(generator, field); - foreach (var fi in field.FieldType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) - { - if (fi.FieldType.IsValueType || fi.FieldType == typeof(string)) - { - CopyValueTypeTemp(generator, field, fi); - } - else if (fi.FieldType.IsClass) - { - CopyReferenceType(generator, fi); - } - } - } - } - - private static void CreateNewTempObject(ILGenerator generator, Type type) - { - var cInfo = type.GetConstructor(new Type[] { }); - generator.Emit(OpCodes.Newobj, cInfo); - generator.Emit(OpCodes.Stloc, _localBuilder); - } - - private static void PlaceNewTempObjInClone(ILGenerator generator, FieldInfo field) - { - // Get object from custom location and store it in right field of location 0 - generator.Emit(OpCodes.Ldloc_0); - generator.Emit(OpCodes.Ldloc, _localBuilder); - generator.Emit(OpCodes.Stfld, field); - } - - private static void CopyValueTypeTemp(ILGenerator generator, FieldInfo fieldParent, FieldInfo fieldDetail) - { - generator.Emit(OpCodes.Ldloc_1); - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, fieldParent); - generator.Emit(OpCodes.Ldfld, fieldDetail); - generator.Emit(OpCodes.Stfld, fieldDetail); - } - } -} diff --git a/src/Maple.Core/Extensions/LinqExtensions.cs b/src/Maple.Core/Extensions/LinqExtensions.cs deleted file mode 100644 index b223f7f..0000000 --- a/src/Maple.Core/Extensions/LinqExtensions.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - public static class LinqExtensions - { - /// - /// Randoms the specified items. - /// - /// - /// The items. - /// - /// Random can't generate a result. There were no valid parameters - items - public static T Random(this IEnumerable baseCollection) - { - if (baseCollection == null) - throw new ArgumentNullException(nameof(baseCollection), $"{nameof(baseCollection)} {Resources.IsRequired}"); - - - // note: creating a Random instance each call may not be correct for you, - // consider a thread-safe static instance - var r = new Random(); - var list = baseCollection as IList ?? baseCollection.ToList(); - return list.Count == 0 ? default(T) : list[r.Next(0, list.Count)]; - } - - /// - /// determines if some of the submitted items can be added to the collection and returns a collection of these items - /// - /// The base collection. - /// The new items. - /// - /// - /// CanAddRange can't return a result. There were no valid parameters - newItems - /// or - /// CanAddRange can't return a result. There were no valid parameters - baseCollection - /// - public static IEnumerable CanAddRange(this IList baseCollection, IList newItems) - { - if (baseCollection == null) - throw new ArgumentNullException(nameof(baseCollection), $"{nameof(baseCollection)} {Resources.IsRequired}"); - - if (newItems?.Any() != true) - throw new ArgumentNullException(nameof(newItems), $"{nameof(newItems)} {Resources.IsRequired}"); - - var excludedIDs = new HashSet(baseCollection.Select(p => p.Id)); - return newItems.Where(p => !excludedIDs.Contains(p.Id)); - } - - /// - /// determines if some of the submitted items can be added to the collection and returns a collection of these items - /// - /// The base collection. - /// The new items. - /// - /// - /// CanAddRange can't return a result. There were no valid parameters - newItems - /// or - /// CanAddRange can't return a result. There were no valid parameters - baseCollection - /// - public static IEnumerable CanAddRange(this IList baseCollection, IList newItems) - { - if (baseCollection == null) - throw new ArgumentNullException(nameof(baseCollection), $"{nameof(baseCollection)} {Resources.IsRequired}"); - - if (newItems?.Any() != true) - throw new ArgumentNullException(nameof(newItems), $"{nameof(newItems)} {Resources.IsRequired}"); - - var excludedIDs = new HashSet(baseCollection.Select(p => p.Id)); - return newItems.Where(p => !excludedIDs.Contains(p.Id)); - } - - public static IEnumerable ForEach(this IEnumerable baseCollection, Func action) - { - if (baseCollection == null) - throw new ArgumentNullException(nameof(baseCollection), $"{nameof(baseCollection)} {Resources.IsRequired}"); - - if (action == null) - throw new ArgumentNullException(nameof(action), $"{nameof(action)} {Resources.IsRequired}"); - - foreach (var item in baseCollection) - yield return action(item); - } - - public static void ForEach(this IEnumerable baseCollection, Action action) - { - if (baseCollection == null) - throw new ArgumentNullException(nameof(baseCollection), $"{nameof(baseCollection)} {Resources.IsRequired}"); - - if (action == null) - throw new ArgumentNullException(nameof(action), $"{nameof(action)} {Resources.IsRequired}"); - - foreach (var item in baseCollection) - action(item); - } - - public static IEnumerable ForEach(this IRangeObservableCollection baseCollection, Func action) - { - if (baseCollection == null) - throw new ArgumentNullException(nameof(baseCollection), $"{nameof(baseCollection)} {Resources.IsRequired}"); - - if (action == null) - throw new ArgumentNullException(nameof(action), $"{nameof(action)} {Resources.IsRequired}"); - - foreach (var item in baseCollection) - yield return action(item); - } - - public static void ForEach(this IRangeObservableCollection baseCollection, Action action) - { - if (baseCollection == null) - throw new ArgumentNullException(nameof(baseCollection), $"{nameof(baseCollection)} {Resources.IsRequired}"); - - if (action == null) - throw new ArgumentNullException(nameof(action), $"{nameof(action)} {Resources.IsRequired}"); - - foreach (var item in baseCollection) - action(item); - } - } -} diff --git a/src/Maple.Core/Extensions/SequenceType.cs b/src/Maple.Core/Extensions/SequenceType.cs deleted file mode 100644 index 2232760..0000000 --- a/src/Maple.Core/Extensions/SequenceType.cs +++ /dev/null @@ -1,186 +0,0 @@ -using System.Diagnostics.CodeAnalysis; - -namespace Maple.Core -{ - /// - /// Enum representing the possible types of a sequence. - /// - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum SequenceType - { - /// - /// Represents an invalid type. - /// - Invalid = 0, - - /// - /// Represents a . - /// - String, - - /// - /// Represents an Array. - /// - Array, - - /// - /// Represents a . This type is non generic. - /// - BitArray, - - /// - /// Represents an . This type is non generic. - /// - ArrayList, - - /// - /// Represents a . This type is non generic. - /// - Queue, - - /// - /// Represents a . This type is non generic. - /// - Stack, - - /// - /// Represents a . This type is non generic. - /// - Hashtable, - - /// - /// Represents a . This type is non generic. - /// - SortedList, - - /// - /// Represents a . This type is non generic. - /// - Dictionary, - - /// - /// Represents a . This type is non generic. - /// - ListDictionary, - - /// - /// Represents an . This interface type is non generic. - /// - IList, - - /// - /// Represents an . This interface type is non generic. - /// - ICollection, - - /// - /// Represents an . This interface type is non generic. - /// - IDictionary, - - /// - /// Represents an . This interface type is non generic. - /// - IEnumerable, - - /// - /// Represents a custom implementation of . - /// - Custom, - - /// - /// Represents a . - /// - GenericList, - - /// - /// Represents a . - /// - GenericLinkedList, - - /// - /// Represents a . - /// - GenericCollection, - - /// - /// Represents a . - /// - GenericQueue, - - /// - /// Represents a . - /// - GenericStack, - - /// - /// Represents a . - /// - GenericHashSet, - - /// - /// Represents a . - /// - GenericSortedList, - - /// - /// Represents a . - /// - GenericDictionary, - - /// - /// Represents a . - /// - GenericSortedDictionary, - - /// - /// Represents a . - /// - GenericBlockingCollection, - - /// - /// Represents a . - /// - GenericConcurrentDictionary, - - /// - /// Represents a . - /// - GenericConcurrentBag, - - /// - /// Represents an . - /// - GenericIList, - - /// - /// Represents an . - /// - GenericICollection, - - /// - /// Represents an . - /// - GenericIEnumerable, - - /// - /// Represents an . - /// - GenericIDictionary, - - /// - /// Represents an ICollection{KeyValuePair{TKey, TValue}}. - /// - GenericICollectionKeyValue, - - /// - /// Represents an IEnumerable{KeyValuePair{TKey, TValue}}. - /// - GenericIEnumerableKeyValue, - - /// - /// Represents a custom implementation of . - /// - GenericCustom - } -} diff --git a/src/Maple.Core/Extensions/StringExtensions.cs b/src/Maple.Core/Extensions/StringExtensions.cs deleted file mode 100644 index 67332a0..0000000 --- a/src/Maple.Core/Extensions/StringExtensions.cs +++ /dev/null @@ -1,675 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading; -using System.Xml; -using System.Xml.Linq; - -namespace Maple.Core -{ - /// - /// Extensions for - /// - public static class StringExtensions - { - /// - /// Contains characters that may be used as regular expression arguments after \. - /// - private static readonly char[] RegexCharacters = { 'G', 'Z', 'A', 'n', 'W', 'w', 'v', 't', 's', 'S', 'r', 'k', 'f', 'D', 'd', 'B', 'b' }; - - private static readonly char[] InvalidFileNameCharacters = Path.GetInvalidFileNameChars(); - private static readonly char[] InvalidPathCharacters = Path.GetInvalidPathChars(); - - /// - /// A nicer way of calling - /// - /// The string to test. - /// if the format parameter is null or an empty string (""); otherwise, . - [DebuggerStepThrough] - public static bool IsNullOrEmpty(this string value) - { - return string.IsNullOrEmpty(value); - } - - /// - /// A nice way of calling the inverse of - /// - /// The string to test. - /// if the format parameter is not null or an empty string (""); otherwise, . - [DebuggerStepThrough] - public static bool IsNotNullOrEmpty(this string value) - { - return !value.IsNullOrEmpty(); - } - - /// - /// A nice way of checking if a string is null, empty or whitespace - /// - /// The string to test. - /// if the format parameter is null or an empty string (""); otherwise, . - [DebuggerStepThrough] - public static bool IsNullOrEmptyOrWhiteSpace(this string value) - { - return string.IsNullOrWhiteSpace(value); - } - - /// - /// A nice way of checking the inverse of (if a string is null, empty or whitespace) - /// - /// The string to test. - /// if the format parameter is not null or an empty string (""); otherwise, . - [DebuggerStepThrough] - public static bool IsNotNullOrEmptyOrWhiteSpace(this string value) - { - return !value.IsNullOrEmptyOrWhiteSpace(); - } - - /// - /// Parses a string as Boolean, valid inputs are: true|false|yes|no|1|0. - /// Input is parsed as Case-Insensitive. - /// - public static bool TryParseAsBool(this string value, out bool result) - { - Ensure.NotNull(value, nameof(value)); - - const StringComparison CompPolicy = StringComparison.OrdinalIgnoreCase; - - if (value.Equals("true", CompPolicy) - || value.Equals("yes", CompPolicy) - || value.Equals("1", CompPolicy)) - { - result = true; - return true; - } - - if (value.Equals("false", CompPolicy) - || value.Equals("no", CompPolicy) - || value.Equals("0", CompPolicy)) - { - result = false; - return true; - } - - result = false; - return false; - } - - /// Formats arguments into string based on the provided . - /// The as string. - /// The arguments. - /// The formatted string. - /// Thrown when is null or empty or whitespace. - [DebuggerStepThrough] - public static string FormatWith(this string format, params object[] args) - { - Ensure.NotNullOrEmptyOrWhiteSpace(format); - return string.Format(format, args); - } - - /// Formats arguments into string based on the provided . - /// The as string. - /// The format provider. - /// The arguments. - /// The formatted string. - /// Thrown when is null or empty or whitespace. - [DebuggerStepThrough] - public static string FormatWith(this string format, IFormatProvider provider, params object[] args) - { - Ensure.NotNullOrEmptyOrWhiteSpace(format); - return string.Format(provider, format, args); - } - - /// - /// Allows for using strings in coalescing operations. - /// - /// The string value to check. - /// Null if is empty or the original . - [DebuggerStepThrough] - public static string NullIfEmpty(this string value) - { - return value == string.Empty ? null : value; - } - - /// - /// Tries to extract the value between the tag from the . - /// This method is case insensitive. - /// - /// The input string. - /// The tag whose value will be returned e.g span, img. - /// The extracted value. - /// True if successful otherwise False. - public static bool TryExtractValueFromTag(this string input, string tagName, out string value) - { - Ensure.NotNull(input, nameof(input)); - Ensure.NotNull(tagName, nameof(tagName)); - - var pattern = $"<{tagName}[^>]*>(.*)"; - var match = Regex.Match(input, pattern, RegexOptions.IgnoreCase); - - if (match.Success) - { - value = match.Groups[1].ToString(); - return true; - } - - value = null; - return false; - } - - /// - /// Returns a string array containing the trimmed substrings in this - /// that are delimited by the provided . - /// - public static string[] SplitAndTrim(this string value, params char[] separators) - { - Ensure.NotNull(value, nameof(value)); - return value.Trim() - .Split(separators, StringSplitOptions.RemoveEmptyEntries) - .Select(s => s.Trim()) - .ToArray(); - } - - /// - /// Checks if the contains the based on the provided rules. - /// - public static bool Contains(this string input, string stringToCheckFor, StringComparison comparison) - { - return input.IndexOf(stringToCheckFor, comparison) >= 0; - } - - /// - /// Checks that given matches any of the potential matches. - /// Inspired by: http://stackoverflow.com/a/20644611/23199 - /// - public static bool EqualsAny(this string input, StringComparer comparer, string match1, string match2) - { - return comparer.Equals(input, match1) || comparer.Equals(input, match2); - } - - /// - /// Checks that given matches any of the potential matches. - /// Inspired by: http://stackoverflow.com/a/20644611/23199 - /// - public static bool EqualsAny(this string input, StringComparer comparer, string match1, string match2, string match3) - { - return comparer.Equals(input, match1) || comparer.Equals(input, match2) || comparer.Equals(input, match3); - } - - /// - /// Checks that given is in a list of potential . - /// Inspired by: http://stackoverflow.com/a/20644611/23199 - /// - public static bool EqualsAny(this string input, StringComparer comparer, params string[] matches) - { - return matches.Any(x => comparer.Equals(x, input)); - } - - /// - /// Checks to see if the given input is a valid palindrome or not. - /// - /// The input string - /// True if palindrome otherwise False - public static bool IsPalindrome(this string input) - { - Ensure.NotNull(input, nameof(input)); - var min = 0; - var max = input.Length - 1; - while (true) - { - if (min > max) { return true; } - - var a = input[min]; - var b = input[max]; - if (char.ToLower(a) != char.ToLower(b)) { return false; } - - min++; - max--; - } - } - - /// - /// Truncates the to the maximum length of and - /// replaces the truncated part with - /// - /// The input string - /// Total length of characters to maintain before truncation. - /// The suffix to add to the end of the truncated - /// Truncated string. - public static string Truncate(this string input, int maxLength, string suffix = "") - { - Ensure.NotNull(input, nameof(input)); - Ensure.NotNull(suffix, nameof(suffix)); - - if (maxLength < 0) { return input; } - if (maxLength == 0) { return string.Empty; } - - var chars = input.Take(maxLength).ToArray(); - - if (chars.Length != input.Length) - { - return new string(chars) + suffix; - } - - return new string(chars); - } - - /// - /// Removes different types of new lines from a given string. - /// - /// input string. - /// The given input minus any new line characters. - public static string RemoveNewLines(this string input) - { - Ensure.NotNull(input, nameof(input)); - return input.Replace("\n", string.Empty).Replace("\r", string.Empty); - } - - /// - /// Separates a PascalCase string. - /// - /// "ThisIsPascalCase".SeparatePascalCase(); // returns "This Is Pascal Case" - /// The format to split - /// The original string separated on each uppercase character. - public static string SeparatePascalCase(this string value) - { - Ensure.NotNullOrEmptyOrWhiteSpace(value); - return Regex.Replace(value, "([A-Z])", " $1").Trim(); - } - - /// - /// Converts string to Pascal Case - /// This Is A Pascal Case String. - /// - /// The given input. - /// The given converted to Pascal Case. - public static string ToPascalCase(this string input) - { - Ensure.NotNull(input, nameof(input)); - - var cultureInfo = Thread.CurrentThread.CurrentCulture; - var textInfo = cultureInfo.TextInfo; - return textInfo.ToTitleCase(input); - } - - /// - /// Compares against , the comparison is case-sensitive. - /// - /// The input string - /// The target string - /// True if equal otherwise False - public static bool IsEqualTo(this string input, string target) - { - if (input == null && target == null) { return true; } - if (input == null || target == null) { return false; } - if (input.Length != target.Length) { return false; } - - return string.CompareOrdinal(input, target) == 0; - } - - /// - /// Handy method to print arguments to System.Console. - /// - /// The input string. - /// The arguments. - [DebuggerStepThrough] - public static void Print(this string input, params object[] args) - { - Console.WriteLine(input, args); - } - - /// - /// Generates a slug. - /// - /// Credit goes to . - /// - /// - [DebuggerStepThrough] - public static string GenerateSlug(this string value, uint? maxLength = null) - { - // prepare string, remove diacritics, lower case and convert hyphens to whitespace - var result = RemoveDiacritics(value).Replace("-", " ").ToLowerInvariant(); - - result = Regex.Replace(result, @"[^a-z0-9\s-]", string.Empty); // remove invalid characters - result = Regex.Replace(result, @"\s+", " ").Trim(); // convert multiple spaces into one space - - if (maxLength.HasValue) - { - result = result.Substring(0, result.Length <= maxLength ? result.Length : (int)maxLength.Value).Trim(); - } - return Regex.Replace(result, @"\s", "-"); - } - - /// - /// Removes the diacritics from the given - /// - /// - /// Credit goes to . - /// - [DebuggerStepThrough] - public static string RemoveDiacritics(this string input) - { - var normalizedString = input.Normalize(NormalizationForm.FormD); - var stringBuilder = StringBuilderCache.Acquire(); - - foreach (var c in normalizedString) - { - var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c); - if (unicodeCategory != UnicodeCategory.NonSpacingMark) - { - stringBuilder.Append(c); - } - } - - return StringBuilderCache.GetStringAndRelease(stringBuilder).Normalize(NormalizationForm.FormC); - } - - /// - /// A method to convert English digits to Persian numbers. - /// - public static string ToPersianNumber(this string input) - { - Ensure.NotNull(input, nameof(input)); - return input - .Replace("0", "۰") - .Replace("1", "۱") - .Replace("2", "۲") - .Replace("3", "۳") - .Replace("4", "۴") - .Replace("5", "۵") - .Replace("6", "۶") - .Replace("7", "۷") - .Replace("8", "۸") - .Replace("9", "۹"); - } - - /// - /// Gets a sequence containing every element with the name equal to . - /// - /// The input containing XML - /// The name of the elements to return - /// The flag indicating whether the name should be looked up in a case sensitive manner - /// The sequence containing all the elements matching the - public static IEnumerable GetElements(this string xmlInput, XName name, bool ignoreCase = true) - { - Ensure.NotNull(xmlInput, nameof(xmlInput)); - return xmlInput.GetElements(name, new XmlReaderSettings(), ignoreCase); - } - - /// - /// Gets a sequence containing every element with the name equal to . - /// - /// The input containing XML - /// The name of the elements to return - /// The settings used by the - /// The flag indicating whether the name should be looked up in a case sensitive manner - /// The sequence containing all the elements matching the - public static IEnumerable GetElements(this string xmlInput, XName name, XmlReaderSettings settings, bool ignoreCase = true) - { - Ensure.NotNull(xmlInput, nameof(xmlInput)); - Ensure.NotNull(name, nameof(name)); - Ensure.NotNull(settings, nameof(settings)); - - using (var stringReader = new StringReader(xmlInput)) - using (var xmlReader = XmlReader.Create(stringReader, settings)) - { - foreach (var xElement in xmlReader.GetEelements(name, ignoreCase)) - { - yield return xElement; - } - } - } - - /// - /// Compresses the given to Base64 string. - /// - /// The string to be compressed - /// The compressed string in Base64 - public static string Compress(this string input) - { - Ensure.NotNull(input, nameof(input)); - - var buffer = Encoding.UTF8.GetBytes(input); - using (var memStream = new MemoryStream()) - using (var zipStream = new GZipStream(memStream, CompressionMode.Compress, true)) - { - zipStream.Write(buffer, 0, buffer.Length); - zipStream.Close(); - - memStream.Position = 0; - - var compressedData = new byte[memStream.Length]; - memStream.Read(compressedData, 0, compressedData.Length); - - var gZipBuffer = new byte[compressedData.Length + 4]; - Buffer.BlockCopy(compressedData, 0, gZipBuffer, 4, compressedData.Length); - Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gZipBuffer, 0, 4); - return Convert.ToBase64String(gZipBuffer); - } - } - - /// - /// Decompresses a Base64 compressed string. - /// - /// The string compressed in Base64 - /// The uncompressed string - public static string Decompress(this string compressedInput) - { - Ensure.NotNull(compressedInput, nameof(compressedInput)); - - var gZipBuffer = Convert.FromBase64String(compressedInput); - using (var memStream = new MemoryStream()) - { - var dataLength = BitConverter.ToInt32(gZipBuffer, 0); - memStream.Write(gZipBuffer, 4, gZipBuffer.Length - 4); - memStream.Position = 0; - - var buffer = new byte[dataLength]; - using (var zipStream = new GZipStream(memStream, CompressionMode.Decompress)) - { - zipStream.Read(buffer, 0, buffer.Length); - } - - return Encoding.UTF8.GetString(buffer); - } - } - - /// - /// Ensures the given can be used as a file name. - /// - public static bool IsValidFileName(this string input) - { - return input.IsNotNullOrEmptyOrWhiteSpace() && input.IndexOfAny(InvalidFileNameCharacters) == -1; - } - - /// - /// Ensures the given can be used as a path. - /// - public static bool IsValidPathName(this string input) - { - return input.IsNotNullOrEmptyOrWhiteSpace() && input.IndexOfAny(InvalidPathCharacters) == -1; - } - - /// - /// Returns a from a Base64 encoded . - /// - /// DRfscsSQbUu8bXRqAvcWQA== or DRfscsSQbUu8bXRqAvcWQA depending on . - /// - /// - /// See: - /// - /// - public static Guid ToGuid(this string input, bool trimmed = true) - { - return trimmed ? new Guid(Convert.FromBase64String(input + "==")) - : new Guid(Convert.FromBase64String(input)); - } - - /// - /// Converts API to [aA][pP][iI]. - /// - /// This should be used as much faster alternative to adding - /// or using the (?i) for example (?i)API(?-i) - /// - /// - public static string ToCaseIncensitiveRegexArgument(this string input) - { - if (input.IsNullOrEmptyOrWhiteSpace()) { return input; } - - var patternIndexes = input.GetStartAndEndIndexes("(?<", ">").ToArray(); - var hasPattern = patternIndexes.Length > 0; - var isInPattern = false; - - var builder = StringBuilderCache.Acquire(); - // ReSharper disable once ForCanBeConvertedToForeach - for (var i = 0; i < input.Length; i++) - { - var prev = i == 0 ? new char() : input[i - 1]; - var currChar = input[i]; - - if (hasPattern) - { - foreach (var pair in patternIndexes) - { - if (i >= pair.Key && i <= pair.Value) - { - isInPattern = true; - break; - } - - isInPattern = false; - } - } - - if (!char.IsLetter(currChar) - || (prev == '\\' && RegexCharacters.Contains(currChar)) - || isInPattern) - { - builder.Append(currChar); - continue; - } - - builder.Append('['); - - if (char.IsUpper(currChar)) - { - builder.Append(char.ToLower(currChar)).Append(currChar); - } - else - { - builder.Append(currChar).Append(char.ToUpper(currChar)); - } - builder.Append(']'); - } - return StringBuilderCache.GetStringAndRelease(builder); - } - - /// - /// Returns all the start and end indexes of the occurrences of the - /// given and - /// in the given . - /// - /// The input to search. - /// The starting tag e.g. <div>. - /// The ending tag e.g. </div>. - /// - /// A sequence where the key is - /// the starting position and value is the end position. - /// - [DebuggerStepThrough] - public static IEnumerable> GetStartAndEndIndexes(this string input, string startTag, string endTag) - { - var startIdx = 0; - int endIdx; - - while ((startIdx = input.IndexOf(startTag, startIdx, StringComparison.Ordinal)) != -1 - && (endIdx = input.IndexOf(endTag, startIdx, StringComparison.Ordinal)) != -1) - { - var result = new KeyValuePair(startIdx, endIdx); - startIdx = endIdx; - yield return result; - } - } - } - - /// - /// Extension methods for classes in the namespace. - /// - public static class XmlExtensions - { - /// - /// Sets the default XML namespace of every element in the given XML element - /// - public static void SetDefaultXmlNamespace(this XElement element, XNamespace xmlns) - { - Ensure.NotNull(element, nameof(element)); - Ensure.NotNull(xmlns, nameof(xmlns)); - - if (element.Name.NamespaceName == string.Empty) - { - element.Name = xmlns + element.Name.LocalName; - } - - foreach (var e in element.Elements()) - { - e.SetDefaultXmlNamespace(xmlns); - } - } - - /// - /// Gets a sequence containing every element with the name equal to . - /// - /// The used to read the XML - /// The name of the elements to return - /// The flag indicating whether the name should be looked up in a case sensitive manner - /// The sequence containing all the elements matching the - public static IEnumerable GetEelements(this XmlReader reader, XName name, bool ignoreCase = true) - { - Ensure.NotNull(reader, nameof(reader)); - Ensure.NotNull(name, nameof(name)); - - var compPolicy = ignoreCase - ? StringComparison.InvariantCultureIgnoreCase - : StringComparison.InvariantCulture; - - reader.MoveToElement(); - while (reader.Read()) - { - while (reader.NodeType == XmlNodeType.Element - && reader.Name.Equals(name.LocalName, compPolicy)) - { - yield return (XElement)XNode.ReadFrom(reader); - } - } - } - - /// - /// Converts the content of the given to . - /// - public static DynamicDictionary ToDynamic(this XmlReader reader, bool ignoreCase = true) - { - Ensure.NotNull(reader, nameof(reader)); - - var result = new DynamicDictionary(ignoreCase); - var elements = new List(); - result["Elements"] = elements; - - reader.MoveToElement(); - while (reader.Read()) - { - while (reader.NodeType == XmlNodeType.Element) - { - var element = (XElement)XNode.ReadFrom(reader); - elements.Add(element); - } - } - - return result; - } - } -} diff --git a/src/Maple.Core/Extensions/TypeExtensions.cs b/src/Maple.Core/Extensions/TypeExtensions.cs deleted file mode 100644 index 86c0276..0000000 --- a/src/Maple.Core/Extensions/TypeExtensions.cs +++ /dev/null @@ -1,469 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Reflection; - -namespace Maple.Core -{ - /// - /// Extension methods for . - /// - public static class TypeExtensions - { - private static readonly Type[] SimpleTypes = - { - typeof(byte), - typeof(sbyte), - typeof(short), - typeof(ushort), - typeof(int), - typeof(uint), - typeof(long), - typeof(ulong), - typeof(float), - typeof(double), - typeof(decimal), - typeof(bool), - typeof(string), - typeof(char), - typeof(Guid), - typeof(DateTime), - typeof(DateTimeOffset), - typeof(TimeSpan), - typeof(byte[]) - }; - - private static readonly Dictionary NonGenericCollectionsToSequenceTypeMapping = new Dictionary(StringComparer.Ordinal) - { - { "System.String", SequenceType.String }, - { "System.Collections.ArrayList", SequenceType.ArrayList }, - { "System.Collections.Queue", SequenceType.Queue }, - { "System.Collections.Stack", SequenceType.Stack }, - { "System.Collections.BitArray", SequenceType.BitArray }, - { "System.Collections.SortedList", SequenceType.SortedList }, - { "System.Collections.Hashtable", SequenceType.Hashtable }, - { "System.Collections.Specialized.ListDictionary", SequenceType.ListDictionary }, - { "System.Collections.IList", SequenceType.IList }, - { "System.Collections.ICollection", SequenceType.ICollection }, - { "System.Collections.IDictionary", SequenceType.IDictionary }, - { "System.Collections.IEnumerable", SequenceType.IEnumerable } - }; - - /// - /// Returns the instance property of the given regardless of it's access modifier. - /// This method can be used to return both a public or non-public property. - /// - [DebuggerStepThrough] - public static bool TryGetInstanceProperty(this Type type, string propertyName, out PropertyInfo property, bool inherit = true) - { - Ensure.NotNull(type, nameof(type)); - Ensure.NotNullOrEmptyOrWhiteSpace(propertyName); - - var flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public; - if (!inherit) { flags = flags | BindingFlags.DeclaredOnly; } - - property = type.GetProperties(flags) - .FirstOrDefault(p => p.Name.Equals(propertyName, StringComparison.Ordinal)); - - return property != null; - } - - /// - /// Returns all instance properties of the given . - /// This method can be used to return both a public or non-public property. - /// - [DebuggerStepThrough] - public static PropertyInfo[] GetInstanceProperties(this Type type, bool inherit = true, bool includePrivate = true) - { - Ensure.NotNull(type, nameof(type)); - return GetInstanceProperties(type.GetTypeInfo(), inherit, includePrivate); - } - - /// - /// Returns all instance properties of the given . - /// This method can be used to return both a public or non-public property. - /// - [DebuggerStepThrough] - public static PropertyInfo[] GetInstanceProperties(this TypeInfo typeInfo, bool inherit, bool includePrivate) - { - Ensure.NotNull(typeInfo, nameof(typeInfo)); - - var flags = BindingFlags.Instance | BindingFlags.Public; - if (includePrivate) { flags = flags | BindingFlags.NonPublic; } - if (!inherit) { flags = flags | BindingFlags.DeclaredOnly; } - - return typeInfo.GetProperties(flags); - } - - /// - /// Returns the properties marked with an attribute of type . - /// It avoids materializing any attribute instances. - /// - /// Type of Attribute which has decorated the properties. - /// Type of Object which has properties decorated with . - /// If true it also searches the ancestors for the . - /// A sequence containing properties decorated with . - [DebuggerStepThrough] - public static IEnumerable GetPropertiesWithAttribute(this Type type, bool inherit = true) where T : Attribute - { - Ensure.NotNull(type, nameof(type)); - return type.GetProperties() - .Where(prop => Attribute.IsDefined(prop, typeof(T)) && (prop.DeclaringType == type || inherit)); - } - - /// - /// Returns a mapping of attribute to for a given . - /// - /// Type of attribute which will be used as the key - /// Type whose properties will be mapped to the attributes - /// If true it also searches the ancestors for the . - /// A mapping between the attributes defined on the properties and the property infos - [DebuggerStepThrough] - public static Dictionary GetAttributeToPropertyMapping(this Type type, bool inherit = true) where T : Attribute - { - Ensure.NotNull(type, nameof(type)); - - var properties = type.GetProperties(); - var result = new Dictionary(properties.Length); - foreach (var property in properties) - { - var attributes = property.GetCustomAttributes(inherit); - var attr = attributes.FirstOrDefault(); - if (attr == null) { continue; } - - result[attr] = property; - } - return result; - } - - /// - /// Tries to get attributes of type defined on the given . - /// - /// The type of the attribute to get - /// The type on which the attribute has been defined - /// All of the attributes found on the given type - /// If true it also searches the ancestors for the . - /// True if successful otherwise False - [DebuggerStepThrough] - public static bool TryGetAttributes(this Type type, out T[] attributes, bool inherit = true) where T : Attribute - { - var result = Attribute.GetCustomAttributes(type, typeof(T), inherit); - - if (result.Length > 0) - { - attributes = result as T[]; - return true; - } - - attributes = null; - return false; - } - - /// - /// Tries to get the generic type arguments for the given . - /// For a type of the generic type is . - /// - /// The type for which generic type should be retrieved - /// The result - /// if generic types can be retrieved otherwise - [DebuggerStepThrough] - public static bool TryGetGenericArguments(this Type type, out Type[] genericArguments) - { - Ensure.NotNull(type, nameof(type)); - - if (type.IsArray) - { - genericArguments = new[] { type.GetElementType() }; - return true; - } - - if (!type.IsGenericType) - { - genericArguments = null; - return false; - } - - genericArguments = type.GetGenericArguments(); - return true; - } - - /// - /// Determines if the given is a sequence of elements. - /// - /// The type to inspect - /// The determined type of the sequence - /// True if is a sequence otherwise False - [DebuggerStepThrough] - public static bool IsSequence(this Type type, out SequenceType sequenceType) - { - Ensure.NotNull(type, nameof(type)); - - if (type.IsArray) - { - sequenceType = SequenceType.Array; - return true; - } - - if (NonGenericCollectionsToSequenceTypeMapping.TryGetValue(type.FullName, out sequenceType)) - { - return true; - } - - if (type.FullName.StartsWith("System.Collections.Generic.List`1", StringComparison.Ordinal)) - { - sequenceType = SequenceType.GenericList; - return true; - } - - if (type.FullName.StartsWith("System.Collections.Generic.HashSet`1", StringComparison.Ordinal)) - { - sequenceType = SequenceType.GenericHashSet; - return true; - } - - if (type.FullName.StartsWith("System.Collections.ObjectModel.Collection`1", StringComparison.Ordinal)) - { - sequenceType = SequenceType.GenericCollection; - return true; - } - - if (type.FullName.StartsWith("System.Collections.Generic.LinkedList`1", StringComparison.Ordinal)) - { - sequenceType = SequenceType.GenericLinkedList; - return true; - } - - if (type.FullName.StartsWith("System.Collections.Generic.Stack`1", StringComparison.Ordinal)) - { - sequenceType = SequenceType.GenericStack; - return true; - } - - if (type.FullName.StartsWith("System.Collections.Generic.Queue`1", StringComparison.Ordinal)) - { - sequenceType = SequenceType.GenericQueue; - return true; - } - - if (type.FullName.StartsWith("System.Collections.Generic.IList`1", StringComparison.Ordinal)) - { - sequenceType = SequenceType.GenericIList; - return true; - } - - if (type.FullName.StartsWith("System.Collections.Generic.ICollection`1[[System.Collections.Generic.KeyValuePair`2", StringComparison.Ordinal)) - { - sequenceType = SequenceType.GenericICollectionKeyValue; - return true; - } - - if (type.FullName.StartsWith("System.Collections.Generic.ICollection`1", StringComparison.Ordinal)) - { - sequenceType = SequenceType.GenericICollection; - return true; - } - - if (type.FullName.StartsWith("System.Collections.Generic.IEnumerable`1[[System.Collections.Generic.KeyValuePair`2", StringComparison.Ordinal)) - { - sequenceType = SequenceType.GenericIEnumerableKeyValue; - return true; - } - - if (type.FullName.StartsWith("System.Collections.Generic.IEnumerable`1", StringComparison.Ordinal)) - { - sequenceType = SequenceType.GenericIEnumerable; - return true; - } - - if (type.FullName.StartsWith("System.Collections.Generic.Dictionary`2", StringComparison.Ordinal)) - { - sequenceType = SequenceType.GenericDictionary; - return true; - } - - if (type.FullName.StartsWith("System.Collections.Generic.SortedDictionary`2", StringComparison.Ordinal)) - { - sequenceType = SequenceType.GenericSortedDictionary; - return true; - } - - if (type.FullName.StartsWith("System.Collections.Generic.SortedList`2", StringComparison.Ordinal)) - { - sequenceType = SequenceType.GenericSortedList; - return true; - } - - if (type.FullName.StartsWith("System.Collections.Generic.IDictionary`2", StringComparison.Ordinal)) - { - sequenceType = SequenceType.GenericIDictionary; - return true; - } - - if (type.FullName.StartsWith("System.Collections.Generic.ICollection`2", StringComparison.Ordinal)) - { - sequenceType = SequenceType.GenericIDictionary; - return true; - } - - if (type.FullName.StartsWith("System.Collections.Concurrent.BlockingCollection`1", StringComparison.Ordinal)) - { - sequenceType = SequenceType.GenericBlockingCollection; - return true; - } - - if (type.FullName.StartsWith("System.Collections.Concurrent.ConcurrentBag`1", StringComparison.Ordinal)) - { - sequenceType = SequenceType.GenericConcurrentBag; - return true; - } - - if (type.FullName.StartsWith("System.Collections.Concurrent.ConcurrentDictionary`2[[", StringComparison.Ordinal)) - { - sequenceType = SequenceType.GenericConcurrentDictionary; - return true; - } - - var interfaces = type.GetInterfaces().ToArray(); - - if (interfaces.Any(i => i.Name.StartsWith("IEnumerable`1", StringComparison.Ordinal))) - { - sequenceType = SequenceType.GenericCustom; - return true; - } - - if (interfaces.Any(i => i.Name.StartsWith("IEnumerable", StringComparison.Ordinal))) - { - sequenceType = SequenceType.Custom; - return true; - } - - sequenceType = SequenceType.Invalid; - return false; - } - - /// - /// Determines whether the implements . - /// - [DebuggerStepThrough] - public static bool Implements(this Type type) - { - Ensure.NotNull(type, nameof(type)); - return typeof(T).IsAssignableFrom(type); - } - - /// - /// Determines whether the given has a default constructor. - /// - /// Type to check. - /// True if has a default constructor, False otherwise. - [DebuggerStepThrough] - public static bool HasDefaultConstructor(this Type type) - { - Ensure.NotNull(type, nameof(type)); - return type.IsValueType || type.GetConstructor(Type.EmptyTypes) != null; - } - - /// - /// Determines whether the given is of simple type. - /// - /// The type. - /// True if it is simple type otherwise False. - [DebuggerStepThrough] - public static bool IsSimpleType(this Type type) - { - Ensure.NotNull(type, nameof(type)); - var underlyingType = Nullable.GetUnderlyingType(type); - type = underlyingType ?? type; - - return Array.IndexOf(SimpleTypes, type) > -1 || type.IsEnum; - } - - /// - /// Determines whether the given an array of - /// - /// The Type of the elements in the array. - /// The type of object. - /// True or False - [DebuggerStepThrough] - public static bool IsArrayOf(this Type type) - { - return type == typeof(T[]); - } - - /// - /// Determines whether the given is a generic list - /// - /// The type to evaluate - /// True if is generic otherwise False - [DebuggerStepThrough] - public static bool IsGenericList(this Type type) - { - if (!type.IsGenericType) { return false; } - - var typeDef = type.GetGenericTypeDefinition(); - - if (typeDef == typeof(List<>) || typeDef == typeof(IList<>)) { return true; } - - return false; - } - - /// - /// Determines if the given is numeric. - /// - [DebuggerStepThrough] - public static bool IsNumeric(this Type type) - { - if (type == null) { return false; } - - var underlyingType = Nullable.GetUnderlyingType(type) ?? type; - if (underlyingType.GetTypeInfo().IsEnum) { return false; } - - // ReSharper disable once SwitchStatementMissingSomeCases - switch (underlyingType.GetTypeCode()) - { - case TypeCode.Byte: - case TypeCode.Decimal: - case TypeCode.Double: - case TypeCode.Int16: - case TypeCode.Int32: - case TypeCode.Int64: - case TypeCode.SByte: - case TypeCode.Single: - case TypeCode.UInt16: - case TypeCode.UInt32: - case TypeCode.UInt64: - return true; - default: - return false; - } - } - - /// - /// Gets the for the given . - /// - [DebuggerStepThrough] - public static TypeCode GetTypeCode(this Type type) - { - if (type == typeof(bool)) { return TypeCode.Boolean; } - if (type == typeof(char)) { return TypeCode.Char; } - if (type == typeof(sbyte)) { return TypeCode.SByte; } - if (type == typeof(byte)) { return TypeCode.Byte; } - if (type == typeof(short)) { return TypeCode.Int16; } - if (type == typeof(ushort)) { return TypeCode.UInt16; } - if (type == typeof(int)) { return TypeCode.Int32; } - if (type == typeof(uint)) { return TypeCode.UInt32; } - if (type == typeof(long)) { return TypeCode.Int64; } - if (type == typeof(ulong)) { return TypeCode.UInt64; } - if (type == typeof(float)) { return TypeCode.Single; } - if (type == typeof(double)) { return TypeCode.Double; } - if (type == typeof(decimal)) { return TypeCode.Decimal; } - if (type == typeof(DateTime)) { return TypeCode.DateTime; } - if (type == typeof(string)) { return TypeCode.String; } - // ReSharper disable once TailRecursiveCall - // ReSharper disable once ConvertIfStatementToReturnStatement - if (type.GetTypeInfo().IsEnum) { return Enum.GetUnderlyingType(type).GetTypeCode(); } - return TypeCode.Object; - } - } -} diff --git a/src/Maple.Core/Helpers/ApplicationHelper.cs b/src/Maple.Core/Helpers/ApplicationHelper.cs deleted file mode 100644 index b73b00f..0000000 --- a/src/Maple.Core/Helpers/ApplicationHelper.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; - -namespace Maple.Core -{ - /// - /// A set of helpful methods - /// - public static class ApplicationHelper - { - /// - /// Returns the time taken to start the current process. - /// - public static TimeSpan GetProcessStartupDuration() - { - return DateTime.Now.Subtract(Process.GetCurrentProcess().StartTime); - } - - /// - /// Queries the process's headers to find if it is LARGEADDRESSAWARE. - /// The method is equivalent to running DumpBin on the executable. - /// - public static bool IsProcessLargeAddressAware() - { - using (var p = Process.GetCurrentProcess()) - { - return IsLargeAddressAware(p.MainModule.FileName); - } - } - - /// - /// - /// - internal static bool IsLargeAddressAware(string file) - { - Ensure.NotNullOrEmptyOrWhiteSpace(file); - var fileInfo = new FileInfo(file); - Ensure.Exists(fileInfo); - - const int ImageFileLargeAddressAware = 0x20; - - using (var stream = File.Open(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) - using (var reader = new BinaryReader(stream)) - { - //No MZ Header - if (reader.ReadInt16() != 0x5A4D) { return false; } - - reader.BaseStream.Position = 0x3C; - var peloc = reader.ReadInt32(); //Get the PE header location. - - reader.BaseStream.Position = peloc; - - //No PE header - if (reader.ReadInt32() != 0x4550) { return false; } - - reader.BaseStream.Position += 0x12; - return (reader.ReadInt16() & ImageFileLargeAddressAware) == ImageFileLargeAddressAware; - } - } - } -} diff --git a/src/Maple.Core/Helpers/NetworkHelper.cs b/src/Maple.Core/Helpers/NetworkHelper.cs deleted file mode 100644 index 611ed66..0000000 --- a/src/Maple.Core/Helpers/NetworkHelper.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Net; -using System.Net.NetworkInformation; -using System.Net.Sockets; - -namespace Maple.Core -{ - /// - /// Provides a set of methods to help work with network related activities. - /// - [SuppressMessage("ReSharper", "InconsistentNaming")] - public static class NetworkHelper - { - /// - /// Returns the LocalHost Fully Qualified Domain Name - /// - /// - /// The localhost Fully Qualified Domain Name - public static string GetFQDN() - { - var domainName = IPGlobalProperties.GetIPGlobalProperties().DomainName; - var hostName = Dns.GetHostName(); - - domainName = "." + domainName; - if (!hostName.EndsWith(domainName)) - { - hostName += domainName; - } - - return hostName; - } - - /// - /// Gets the local IP address for the machine or VM running the code. - /// - /// - /// - /// - /// The local IP address - public static IPAddress GetLocalIPAddress() - { - using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0)) - { - // can be any address - socket.Connect("10.0.2.4", 65530); - var endPoint = socket.LocalEndPoint as IPEndPoint; - // ReSharper disable once PossibleNullReferenceException - return IPAddress.Parse(endPoint.Address.ToString()); - } - } - - /// - /// Gets all the IP (v4 and not v6) addresses of the local computer together with - /// the interface to which the IP belongs. - /// - /// - public static IDictionary GetLocalIPAddresses() - { - // Get a list of all network interfaces (usually one per network card, dial-up, and VPN connection) - var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces(); - - var result = new Dictionary(); - foreach (var networkInterface in networkInterfaces) - { - // Read the IP configuration for each network - var properties = networkInterface.GetIPProperties(); - - // Each network interface may have multiple IP addresses - foreach (var address in properties.UnicastAddresses) - { - // We're only interested in IPv4 addresses for now - if (address.Address.AddressFamily != AddressFamily.InterNetwork) { continue; } - - // Ignore loopback addresses (e.g., 127.0.0.1) - if (IPAddress.IsLoopback(address.Address)) { continue; } - - result.Add(address.Address, networkInterface.Name); - } - } - return result; - } - } -} diff --git a/src/Maple.Core/Helpers/ProcessHelper.cs b/src/Maple.Core/Helpers/ProcessHelper.cs deleted file mode 100644 index 8205735..0000000 --- a/src/Maple.Core/Helpers/ProcessHelper.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace Maple.Core -{ - /// - /// Provides a set of methods to help work with a . - /// - public static class ProcessHelper - { - /// - /// Starts a Process Asynchronously. - /// - /// - /// The information for the process to run. - /// The cancellation token. - /// A task representing the started process which you can await until process exits. - public static Task ExecuteAsync(ProcessStartInfo processInfo, CancellationToken cToken = default(CancellationToken)) - { - Ensure.NotNull(processInfo, nameof(processInfo)); - - processInfo.UseShellExecute = false; - processInfo.CreateNoWindow = true; - processInfo.RedirectStandardOutput = true; - processInfo.RedirectStandardError = true; - - var process = new Process - { - EnableRaisingEvents = true, - StartInfo = processInfo - }; - - var tcs = new TaskCompletionSource(); - var standardOutput = new List(); - var standardError = new List(); - - var standardOutputResults = new TaskCompletionSource(); - process.OutputDataReceived += (sender, args) => - { - if (args.Data != null) - standardOutput.Add(args.Data); - else - standardOutputResults.SetResult(standardOutput.ToArray()); - }; - - var standardErrorResults = new TaskCompletionSource(); - process.ErrorDataReceived += (sender, args) => - { - if (args.Data != null) - standardError.Add(args.Data); - else - standardErrorResults.SetResult(standardError.ToArray()); - }; - - process.Exited += (sender, args) => - { - // Since the Exited event can happen asynchronously to the output and error events, - // we use the task results for stdout/stderr to ensure they are both closed - tcs.TrySetResult(new ProcessExecutionResult(process, standardOutputResults.Task.Result, standardErrorResults.Task.Result)); - }; - - using (cToken.Register(() => - { - tcs.TrySetCanceled(); - try - { - if (!process.HasExited) { process.Kill(); } - } - catch (InvalidOperationException) { } - })) - { - cToken.ThrowIfCancellationRequested(); - - if (!process.Start()) - { - tcs.TrySetException(new InvalidOperationException("Failed to start the process.")); - } - - process.BeginOutputReadLine(); - process.BeginErrorReadLine(); - return tcs.Task; - } - } - - /// - /// Starts a process represented by asynchronously. - /// - /// - /// The path to the process. - /// The arguments to be passed to the process. - /// The cancellation token. - /// A task representing the started process which you can await until process exits. - public static Task ExecuteAsync(string processPath, string args, CancellationToken cToken = default(CancellationToken)) - { - Ensure.NotNullOrEmptyOrWhiteSpace(processPath); - return ExecuteAsync(new ProcessStartInfo(processPath, args), cToken); - } - - /// - /// Starts a process represented by and asynchronously. - /// - /// - /// The path to the process. - /// The arguments to be passed to the process. - /// The cancellation token. - /// A task representing the started process which you can await until process exits. - public static Task ExecuteAsync(FileInfo processPath, string args, CancellationToken cToken = default(CancellationToken)) - { - Ensure.NotNull(processPath, nameof(processPath)); - return ExecuteAsync(new ProcessStartInfo(processPath.FullName, args), cToken); - } - } -} diff --git a/src/Maple.Core/IO/Base/MapleFileSystemBase.cs b/src/Maple.Core/IO/Base/MapleFileSystemBase.cs deleted file mode 100644 index 712e670..0000000 --- a/src/Maple.Core/IO/Base/MapleFileSystemBase.cs +++ /dev/null @@ -1,193 +0,0 @@ -using System; -using System.Windows.Input; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - public abstract class MapleFileSystemBase : ViewModel, IFileSystemInfo - { - public static bool NoFilesFilter(object obj) - { - if (obj is IFileSystemFile) - return false; - - return SearchFilter(obj); - } - - public static bool SearchFilter(object obj) - { - var info = obj as IFileSystemInfo; - - if (info == null) - return false; - - if (info.IsHidden || info.IsBusy) - return false; - - if (string.IsNullOrWhiteSpace(info.Filter)) - return true; - - return info.Name.ToLowerInvariant().Contains(info.Filter.ToLowerInvariant()); - } - - public ICommand LoadCommand { get; protected set; } - public ICommand RefreshCommand { get; protected set; } - public ICommand DeleteCommand { get; protected set; } - - private IFileSystemDirectory _parent; - public IFileSystemDirectory Parent - { - get { return _parent; } - protected set { SetValue(ref _parent, value); } - } - - private string _name; - public string Name - { - get { return _name; } - protected set { SetValue(ref _name, value); } - } - - private string _fullName; - public string FullName - { - get { return _fullName; } - protected set { SetValue(ref _fullName, value); } - } - - private string _filter; - public string Filter - { - get { return _filter; } - set { SetValue(ref _filter, value); } - } - - private bool _exists; - public bool Exists - { - get { return _exists; } - protected set { SetValue(ref _exists, value); } - } - - private bool _isLoaded; - public bool IsLoaded - { - get { return _isLoaded; } - protected set { SetValue(ref _isLoaded, value); } - } - - private bool _isExpanded; - public bool IsExpanded - { - get { return _isExpanded; } - set { SetValue(ref _isExpanded, value, OnChanged: OnExpandedChanged); } - } - - private bool _isSelected; - public bool IsSelected - { - get { return _isSelected; } - set { SetValue(ref _isSelected, value); } - } - - private bool _isHidden; - public bool IsHidden - { - get { return _isHidden; } - protected set { SetValue(ref _isHidden, value); } - } - - private bool _isContainer; - public bool IsContainer - { - get { return _isContainer; } - protected set { SetValue(ref _isContainer, value); } - } - - private bool _hasContainers; - public bool HasContainers - { - get { return _hasContainers; } - protected set { SetValue(ref _hasContainers, value); } - } - - private IDepth _depth; - public IDepth Depth - { - get { return _depth; } - protected set { SetValue(ref _depth, value); } - } - - private MapleFileSystemBase(IMessenger messenger) - : base(messenger) - { - LoadCommand = new RelayCommand(Load, CanLoad); - RefreshCommand = new RelayCommand(Refresh, CanRefresh); - DeleteCommand = new RelayCommand(Delete, CanDelete); - - Exists = true; - IsHidden = false; - IsContainer = false; - HasContainers = false; - } - - protected MapleFileSystemBase(string name, string fullName, IDepth depth, IFileSystemDirectory parent, IMessenger messenger) - : this(messenger) - { - if (string.IsNullOrEmpty(name)) - throw new ArgumentNullException(nameof(name), $"{nameof(name)} {Resources.IsRequired}"); - - if (string.IsNullOrEmpty(fullName)) - throw new ArgumentNullException(nameof(fullName), $"{nameof(fullName)} {Resources.IsRequired}"); - - if (depth == null) - throw new ArgumentNullException(nameof(depth), $"{nameof(depth)} {Resources.IsRequired}"); - - if (!(this is IFileSystemDrive) && parent == null) - throw new ArgumentNullException(nameof(parent), $"{nameof(parent)} {Resources.IsRequired}"); - - using (BusyStack.GetToken()) - { - Depth = depth; - Depth.Current++; - - Name = name; - FullName = fullName; - Parent = parent; - } - } - - public void Load() - { - if (IsLoaded) - return; - - Refresh(); - } - - public abstract void Refresh(); - public abstract void LoadMetaData(); - public abstract void OnFilterChanged(string filter); - public abstract void Delete(); - public abstract bool CanDelete(); - - protected bool CanLoad() - { - return !IsBusy && !IsLoaded; - } - - protected bool CanRefresh() - { - return !IsBusy; - } - - private void OnExpandedChanged() - { - if (!IsBusy && !IsLoaded) - { - Load(); - IsLoaded = true; - } - } - } -} diff --git a/src/Maple.Core/IO/Base/MapleFileSystemContainerBase.cs b/src/Maple.Core/IO/Base/MapleFileSystemContainerBase.cs deleted file mode 100644 index 2bb15a3..0000000 --- a/src/Maple.Core/IO/Base/MapleFileSystemContainerBase.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.ComponentModel; -using System.Linq; -using System.Windows.Data; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - public abstract class MapleFileSystemContainerBase : MapleFileSystemBase, IFileSystemDirectory - { - private readonly ILoggingService _loggingService; - - private ICollectionView _noFilesCollectionView; - public ICollectionView NoFilesCollectionView - { - get { return _noFilesCollectionView; } - protected set { SetValue(ref _noFilesCollectionView, value); } - } - - private ICollectionView _defaultCollectionView; - public ICollectionView DefaultCollectionView - { - get { return _defaultCollectionView; } - protected set { SetValue(ref _defaultCollectionView, value); } - } - - private IRangeObservableCollection _children; - public IRangeObservableCollection Children - { - get { return _children; } - private set { SetValue(ref _children, value); } - } - - protected MapleFileSystemContainerBase(string name, string fullName, IDepth depth, IFileSystemDirectory parent, IMessenger messenger, ILoggingService loggingService) - : base(name, fullName, depth, parent, messenger) - { - using (BusyStack.GetToken()) - { - IsContainer = true; - - Children = new RangeObservableCollection(); - - NoFilesCollectionView = CollectionViewSource.GetDefaultView(Children); - DefaultCollectionView = CollectionViewSource.GetDefaultView(Children); - - using (NoFilesCollectionView.DeferRefresh()) - NoFilesCollectionView.Filter = NoFilesFilter; - - using (DefaultCollectionView.DeferRefresh()) - DefaultCollectionView.Filter = SearchFilter; - - _loggingService = loggingService ?? throw new ArgumentNullException(nameof(loggingService), $"{nameof(loggingService)} {Resources.IsRequired}"); - } - } - - public override void OnFilterChanged(string filter) - { - using (BusyStack.GetToken()) - { - Filter = filter; - Children.ForEach(p => p.LoadMetaData()); - Children.ForEach(p => p.Filter = filter); - - using (DefaultCollectionView.DeferRefresh()) - DefaultCollectionView.Filter = SearchFilter; - } - } - - public override void Refresh() - { - using (BusyStack.GetToken()) - { - Children.Clear(); - Children.AddRange(FileSystemExtensions.GetChildren(this, Depth, Messenger, _loggingService)); - HasContainers = Children.Any(p => p is MapleFileSystemContainerBase); - - OnFilterChanged(string.Empty); - } - } - } -} diff --git a/src/Maple.Core/IO/FileSystemBrowser.cs b/src/Maple.Core/IO/FileSystemBrowser.cs deleted file mode 100644 index d2ca981..0000000 --- a/src/Maple.Core/IO/FileSystemBrowser.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Windows.Controls; - -namespace Maple.Core -{ - public class FileSystemBrowser : ContentControl - { - } -} diff --git a/src/Maple.Core/IO/FileSystemViewModel.cs b/src/Maple.Core/IO/FileSystemViewModel.cs deleted file mode 100644 index eea2689..0000000 --- a/src/Maple.Core/IO/FileSystemViewModel.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System.Collections; -using System.IO; -using System.Linq; -using System.Windows.Input; -using Maple.Domain; - -namespace Maple.Core -{ - public class FileSystemViewModel : ViewModel - { - private ICommand _selectCommand; - /// - /// command to update the selected folder or drive in the master view - /// - public ICommand SelectCommand - { - get { return _selectCommand; } - private set { SetValue(ref _selectCommand, value); } - } - - private IRangeObservableCollection _selectedItems; - /// - /// contains either folders or files ready to be used somewhere else - /// - public IRangeObservableCollection SelectedItems - { - get { return _selectedItems; } - private set { SetValue(ref _selectedItems, value); } - } - - private IList _selectedItemsList; - /// - /// bound to contain selected folders and files from the detail view - /// - public IList SelectedItemsList - { - get { return _selectedItemsList; } - set { SetValue(ref _selectedItemsList, value, OnChanged: OnSelectedItemsListChanged); } - } - - private IRangeObservableCollection _drives; - /// - /// the currently available drives of the filesystem - /// - public IRangeObservableCollection Drives - { - get { return _drives; } - private set { SetValue(ref _drives, value); } - } - - private MapleFileSystemContainerBase _selectedItem; - /// - /// the selected item in the master view - /// - public MapleFileSystemContainerBase SelectedItem - { - get { return _selectedItem; } - set { SetValue(ref _selectedItem, value, OnChanged: OnSelectedItemChanged); } - } - - private string _filter; - /// - /// text to search for in the items in the detailview (source is the master view) - /// - public string Filter - { - get { return _filter; } - set { SetValue(ref _filter, value, OnChanged: () => SelectedItem.OnFilterChanged(Filter)); } - } - - private bool _displayListView; - /// - /// flag to switch between different display styles for the detail view - /// - public bool DisplayListView - { - get { return _displayListView; } - set { SetValue(ref _displayListView, value); } - } - - public FileSystemViewModel(IMessenger messenger, ILoggingService loggingService) - : base(messenger) - { - using (BusyStack.GetToken()) - { - DisplayListView = false; - - Drives = new RangeObservableCollection(); - SelectedItems = new RangeObservableCollection(); - - var drives = DriveInfo.GetDrives() - .Where(p => p.IsReady && p.DriveType != DriveType.CDRom && p.DriveType != DriveType.Unknown) - .Select(p => new MapleDrive(p, new FileSystemDepth(0), Messenger, loggingService)) - .ToList(); - Drives.AddRange(drives); - - SelectCommand = new RelayCommand(SetSelectedItem, CanSetSelectedItem); - } - } - - private void OnSelectedItemsListChanged() - { - SelectedItems.Clear(); - SelectedItems.AddRange(SelectedItemsList.Cast()); - } - - private void OnSelectedItemChanged() - { - if (SelectedItem == null) - return; - - SelectedItem.Load(); - SelectedItem.LoadMetaData(); - - Messenger.Publish(new FileSystemInfoChangedMessage(this, SelectedItem)); - } - - public void SetSelectedItem(object item) - { - var value = item as MapleFileSystemContainerBase; - - if (value == null) - return; - - SelectedItem = value; - SelectedItem.ExpandPath(); - SelectedItem.Parent.IsSelected = true; - } - - private bool CanSetSelectedItem(object item) - { - if (item == null) - return false; - - var value = item as MapleFileSystemContainerBase; - - return value != null && value != SelectedItem; - } - } -} diff --git a/src/Maple.Core/IO/IOUtils.cs b/src/Maple.Core/IO/IOUtils.cs deleted file mode 100644 index 92001b9..0000000 --- a/src/Maple.Core/IO/IOUtils.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.IO; -using System.Linq; - -namespace Maple.Core -{ - public static class IOUtils - { - public static bool IsLocalFile(string path) - { - if (ContainsInvalidChars(path)) - return false; - - return File.Exists(path); - } - - private static bool ContainsInvalidChars(string path) - { - var result = false; - var invalidChars = Path.GetInvalidPathChars() - .Concat(Path.GetInvalidFileNameChars()) - .Distinct(); - - for (var i = 0; i < path.Length; i++) - { - result = invalidChars.Contains(path[i]); - if (result) - return true; - } - - return result; - } - } -} diff --git a/src/Maple.Core/IO/Interfaces/IDepth.cs b/src/Maple.Core/IO/Interfaces/IDepth.cs deleted file mode 100644 index 30baa98..0000000 --- a/src/Maple.Core/IO/Interfaces/IDepth.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Maple.Core -{ - public interface IDepth - { - int Current { get; set; } - - int Maximum { get; } - - bool IsMaxReached { get; } - } -} diff --git a/src/Maple.Core/IO/Interfaces/IFileSystemDirectory.cs b/src/Maple.Core/IO/Interfaces/IFileSystemDirectory.cs deleted file mode 100644 index 1298d7f..0000000 --- a/src/Maple.Core/IO/Interfaces/IFileSystemDirectory.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Maple.Domain; - -namespace Maple.Core -{ - public interface IFileSystemDirectory : IFileSystemInfo - { - IRangeObservableCollection Children { get; } - } -} diff --git a/src/Maple.Core/IO/Interfaces/IFileSystemDrive.cs b/src/Maple.Core/IO/Interfaces/IFileSystemDrive.cs deleted file mode 100644 index 52a4064..0000000 --- a/src/Maple.Core/IO/Interfaces/IFileSystemDrive.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Maple.Domain; - -namespace Maple.Core -{ - public interface IFileSystemDrive : IFileSystemInfo - { - IRangeObservableCollection Children { get; } - } -} diff --git a/src/Maple.Core/IO/Interfaces/IFileSystemFile.cs b/src/Maple.Core/IO/Interfaces/IFileSystemFile.cs deleted file mode 100644 index 6c0b687..0000000 --- a/src/Maple.Core/IO/Interfaces/IFileSystemFile.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Maple.Core -{ - public interface IFileSystemFile : IFileSystemInfo - { - - } -} diff --git a/src/Maple.Core/IO/Interfaces/IFileSystemInfo.cs b/src/Maple.Core/IO/Interfaces/IFileSystemInfo.cs deleted file mode 100644 index 4cd8d98..0000000 --- a/src/Maple.Core/IO/Interfaces/IFileSystemInfo.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System.ComponentModel; -using System.Windows.Input; - -namespace Maple.Core -{ - public interface IFileSystemInfo : INotifyPropertyChanged - { - /// - /// conditional refresh - /// - ICommand LoadCommand { get; } - /// - /// explicit refresh - /// - ICommand RefreshCommand { get; } - /// - /// delete an object from the filesystem - /// - ICommand DeleteCommand { get; } - /// - /// the logical parent - /// - IFileSystemDirectory Parent { get; } - - string Name { get; } - string FullName { get; } - string Filter { get; set; } - - bool IsExpanded { get; set; } - bool IsSelected { get; set; } - - bool Exists { get; } - bool IsLoaded { get; } - bool IsBusy { get; } - bool IsHidden { get; } - bool IsContainer { get; } - - bool HasContainers { get; } - - /// - /// updates filtering and the current children - /// - void Refresh(); - /// - /// Loads attributes and checks if the object still exists on file system - /// - void LoadMetaData(); - /// - /// updates the filtering - /// - /// - void OnFilterChanged(string filter); - - void Delete(); - bool CanDelete(); - } -} diff --git a/src/Maple.Core/IO/MapleDirectory.cs b/src/Maple.Core/IO/MapleDirectory.cs deleted file mode 100644 index 75a5023..0000000 --- a/src/Maple.Core/IO/MapleDirectory.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Diagnostics; -using System.IO; -using Maple.Domain; - -namespace Maple.Core -{ - [DebuggerDisplay("Directory: {Name} IsContainer: {IsContainer}")] - public class MapleDirectory : MapleFileSystemContainerBase, IFileSystemDirectory - { - public MapleDirectory(DirectoryInfo info, IDepth depth, IFileSystemDirectory parent, IMessenger messenger, ILoggingService loggingService) - : base(info.Name, info.FullName, depth, parent, messenger, loggingService) - { - using (BusyStack.GetToken()) - { - if (!Depth.IsMaxReached) - Refresh(); - } - } - - public override void LoadMetaData() - { - var info = new DirectoryInfo(FullName); - - Exists = info.Exists; - IsHidden = info.Attributes.HasFlag(FileAttributes.Hidden); - } - - public override void Delete() - { - Directory.Delete(FullName); - Refresh(); - } - - public override bool CanDelete() - { - return Directory.Exists(FullName); - } - } -} diff --git a/src/Maple.Core/IO/MapleDrive.cs b/src/Maple.Core/IO/MapleDrive.cs deleted file mode 100644 index e53b299..0000000 --- a/src/Maple.Core/IO/MapleDrive.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.Diagnostics; -using System.IO; -using Maple.Domain; - -namespace Maple.Core -{ - /// - /// - /// - /// - /// - /// - [DebuggerDisplay("Drive: {Name} IsContainer: {IsContainer}")] - public class MapleDrive : MapleFileSystemContainerBase, IFileSystemDrive - { - /// - /// Initializes a new instance of the class. - /// - /// The information. - /// The depth. - /// - public MapleDrive(DriveInfo info, IDepth depth, IMessenger messenger, ILoggingService loggingService) - : base(info.Name, info.Name, depth, null, messenger, loggingService) - { - using (BusyStack.GetToken()) - { - if (!Depth.IsMaxReached) - Refresh(); - } - } - - /// - /// Loads the meta data. - /// - /// - public override void LoadMetaData() - { - } - - /// - /// Deletes this instance. - /// - /// - public override void Delete() - { - } - - /// - /// Determines whether this instance can delete. - /// - /// - /// true if this instance can delete; otherwise, false. - /// - /// - public override bool CanDelete() - { - return false; - } - } -} diff --git a/src/Maple.Core/IO/MapleFile.cs b/src/Maple.Core/IO/MapleFile.cs deleted file mode 100644 index 76196fb..0000000 --- a/src/Maple.Core/IO/MapleFile.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System.Diagnostics; -using System.IO; - -namespace Maple.Core -{ - /// - /// - /// - /// - /// - /// - [DebuggerDisplay("File: {Name} IsContainer: {IsContainer}")] - public class MapleFile : MapleFileSystemBase, IFileSystemFile - { - public MapleFile(FileInfo info, IDepth depth, IFileSystemDirectory parent, IMessenger messenger) - : base(info.Name, info.FullName, depth, parent, messenger) - { - using (BusyStack.GetToken()) - { - if (!Depth.IsMaxReached) - { - Refresh(); - IsExpanded = true; - } - } - } - - /// - /// Refreshes this instance. - /// - /// - public override void Refresh() - { - using (BusyStack.GetToken()) - { - OnFilterChanged(string.Empty); - } - } - - /// - /// Called when [filter changed]. - /// - /// The filter. - /// - public override void OnFilterChanged(string filter) - { - Filter = filter; - } - - /// - /// Loads the meta data. - /// - /// - public override void LoadMetaData() - { - var info = new FileInfo(FullName); - - Exists = info.Exists; - IsHidden = info.Attributes.HasFlag(FileAttributes.Hidden); - } - - /// - /// Deletes this instance. - /// - /// - public override void Delete() - { - File.Delete(FullName); - Parent.Refresh(); - } - - /// - /// Determines whether this instance can delete. - /// - /// - /// true if this instance can delete; otherwise, false. - /// - /// - public override bool CanDelete() - { - return File.Exists(FullName); - } - } -} diff --git a/src/Maple.Core/IO/Util/FileSystemDepth.cs b/src/Maple.Core/IO/Util/FileSystemDepth.cs deleted file mode 100644 index d93f7cc..0000000 --- a/src/Maple.Core/IO/Util/FileSystemDepth.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace Maple.Core -{ - public class FileSystemDepth : ObservableObject, IDepth - { - public bool IsMaxReached => Current > Maximum; - - private int _maxDepth; - public int Maximum - { - get { return _maxDepth; } - private set { SetValue(ref _maxDepth, value, OnChanged: OnIsMaxReachedChanged); } - } - - private int _depth; - public int Current - { - get { return _depth; } - set { SetValue(ref _depth, value, OnChanged: OnIsMaxReachedChanged); } - } - - public FileSystemDepth(int maxDepth) - { - Maximum = maxDepth; - Current = 0; - } - - private void OnIsMaxReachedChanged() - { - OnPropertyChanged(nameof(IsMaxReached)); - } - } -} diff --git a/src/Maple.Core/IO/Util/FileSystemExtensions.cs b/src/Maple.Core/IO/Util/FileSystemExtensions.cs deleted file mode 100644 index cc85827..0000000 --- a/src/Maple.Core/IO/Util/FileSystemExtensions.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Security.AccessControl; -using System.Security.Permissions; -using Maple.Domain; - -namespace Maple.Core -{ - public static class FileSystemExtensions - { - public static IEnumerable GetChildren(this MapleFileSystemContainerBase directory, IDepth depth, IMessenger messenger, ILoggingService log) - { - var result = new List(); - - if (!CanAccess(directory.FullName, log) && directory.DirectoryIsEmpty()) - return result; - - result.AddRange(GetDirectories(directory.FullName, depth, directory, messenger, log)); - result.AddRange(GetFiles(directory.FullName, depth, directory, messenger, log)); - - return result; - } - - private static bool CanAccess(string path, ILoggingService log) - { - var permission = new FileIOPermission(FileIOPermissionAccess.AllAccess, AccessControlActions.View, path); - - try - { - permission.Demand(); - return true; - } - catch (UnauthorizedAccessException ex) - { - Debug.WriteLine($"{nameof(UnauthorizedAccessException)} occured during reading off {path}"); - Debug.WriteLine(ex.Message); - - log.Error(ex); - return false; - } - } - - private static IEnumerable GetDirectories(string path, IDepth depth, IFileSystemDirectory parent, IMessenger messenger, ILoggingService log) - { - // TODO return missing permissions - - var result = new List(); - try - { - var directories = Directory.GetDirectories(path) - .Select(p => new DirectoryInfo(p)) - .Where(p => p.Attributes.HasFlag(FileAttributes.Directory) - && !p.Attributes.HasFlag(FileAttributes.Hidden) - && !p.Attributes.HasFlag(FileAttributes.System) - && !p.Attributes.HasFlag(FileAttributes.Offline) - && !p.Attributes.HasFlag(FileAttributes.Encrypted)) - .Select(p => new MapleDirectory(p, depth, parent, messenger, log)) - .ToList(); - - result.AddRange(directories); - } - catch (UnauthorizedAccessException ex) - { - Debug.WriteLine($"{nameof(UnauthorizedAccessException)} occured during reading off {path}"); // TODO localize - Debug.WriteLine(ex.Message); - - log.Error(ex); - } - return result; - } - - private static IEnumerable GetFiles(string path, IDepth depth, IFileSystemDirectory parent, IMessenger messenger, ILoggingService log) - { - var result = new List(); - try - { - var files = Directory.GetFiles(path) - .Select(p => new FileInfo(p)) - .Where(p => !p.Attributes.HasFlag(FileAttributes.Directory) - && !p.Attributes.HasFlag(FileAttributes.Hidden) - && !p.Attributes.HasFlag(FileAttributes.System) - && !p.Attributes.HasFlag(FileAttributes.Offline) - && !p.Attributes.HasFlag(FileAttributes.Encrypted)) - .Select(p => new MapleFile(p, depth, parent, messenger)) - .ToList(); - - result.AddRange(files); - } - catch (UnauthorizedAccessException ex) - { - Debug.WriteLine($"{nameof(UnauthorizedAccessException)} occured during reading off {path}"); - Debug.WriteLine(ex.Message); - - log.Error(ex); - } - return result; - } - - public static bool DirectoryIsEmpty(this MapleFileSystemContainerBase info) - { - if (!Directory.Exists(info.FullName)) - return false; - - return DirectoryIsEmpty(info.FullName); - } - - public static bool DirectoryIsEmpty(string path) - { - return !Directory.EnumerateFileSystemEntries(path).Any(); - } - - public static void ExpandPath(this IFileSystemInfo item) - { - item.IsExpanded = true; - var parent = item.Parent; - - while (parent != null) - { - parent.IsExpanded = true; - parent = parent.Parent; - } - } - } -} diff --git a/src/Maple.Core/IO/Util/SelectedTreeViewItemBehavior.cs b/src/Maple.Core/IO/Util/SelectedTreeViewItemBehavior.cs deleted file mode 100644 index af7d48c..0000000 --- a/src/Maple.Core/IO/Util/SelectedTreeViewItemBehavior.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System.Windows; -using System.Windows.Controls; -using System.Windows.Interactivity; - -namespace Maple.Core -{ - /// - /// - /// - /// - /// - public class SelectedTreeViewItemBehavior : Behavior - { - /// - /// Gets or sets the selected item. - /// - /// - /// The selected item. - /// - /// - public object SelectedItem - { - get { return GetValue(SelectedItemProperty); } - set { SetValue(SelectedItemProperty, value); } - } - - /// - /// The selected item property - /// - /// - public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register( - nameof(SelectedItem), - typeof(object), - typeof(SelectedTreeViewItemBehavior), - new UIPropertyMetadata(null, OnSelectedItemChanged)); - - private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) - { - var item = e.NewValue as TreeViewItem; - - item?.SetValue(TreeViewItem.IsSelectedProperty, true); - } - - /// - /// Called when [attached]. - /// - /// - protected override void OnAttached() - { - base.OnAttached(); - - AssociatedObject.SelectedItemChanged += OnTreeViewSelectedItemChanged; - } - - /// - /// Called when [detaching]. - /// - /// - protected override void OnDetaching() - { - base.OnDetaching(); - - if (AssociatedObject != null) - AssociatedObject.SelectedItemChanged -= OnTreeViewSelectedItemChanged; - } - - private void OnTreeViewSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs e) - { - SelectedItem = e.NewValue; - } - } -} diff --git a/src/Maple.Core/Interfaces/IConfigurableWindowSettings.cs b/src/Maple.Core/Interfaces/IConfigurableWindowSettings.cs deleted file mode 100644 index bf370d0..0000000 --- a/src/Maple.Core/Interfaces/IConfigurableWindowSettings.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Windows; - -namespace Maple.Core -{ - /// - /// - /// - public interface IConfigurableWindowSettings - { - /// - /// Returns true if the application has never - /// been run before by the current user. If - /// this returns true, the Window's initial - /// location is determined by the operating - /// system, not the WindowLocation property. - /// - /// - /// true if this instance is first run; otherwise, false. - /// - bool IsFirstRun { get; } - - /// - /// Gets/sets the Window's desktop coordinate. - /// - /// - /// The window location. - /// - Point WindowLocation { get; set; } - - /// - /// Gets/sets the size of the Window. - /// - /// - /// The size of the window. - /// - Size WindowSize { get; set; } - - /// - /// Gets/sets the WindowState of the Window. - /// - /// - /// The state of the window. - /// - WindowState WindowState { get; set; } - } -} diff --git a/src/Maple.Core/Interfaces/IIocFrameworkElement.cs b/src/Maple.Core/Interfaces/IIocFrameworkElement.cs deleted file mode 100644 index 0724ec1..0000000 --- a/src/Maple.Core/Interfaces/IIocFrameworkElement.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Maple.Core -{ - /// - /// - /// - public interface IIocFrameworkElement - { - /// - /// Gets the translation manager. - /// - /// - /// The translation manager. - /// - ILocalizationService TranslationManager { get; } - } -} diff --git a/src/Maple.Core/Interfaces/ILoadableViewModel.cs b/src/Maple.Core/Interfaces/ILoadableViewModel.cs deleted file mode 100644 index e00dcb7..0000000 --- a/src/Maple.Core/Interfaces/ILoadableViewModel.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Windows.Input; -using Maple.Domain; - -namespace Maple.Core -{ - /// - /// - /// - /// - public interface ILoadableViewModel : IRefreshable - { - /// - /// Gets a value indicating whether this instance is loaded. - /// - /// - /// true if this instance is loaded; otherwise, false. - /// - bool IsLoaded { get; } - - ICommand LoadCommand { get; } - ICommand RefreshCommand { get; } - } -} diff --git a/src/Maple.Core/Interfaces/ILocalizationService.cs b/src/Maple.Core/Interfaces/ILocalizationService.cs deleted file mode 100644 index 987ad62..0000000 --- a/src/Maple.Core/Interfaces/ILocalizationService.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Collections.Generic; -using System.ComponentModel; -using System.Globalization; -using Maple.Domain; - -namespace Maple.Core -{ - /// - /// - /// - /// - /// - public interface ILocalizationService : INotifyPropertyChanged, IRefreshable - { - /// - /// Gets or sets the current language. - /// - /// - /// The current language. - /// - CultureInfo CurrentLanguage { get; set; } - /// - /// Gets the languages. - /// - /// - /// The languages. - /// - IEnumerable Languages { get; } - /// - /// Translates the specified key. - /// - /// The key. - /// - string Translate(string key); - } -} diff --git a/src/Maple.Core/Interfaces/ISaveableViewModel.cs b/src/Maple.Core/Interfaces/ISaveableViewModel.cs deleted file mode 100644 index 219cefc..0000000 --- a/src/Maple.Core/Interfaces/ISaveableViewModel.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Windows.Input; - -namespace Maple.Core -{ - public interface ISaveableViewModel - { - ICommand SaveCommand { get; } - } -} diff --git a/src/Maple.Core/Maple.Core.csproj b/src/Maple.Core/Maple.Core.csproj deleted file mode 100644 index e37cb5a..0000000 --- a/src/Maple.Core/Maple.Core.csproj +++ /dev/null @@ -1,194 +0,0 @@ - - - Debug - AnyCPU - {21FA5854-0692-42E2-924E-A38CF3C7FF71} - Library - Properties - Maple.Core - Maple.Core - v4.7.1 - 512 - - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - AnyCPU - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - 2.2.0 - - - 2.2.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - True - Settings.settings - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Designer - - - PublicSettingsSingleFileGenerator - Settings.Designer.cs - - - - - {B3CD46BE-3C08-4BAE-AE60-A6D84A62400C} - Maple.Data - - - {9d7d05a6-8271-4836-a7bb-5b2abeccbd81} - Maple.Domain - - - {A073FC92-90E3-4541-8B52-6F7293187871} - Maple.Localization - - - - \ No newline at end of file diff --git a/src/Maple.Core/Messages/CompletedMediaItemMessage.cs b/src/Maple.Core/Messages/CompletedMediaItemMessage.cs deleted file mode 100644 index 5ef3518..0000000 --- a/src/Maple.Core/Messages/CompletedMediaItemMessage.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Maple.Domain; - -namespace Maple.Core -{ - public class CompletedMediaItemMessage : GenericMapleMessage - { - public CompletedMediaItemMessage(object sender, IMediaItem mediaItem) : base(sender, mediaItem) - { - } - } -} diff --git a/src/Maple.Core/Messages/FileSystemInfoChangedMessage.cs b/src/Maple.Core/Messages/FileSystemInfoChangedMessage.cs deleted file mode 100644 index 3ffb360..0000000 --- a/src/Maple.Core/Messages/FileSystemInfoChangedMessage.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Maple.Core -{ - public class FileSystemInfoChangedMessage : GenericMapleMessage - { - public FileSystemInfoChangedMessage(object sender, IFileSystemInfo info) : base(sender, info) - { - } - } -} diff --git a/src/Maple.Core/Messages/LoadedMessage.cs b/src/Maple.Core/Messages/LoadedMessage.cs deleted file mode 100644 index 92cc23a..0000000 --- a/src/Maple.Core/Messages/LoadedMessage.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Maple.Core -{ - public class LoadedMessage : GenericMapleMessage - { - public LoadedMessage(object sender, ObservableObject viewModel) : base(sender, viewModel) - { - } - } -} diff --git a/src/Maple.Core/Messages/LogMessageReceivedMessage.cs b/src/Maple.Core/Messages/LogMessageReceivedMessage.cs deleted file mode 100644 index d31f192..0000000 --- a/src/Maple.Core/Messages/LogMessageReceivedMessage.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Maple.Core -{ - public class LogMessageReceivedMessage : GenericMapleMessage - { - public LogMessageReceivedMessage(object sender, string content) : base(sender, content) - { - } - } -} diff --git a/src/Maple.Core/Messages/RepeatModeChangedMessage.cs b/src/Maple.Core/Messages/RepeatModeChangedMessage.cs deleted file mode 100644 index a6cf733..0000000 --- a/src/Maple.Core/Messages/RepeatModeChangedMessage.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Maple.Domain; - -namespace Maple.Core -{ - public class RepeatModeChangedMessage : GenericMapleMessage - { - public RepeatModeChangedMessage(object sender, RepeatMode content) : base(sender, content) - { - } - } -} diff --git a/src/Maple.Core/Messages/ShuffleModeChangedMessage.cs b/src/Maple.Core/Messages/ShuffleModeChangedMessage.cs deleted file mode 100644 index 7241efc..0000000 --- a/src/Maple.Core/Messages/ShuffleModeChangedMessage.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Maple.Core -{ - public class ShuffleModeChangedMessage : GenericMapleMessage - { - public ShuffleModeChangedMessage(object sender, bool content) : base(sender, content) - { - } - } -} diff --git a/src/Maple.Core/Messages/UiPrimaryColorChangedMessage.cs b/src/Maple.Core/Messages/UiPrimaryColorChangedMessage.cs deleted file mode 100644 index b9d0cf4..0000000 --- a/src/Maple.Core/Messages/UiPrimaryColorChangedMessage.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Windows.Media; - -namespace Maple.Core -{ - public class UiPrimaryColorChangedMessage : GenericMapleMessage - { - public UiPrimaryColorChangedMessage(object sender, Color color) : base(sender, color) - { - } - } -} diff --git a/src/Maple.Core/Messages/ViewModelSelectionChangedMessage.cs b/src/Maple.Core/Messages/ViewModelSelectionChangedMessage.cs deleted file mode 100644 index ab1c112..0000000 --- a/src/Maple.Core/Messages/ViewModelSelectionChangedMessage.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; - -namespace Maple.Core -{ - public class ViewModelSelectionChangedMessage : GenericMapleMessage - { - public ViewModelSelectionChangedMessage(IReadOnlyCollection sender, TViewModel viewModel) : base(sender, viewModel) - { - } - } -} diff --git a/src/Maple.Core/Messages/ViewModelSelectionChangingMessage.cs b/src/Maple.Core/Messages/ViewModelSelectionChangingMessage.cs deleted file mode 100644 index a2a2fec..0000000 --- a/src/Maple.Core/Messages/ViewModelSelectionChangingMessage.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Maple.Core -{ - public class ViewModelSelectionChangingMessage : GenericMapleMessage - { - public ViewModelSelectionChangingMessage(object sender, TViewModel viewModel) : base(sender, viewModel) - { - } - } -} diff --git a/src/Maple.Core/Observables/Base/ObservableObject.cs b/src/Maple.Core/Observables/Base/ObservableObject.cs deleted file mode 100644 index 163ab2c..0000000 --- a/src/Maple.Core/Observables/Base/ObservableObject.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Runtime.CompilerServices; - -namespace Maple.Core -{ - /// - /// INotifyPropertyChanged base implementation - /// - /// - public abstract class ObservableObject : INotifyPropertyChanged - { - /// - /// Occurs when a property value changes. - /// - public event PropertyChangedEventHandler PropertyChanged; - - /// - /// Called when [property changed]. - /// - /// Name of the property. - protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - protected virtual bool SetValue(ref T field, T value, Action OnChanging = null, Action OnChanged = null, [CallerMemberName]string propertyName = null) - { - if (EqualityComparer.Default.Equals(field, value)) - return false; - - OnChanging?.Invoke(); - - field = value; - OnPropertyChanged(propertyName); - - OnChanged?.Invoke(); - - return true; - } - } -} diff --git a/src/Maple.Core/Observables/BusyStack.cs b/src/Maple.Core/Observables/BusyStack.cs deleted file mode 100644 index 02dba57..0000000 --- a/src/Maple.Core/Observables/BusyStack.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System; -using System.Collections.Concurrent; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - /// - /// - /// - /// - public class BusyStack : ObservableObject - { - private ConcurrentBag _items; - /// - /// Gets or sets the items. - /// - /// - /// The items. - /// - protected ConcurrentBag Items - { - get { return _items; } - set { SetValue(ref _items, value, InvokeOnChanged); } - } - - private Action _onChanged; - /// - /// Gets or sets the on changed. - /// - /// - /// The on changed. - /// - public Action OnChanged - { - get { return _onChanged; } - set { SetValue(ref _onChanged, value); } - } - - /// - /// Initializes a new instance of the class. - /// - public BusyStack() - { - Items = new ConcurrentBag(); - } - - /// - /// Initializes a new instance of the class. - /// - /// The OnChanged Action. - /// onChanged - /// - public BusyStack(Action onChanged) - : this() - { - OnChanged = onChanged ?? throw new ArgumentNullException(nameof(onChanged), $"{nameof(onChanged)} {Resources.IsRequired}"); - } - - /// - /// Tries to take an item from the stack and returns true if that action was successful - /// - /// - public bool Pull() - { - var result = Items.TryTake(out BusyToken token); - - if (result) - InvokeOnChanged(); - - return result; - } - - /// - /// Adds a new to the Stack - /// - /// The token. - public void Push(BusyToken token) - { - Items.Add(token); - - InvokeOnChanged(); - } - - /// - /// Determines whether this instance has items. - /// - /// - /// true if this instance has items; otherwise, false. - /// - public bool HasItems() - { - return Items?.TryPeek(out BusyToken token) ?? false; - } - - /// - /// Returns a new thats associated with instance of a - /// - /// - /// a new - /// - public BusyToken GetToken() - { - return new BusyToken(this); - } - - private void InvokeOnChanged() - { - DispatcherFactory.Invoke(OnChanged, HasItems()); - } - } -} diff --git a/src/Maple.Core/Observables/BusyToken.cs b/src/Maple.Core/Observables/BusyToken.cs deleted file mode 100644 index f8ce9af..0000000 --- a/src/Maple.Core/Observables/BusyToken.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Runtime.Serialization; - -namespace Maple.Core -{ - /// - /// - /// - /// - /// - [Serializable] - public class BusyToken : WeakReference, IDisposable - { - /// - /// Gets a value indicating whether this is disposing. - /// - /// - /// true if disposing; otherwise, false. - /// - public bool Disposing { get; private set; } - - /// - /// Initializes a new instance of the class. - /// - /// The stack. - public BusyToken(BusyStack stack) : base(stack) - { - stack.Push(this); - } - - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose(bool disposing) - { - if (!Disposing) - { - Disposing = true; - - if (Target != null) - { - var stack = Target as BusyStack; - stack?.Pull(); - } - } - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected BusyToken(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - } - } -} diff --git a/src/Maple.Core/Observables/ChangeTracker.cs b/src/Maple.Core/Observables/ChangeTracker.cs deleted file mode 100644 index d67ca3b..0000000 --- a/src/Maple.Core/Observables/ChangeTracker.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - public class ChangeTracker - { - private readonly IDictionary _changes; - public bool HasChanged => _changes.Any(); - - public ChangeTracker() - { - _changes = new Dictionary(); - } - - /// - /// Updates the current state of the ChangeTracker - /// - /// - /// - /// true, if the HasChanged Property changed - public bool Update(object changedValue, [CallerMemberName] string propertyName = null) - { - if (string.IsNullOrEmpty(propertyName)) - throw new ArgumentNullException(nameof(propertyName), $"{nameof(propertyName)} {Resources.IsRequired}"); - - if (_changes.ContainsKey(propertyName)) - { - var group = _changes[propertyName]; - // change back to original value - if (ReferenceEquals(group.OriginalValue, changedValue)) - { - _changes.Remove(propertyName); - return true; - } - else - { - // change to new value - if (!ReferenceEquals(group.NewValue, changedValue)) - { - group.NewValue = changedValue; - _changes[propertyName] = group; - return true; - } - } - - return false; - } - else - { - // add new value - var group = new ChangeGroup - { - OriginalValue = changedValue, - NewValue = changedValue, - }; - _changes.Add(propertyName, group); - return true; - } - } - - private class ChangeGroup - { - public object OriginalValue { get; set; } - public object NewValue { get; set; } - } - } -} diff --git a/src/Maple.Core/Observables/NotifyPropertyChangedExtension.cs b/src/Maple.Core/Observables/NotifyPropertyChangedExtension.cs deleted file mode 100644 index accb748..0000000 --- a/src/Maple.Core/Observables/NotifyPropertyChangedExtension.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Runtime.CompilerServices; - -namespace Maple.Core -{ - public static class NotifyPropertyChangedExtension - { - public static void MutateVerbose(this INotifyPropertyChanged instance, ref TField field, TField newValue, Action raise, [CallerMemberName] string propertyName = null) - { - if (EqualityComparer.Default.Equals(field, newValue)) - return; - - field = newValue; - raise?.Invoke(new PropertyChangedEventArgs(propertyName)); - } - } -} diff --git a/src/Maple.Core/Observables/NotifyTaskCompletion.cs b/src/Maple.Core/Observables/NotifyTaskCompletion.cs deleted file mode 100644 index cdc8650..0000000 --- a/src/Maple.Core/Observables/NotifyTaskCompletion.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.ComponentModel; -using System.Threading.Tasks; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - public sealed class NotifyTaskCompletion : INotifyPropertyChanged - { - public event PropertyChangedEventHandler PropertyChanged; - - public Task Task { get; private set; } - public Task TaskCompletion { get; private set; } - public TResult Result => (Task.Status == TaskStatus.RanToCompletion) ? Task.Result : default(TResult); - - public TaskStatus Status { get { return Task.Status; } } - public bool IsCompleted { get { return Task.IsCompleted; } } - public bool IsNotCompleted { get { return !Task.IsCompleted; } } - public bool IsSuccessfullyCompleted => Task.Status == TaskStatus.RanToCompletion; - - public bool IsCanceled { get { return Task.IsCanceled; } } - public bool IsFaulted { get { return Task.IsFaulted; } } - public AggregateException Exception { get { return Task.Exception; } } - public Exception InnerException => Exception?.InnerException; - public string ErrorMessage => InnerException?.Message; - - public NotifyTaskCompletion(Task task) - { - Task = task ?? throw new ArgumentNullException(nameof(task), $"{nameof(task)} {Resources.IsRequired}"); - TaskCompletion = WatchTaskAsync(task); - } - - private async Task WatchTaskAsync(Task task) - { - try - { - await task.ConfigureAwait(true); - } - catch - { - // no need to catch, since we capture the exception through the property task - } - - var propertyChanged = PropertyChanged; - if (propertyChanged == null) - return; - - propertyChanged(this, new PropertyChangedEventArgs(nameof(Status))); - propertyChanged(this, new PropertyChangedEventArgs(nameof(IsCompleted))); - propertyChanged(this, new PropertyChangedEventArgs(nameof(IsNotCompleted))); - - if (task.IsCanceled) - { - propertyChanged(this, new PropertyChangedEventArgs(nameof(IsCanceled))); - } - else if (task.IsFaulted) - { - propertyChanged(this, new PropertyChangedEventArgs(nameof(IsFaulted))); - propertyChanged(this, new PropertyChangedEventArgs(nameof(Exception))); - propertyChanged(this, new PropertyChangedEventArgs(nameof(InnerException))); - propertyChanged(this, new PropertyChangedEventArgs(nameof(ErrorMessage))); - } - else - { - propertyChanged(this, new PropertyChangedEventArgs(nameof(IsSuccessfullyCompleted))); - propertyChanged(this, new PropertyChangedEventArgs(nameof(Result))); - } - } - } -} diff --git a/src/Maple.Core/Observables/RangeObservableCollection.cs b/src/Maple.Core/Observables/RangeObservableCollection.cs deleted file mode 100644 index ce8f7ac..0000000 --- a/src/Maple.Core/Observables/RangeObservableCollection.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Linq; -using System.Runtime.CompilerServices; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - public class RangeObservableCollection : ObservableCollection, IRangeObservableCollection - { - private bool _suppressNotification; - private readonly BusyStack _busyStack; - - public RangeObservableCollection() - : base() - { - _busyStack = new BusyStack(); - _busyStack.OnChanged += (updatePending) => _suppressNotification = updatePending; - } - - public RangeObservableCollection(IEnumerable items) : this() - { - AddRange(items); - } - - /// - /// Raises the event with the provided arguments. - /// - /// Arguments of the event being raised. - protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) - { - if (!_suppressNotification) - RaiseCollectionChanged(e); - } - - /// - /// Raises the collection changed. - /// - /// The instance containing the event data. - private void RaiseCollectionChanged(NotifyCollectionChangedEventArgs param) - { - base.OnCollectionChanged(param); - } - - public virtual void AddRange(IList items) - { - AddRange(items.Cast()); - } - - public virtual void AddRange(IEnumerable items) - { - if (items == null) - throw new ArgumentNullException(nameof(items), $"{nameof(items)} {Resources.IsRequired}"); - - using (_busyStack.GetToken()) - { - foreach (var item in items) - Add(item); - } - - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); - } - - public virtual void RemoveRange(IEnumerable items) - { - if (items == null) - throw new ArgumentNullException(nameof(items), $"{nameof(items)} {Resources.IsRequired}"); - - using (_busyStack.GetToken()) - { - foreach (var item in items) - Remove(item); - } - - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); - } - - public virtual void RemoveRange(IList items) - { - if (items == null) - throw new ArgumentNullException(nameof(items), $"{nameof(items)} {Resources.IsRequired}"); - - using (_busyStack.GetToken()) - { - foreach (var item in items.Cast()) - Remove(item); - } - - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); - } - - public virtual void RemoveRange(IList items) - { - if (items == null) - throw new ArgumentNullException(nameof(items), $"{nameof(items)} {Resources.IsRequired}"); - - using (_busyStack.GetToken()) - { - foreach (var item in items) - Remove(item); - } - - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); - } - - public void OnPropertyChanged([CallerMemberName]string propertyName = null) - { - OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); - } - - protected override void OnPropertyChanged(PropertyChangedEventArgs e) - { - RaisePropertyChanged(e); - } - - private void RaisePropertyChanged(PropertyChangedEventArgs param) - { - base.OnPropertyChanged(param); - } - - public void AddRange(IList items) - { - AddRange((IEnumerable)items); - } - } -} diff --git a/src/Maple.Core/Observables/ViewModels/BaseDataListViewModel.cs b/src/Maple.Core/Observables/ViewModels/BaseDataListViewModel.cs deleted file mode 100644 index 0b3949d..0000000 --- a/src/Maple.Core/Observables/ViewModels/BaseDataListViewModel.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using System.Windows.Input; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - /// - /// ListViewModel implementation for ObservableObjects related to the DataAccessLayer (DB) - /// - /// a wrapper class implementing - /// a DTO implementing - /// - public abstract class BaseDataListViewModel : BaseListViewModel, ILoadableViewModel - where TViewModel : BaseDataViewModel, ISequence - where TModel : class, IBaseObject - { - protected readonly ISequenceService _sequenceProvider; - protected readonly ILocalizationService _translationService; - protected readonly ILoggingService _log; - - /// - /// Gets the load command. - /// - /// - /// The load command. - /// - public ICommand LoadCommand => AsyncCommand.Create(LoadAsync, () => !IsLoaded); - /// - /// Gets the refresh command. - /// - /// - /// The refresh command. - /// - public ICommand RefreshCommand => AsyncCommand.Create(LoadAsync); - /// - /// Gets the save command. - /// - /// - /// The save command. - /// - public ICommand SaveCommand => new RelayCommand(Save); - - protected BaseDataListViewModel(ViewModelServiceContainer container) - : base(container.Messenger) - { - _log = container.Log; - _translationService = container.LocalizationService; - _sequenceProvider = container.SequenceService; - } - - public abstract Task LoadAsync(); - public abstract void Save(); - - /// - /// Removes the specified item. - /// - /// The item. - public override void Remove(TViewModel viewModel) - { - if (viewModel == null) - throw new ArgumentNullException(nameof(viewModel), $"{nameof(viewModel)} {Resources.IsRequired}"); - - using (BusyStack.GetToken()) - { - while (Items.Contains(viewModel)) - { - viewModel.Model.IsDeleted = true; - base.Remove(viewModel); - } - } - } - - /// - /// Removes the range. - /// - /// The items. - public override void RemoveRange(IEnumerable items) - { - if (items == null) - throw new ArgumentNullException(nameof(items), $"{nameof(items)} {Resources.IsRequired}"); - - using (BusyStack.GetToken()) - { - items.ForEach(p => p.Model.IsDeleted = true); - base.RemoveRange(items); - } - } - - /// - /// Removes the range. - /// - /// The items. - /// items - public override void RemoveRange(IList items) - { - if (items == null) - throw new ArgumentNullException(nameof(items), $"{nameof(items)} {Resources.IsRequired}"); - - using (BusyStack.GetToken()) - { - foreach (var item in items) - Remove(item as TViewModel); - } - } - - public override void Add(TViewModel viewModel) - { - if (viewModel == null) - throw new ArgumentNullException(nameof(viewModel), $"{nameof(viewModel)} {Resources.IsRequired}"); - - var sequence = _sequenceProvider.Get(Items.Cast().ToList()); - viewModel.Sequence = sequence; - base.Add(viewModel); - } - - public override void AddRange(IEnumerable items) - { - if (items == null) - throw new ArgumentNullException(nameof(items), $"{nameof(items)} {Resources.IsRequired}"); - - using (BusyStack.GetToken()) - { - var added = false; - var sequence = _sequenceProvider.Get(Items.Cast().ToList()); - - foreach (var item in items) - { - item.Sequence = sequence; - Add(item); - - sequence++; - added = true; - } - - if (SelectedItem == null && added) - SelectedItem = Items.First(); - } - } - } -} diff --git a/src/Maple.Core/Observables/ViewModels/BaseDataViewModel.cs b/src/Maple.Core/Observables/ViewModels/BaseDataViewModel.cs deleted file mode 100644 index b3fbbd4..0000000 --- a/src/Maple.Core/Observables/ViewModels/BaseDataViewModel.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using Maple.Domain; - -namespace Maple.Core -{ - public abstract class BaseDataViewModel : BaseViewModel - where TModel : class, IBaseObject - { - protected ChangeTracker ChangeTracker { get; } - protected bool SkipChangeTracking { get; set; } - - public bool IsChanged - { - get { return ChangeTracker.HasChanged; } - } - - protected override bool SetValue(ref T field, T value, Action OnChanging = null, Action OnChanged = null, [CallerMemberName] string propertyName = null) - { - var result = base.SetValue(ref field, value, OnChanging, OnChanged, propertyName); - - if (result) - { - if (!SkipChangeTracking && ChangeTracker.Update(value, propertyName)) - OnPropertyChanged(nameof(IsChanged)); - } - - return result; - } - - protected BaseDataViewModel(TModel model, IMessenger messenger) - : base(model, messenger) - { - SkipChangeTracking = true; - - ChangeTracker = new ChangeTracker(); - Model = model ?? throw new ArgumentNullException(nameof(model)); - - SkipChangeTracking = false; - } - } -} diff --git a/src/Maple.Core/Observables/ViewModels/BaseListViewModel.cs b/src/Maple.Core/Observables/ViewModels/BaseListViewModel.cs deleted file mode 100644 index f6f54aa..0000000 --- a/src/Maple.Core/Observables/ViewModels/BaseListViewModel.cs +++ /dev/null @@ -1,249 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Windows.Data; -using System.Windows.Input; -using Maple.Domain; - -namespace Maple.Core -{ - /// - /// ListViewModel implementation for ObservableObjects unrelated to the DataAccessLayer (DB) - /// - /// a class implementing - /// - public abstract class BaseListViewModel : ViewModel - where TViewModel : INotifyPropertyChanged - { - protected readonly object _itemsLock; - - /// - /// Indicates whether the LoadCommand/ the Load Method has been executed yet - /// - public bool IsLoaded { get; protected set; } - - private TViewModel _selectedItem; - public virtual TViewModel SelectedItem - { - get { return _selectedItem; } - set - { - if (EqualityComparer.Default.Equals(_selectedItem, value)) - return; - - Messenger.Publish(new ViewModelSelectionChangingMessage(Items, _selectedItem)); - _selectedItem = value; - Messenger.Publish(new ViewModelSelectionChangedMessage(Items, _selectedItem)); - - OnPropertyChanged(); - } - } - - private IRangeObservableCollection _items; - /// - /// Contains all the UI relevant Models and notifies about changes in the collection and inside the Models themself - /// - [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public IReadOnlyCollection Items - { - get { return (IReadOnlyCollection)_items; } - private set { SetValue(ref _items, (IRangeObservableCollection)value); } - } - - private ICollectionView _view; - /// - /// For grouping, sorting and filtering - /// - /// - /// The view. - /// - public ICollectionView View - { - get { return _view; } - private set { SetValue(ref _view, value); } - } - - public int Count => Items?.Count ?? 0; - /// - /// Gets the at the specified index. - /// - /// - /// The . - /// - /// The index. - /// - public TViewModel this[int index] - { - get { return _items[index]; } - } - - public ICommand RemoveRangeCommand { get; private set; } - public ICommand RemoveCommand { get; private set; } - public ICommand ClearCommand { get; private set; } - public ICommand AddCommand { get; protected set; } - - protected BaseListViewModel(IMessenger messenger) - : base(messenger) - { - _itemsLock = new object(); - - - Items = new RangeObservableCollection(); - _items.CollectionChanged += ItemsCollectionChanged; - - View = CollectionViewSource.GetDefaultView(Items); - - // initial Notification, so that UI recognizes the value - OnPropertyChanged(nameof(Count)); - - InitializeCommands(); - - BindingOperations.EnableCollectionSynchronization(Items, _itemsLock); - } - - protected BaseListViewModel(IList items, IMessenger messenger) - : this(messenger) - { - AddRange(items); - } - - protected BaseListViewModel(IEnumerable items, IMessenger messenger) - : this(messenger) - { - AddRange(items); - } - - private void InitializeCommands() - { - RemoveCommand = new RelayCommand(Remove, CanRemove); - RemoveRangeCommand = new RelayCommand(RemoveRange, CanRemoveRange); - ClearCommand = new RelayCommand(() => Clear(), CanClear); - } - - private void ItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - OnPropertyChanged(nameof(Count)); - } - - protected virtual void OnLoaded() - { - IsLoaded = true; - Messenger.Publish(new LoadedMessage(this, this)); - } - - /// - /// Adds the specified item. - /// - /// The item. - /// item - public virtual void Add(TViewModel item) - { - if (item == null) - throw new ArgumentNullException(nameof(item)); - - using (BusyStack.GetToken()) - _items.Add(item); - } - - /// The items. - /// items - public virtual void AddRange(IEnumerable items) - { - if (items == null) - throw new ArgumentNullException(nameof(items)); - - using (BusyStack.GetToken()) - _items.AddRange(items); - } - - protected virtual bool CanAdd(TViewModel item) - { - return Items != null && item != null; - } - - /// - /// Removes the specified item. - /// - /// The item. - public virtual void Remove(TViewModel item) - { - using (BusyStack.GetToken()) - _items.Remove(item); - } - - /// The items. - /// items - public virtual void RemoveRange(IEnumerable items) - { - if (items == null) - throw new ArgumentNullException(nameof(items)); - - using (BusyStack.GetToken()) - _items.RemoveRange(items); - } - - /// The items. - /// items - public virtual void RemoveRange(IList items) - { - if (items == null) - throw new ArgumentNullException(nameof(items)); - - using (BusyStack.GetToken()) - _items.RemoveRange(items.Cast()); - } - - /// - /// Determines whether this instance can remove the specified item. - /// - /// The item. - /// - /// true if this instance can remove the specified item; otherwise, false. - /// - public virtual bool CanRemove(TViewModel item) - { - return CanClear() && item != null && Items.Contains(item); - } - - /// - /// Checks if any of the submitted items can be removed - /// - /// The items. - /// - /// true if this instance [can remove range] the specified items; otherwise, false. - /// - public virtual bool CanRemoveRange(IEnumerable items) - { - return CanClear() && items != null && items.Any(p => Items.Contains(p)); - } - - /// - /// Determines whether this instance [can remove range] the specified items. - /// - /// The items. - /// - /// true if this instance [can remove range] the specified items; otherwise, false. - /// - public virtual bool CanRemoveRange(IList items) - { - return items == null ? false : CanRemoveRange(items.Cast()); - } - - public virtual void Clear() - { - SelectedItem = default(TViewModel); - - using (BusyStack.GetToken()) - _items.Clear(); - } - - public virtual bool CanClear() - { - return Items?.Count > 0 && !IsBusy; - } - } -} diff --git a/src/Maple.Core/Observables/ViewModels/BaseViewModel.cs b/src/Maple.Core/Observables/ViewModels/BaseViewModel.cs deleted file mode 100644 index dcebcc8..0000000 --- a/src/Maple.Core/Observables/ViewModels/BaseViewModel.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Maple.Core -{ - public abstract class BaseViewModel : ViewModel - { - private TViewModel _model; - public TViewModel Model - { - get { return _model; } - protected set { SetValue(ref _model, value); } - } - - protected BaseViewModel(TViewModel model, IMessenger messenger) - : base(messenger) - { - _model = model; - } - } -} diff --git a/src/Maple.Core/Observables/ViewModels/ValidableBaseDataViewModel.cs b/src/Maple.Core/Observables/ViewModels/ValidableBaseDataViewModel.cs deleted file mode 100644 index 9cd4649..0000000 --- a/src/Maple.Core/Observables/ViewModels/ValidableBaseDataViewModel.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Runtime.CompilerServices; -using FluentValidation; -using FluentValidation.Results; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - public abstract class ValidableBaseDataViewModel : BaseDataViewModel, INotifyDataErrorInfo - where TViewModel : BaseDataViewModel, ISequence - where TModel : class, IBaseObject - { - protected bool SkipValidation { get; set; } - - protected IValidator Validator { get; } - protected IDictionary Messages { get; } - - public event EventHandler ErrorsChanged; - - public bool HasErrors => Messages.Any(p => !p.Value.IsValid); - - protected ValidableBaseDataViewModel(TModel model, IValidator validator, IMessenger messenger) - : base(model, messenger) - { - SkipChangeTracking = true; - SkipValidation = true; - - Messages = new Dictionary(); - - Validator = validator ?? throw new ArgumentNullException(nameof(validator), $"{nameof(validator)} {Resources.IsRequired}"); //order is important in this case - Model = model ?? throw new ArgumentNullException(nameof(model), $"{nameof(model)} {Resources.IsRequired}"); - - SkipChangeTracking = false; - } - - public virtual void Validate() - { - SkipValidation = false; - var result = Validator.Validate(this); - // TODO figure out how i can get update the errors dictionary from this - // aka get propertyNames from the validator - - // run validation on all properties and rules - } - - public IEnumerable GetErrors(string propertyName) - { - if (string.IsNullOrEmpty(propertyName)) - return Messages.SelectMany(p => p.Value.Errors.Select(f => f.ErrorMessage)); - - if (Messages?.ContainsKey(propertyName) != true) - return Enumerable.Empty(); - - return Messages[propertyName].Errors.Select(p => p.ErrorMessage); - } - - /// - /// Validates the specified property name. - /// - /// Name of the property. - /// - /// - public virtual void Validate([CallerMemberName] string propertyName = null) - { - if (SkipValidation) - return; - - if (string.IsNullOrEmpty(propertyName)) - throw new ArgumentNullException(propertyName, $"{nameof(propertyName)} {Resources.IsRequired}"); - - AddOrUpdateValidationResults(Validator.Validate(this, propertyName), propertyName); - } - - protected override void OnPropertyChanged([CallerMemberName] string propertyName = null) - { - base.OnPropertyChanged(propertyName); - - if (this == null || SkipValidation) - return; - - AddOrUpdateValidationResults(Validator.Validate(this, propertyName), propertyName); - } - - private void AddOrUpdateValidationResults(ValidationResult result, string propertyName) - { - if (result == null) - throw new ArgumentNullException(nameof(result), $"{nameof(result)} {Resources.IsRequired}"); - - if (SkipValidation) - return; - - var hadErrors = false; - - if (Messages.ContainsKey(propertyName)) - { - hadErrors = Messages[propertyName].Errors.Count > 0; - - Messages[propertyName].Errors.Clear(); - Messages[propertyName] = result; - } - else - Messages.Add(propertyName, result); - - if (hadErrors != (result?.IsValid ?? false)) - return; - - OnErrorsChanged(propertyName); - - if (Debugger.IsAttached) - { - foreach (var item in Messages[propertyName].Errors) - Debug.WriteLine(item); - } - } - - protected void OnErrorsChanged(string propertyName) - { - ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName)); - } - } -} diff --git a/src/Maple.Core/Observables/ViewModels/ViewModel.cs b/src/Maple.Core/Observables/ViewModels/ViewModel.cs deleted file mode 100644 index cc473f4..0000000 --- a/src/Maple.Core/Observables/ViewModels/ViewModel.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Collections.Generic; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - public abstract class ViewModel : ObservableObject, IDisposable - { - protected IMessenger Messenger { get; } - protected BusyStack BusyStack { get; } - - protected bool Disposed { get; set; } - protected ICollection MessageTokens { get; private set; } - - private bool _isBusy; - public bool IsBusy - { - get { return _isBusy; } - set { SetValue(ref _isBusy, value); } - } - - protected ViewModel(IMessenger messenger) - { - BusyStack = new BusyStack(); - BusyStack.OnChanged += (isBusy) => IsBusy = isBusy; - MessageTokens = new List(); - - Messenger = messenger ?? throw new ArgumentNullException(nameof(messenger), $"{nameof(messenger)} {Resources.IsRequired}"); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (Disposed) - return; - - if (disposing) - { - if (MessageTokens != null) - { - foreach (var token in MessageTokens) - Messenger.Unsubscribe(token); - - MessageTokens = null; - } - - // Free any other managed objects here. - } - - // Free any unmanaged objects here. - Disposed = true; - } - } -} diff --git a/src/Maple.Core/ProcessExecutionResult.cs b/src/Maple.Core/ProcessExecutionResult.cs deleted file mode 100644 index ab1f89f..0000000 --- a/src/Maple.Core/ProcessExecutionResult.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Diagnostics; - -namespace Maple.Core -{ - /// - /// Represents the result of executing a process. - /// - public sealed class ProcessExecutionResult : IDisposable - { - private Process _process; - private bool _disposed; - - internal ProcessExecutionResult(Process process, string[] standardOutput, string[] standardError) - { - _process = Ensure.NotNull(process, nameof(process)); - - PID = _process.Id; - ExecutionTime = _process.ExitTime - _process.StartTime; - StandardOutput = Ensure.NotNull(standardOutput, nameof(standardOutput)); - StandardError = Ensure.NotNull(standardError, nameof(standardError)); - } - - /// - /// Gets the process ID. - /// - // ReSharper disable once InconsistentNaming - public int PID { get; } - - /// - /// Gets the execution time of the process. - /// - public TimeSpan ExecutionTime { get; } - - /// - /// Gets the standard output of the process. - /// - public string[] StandardOutput { get; } - - /// - /// Gets the standard error of the process. - /// - public string[] StandardError { get; } - - /// - /// Read the value of the process property identified by the given . - /// - public T ReadProcessInfo(Func selector) - { - return selector(_process); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Releases all resources used by the underlying process. - /// - private void Dispose(bool disposing) - { - if (_disposed) - return; - - if (disposing) - { - if (_process != null) - { - _process.Dispose(); - _process = null; - } - } - - _disposed = true; - } - } -} diff --git a/src/Maple.Core/Properties/AssemblyInfo.cs b/src/Maple.Core/Properties/AssemblyInfo.cs deleted file mode 100644 index 88e3a6a..0000000 --- a/src/Maple.Core/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,5 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("Maple.Core")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] diff --git a/src/Maple.Core/Properties/Settings.Designer.cs b/src/Maple.Core/Properties/Settings.Designer.cs deleted file mode 100644 index d81a082..0000000 --- a/src/Maple.Core/Properties/Settings.Designer.cs +++ /dev/null @@ -1,45 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Maple.Core.Properties -{ - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.5.0.0")] - public sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase - { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default - { - get - { - return defaultInstance; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("en")] - public global::System.Globalization.CultureInfo StartUpCulture - { - get - { - return ((global::System.Globalization.CultureInfo)(this["StartUpCulture"])); - } - set - { - this["StartUpCulture"] = value; - } - } - } -} diff --git a/src/Maple.Core/Properties/Settings.settings b/src/Maple.Core/Properties/Settings.settings deleted file mode 100644 index 0c48859..0000000 --- a/src/Maple.Core/Properties/Settings.settings +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - en - - - \ No newline at end of file diff --git a/src/Maple.Core/Services/DetailLoggingService.cs b/src/Maple.Core/Services/DetailLoggingService.cs deleted file mode 100644 index 2a40703..0000000 --- a/src/Maple.Core/Services/DetailLoggingService.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - /// - /// Generates a Diagnostic report when exceptions are being thrown around - /// - public class DetailLoggingService : ILoggingService - { - private readonly ILoggingService _log; - - private bool _hasLoggedException = false; - - public DetailLoggingService(ILoggingService log) - { - _log = log ?? throw new ArgumentNullException(nameof(log), $"{nameof(log)} {Resources.IsRequired}"); - } - - public void Error(object message) - { - if (!_hasLoggedException) - _log.Error(DiagnosticReport.Generate(DiagnosticReportType.Full)); - - _log.Error(message); - - _hasLoggedException = true; - } - - public void Error(object message, Exception exception) - { - if (!_hasLoggedException) - _log.Error(DiagnosticReport.Generate(DiagnosticReportType.Full)); - - _log.Error(message, exception); - - _hasLoggedException = true; - } - - public void Fatal(object message) - { - if (!_hasLoggedException) - _log.Fatal(DiagnosticReport.Generate(DiagnosticReportType.Full)); - - _log.Fatal(message); - - _hasLoggedException = true; - } - - public void Fatal(object message, Exception exception) - { - if (!_hasLoggedException) - _log.Fatal(DiagnosticReport.Generate(DiagnosticReportType.Full)); - - _log.Fatal(message, exception); - - _hasLoggedException = true; - } - - public void Info(object message) - { - _log.Info(message); - } - - public void Info(object message, Exception exception) - { - _log.Info(message, exception); - } - - public void Warn(object message) - { - _log.Warn(message); - } - - public void Warn(object message, Exception exception) - { - _log.Warn(message, exception); - } - } -} diff --git a/src/Maple.Core/Services/Localization/LocalizationDTO.cs b/src/Maple.Core/Services/Localization/LocalizationDTO.cs deleted file mode 100644 index 6e762f7..0000000 --- a/src/Maple.Core/Services/Localization/LocalizationDTO.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.ComponentModel; -using System.Windows; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - /// - /// Poco that holds localization data and supports changing it during runtime - /// - /// - /// - /// - /// - public class LocalizationDTO : ObservableObject, INotifyPropertyChanged, IDisposable - { - private readonly string _key; - private readonly ILocalizationService _service; - private readonly bool _toUpper; - - public LocalizationDTO(ILocalizationService service, string key, bool toUpper) - { - _service = service ?? throw new ArgumentNullException(nameof(service), $"{nameof(service)} {Resources.IsRequired}"); - _key = key ?? throw new ArgumentNullException(nameof(key), $"{nameof(key)} {Resources.IsRequired}"); - _toUpper = toUpper; - - WeakEventManager.AddHandler(_service, "PropertyChanged", ValueChanged); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - WeakEventManager.RemoveHandler(_service, "PropertyChanged", ValueChanged); - } - - public object Value - { - get { return GetValue(); } - } - - private void ValueChanged(object sender, PropertyChangedEventArgs e) - { - OnPropertyChanged(nameof(Value)); - } - - private string GetValue() - { - if (_toUpper) - return _service?.Translate(_key).ToUpperInvariant(); - - return _service?.Translate(_key); - } - } -} diff --git a/src/Maple.Core/Services/Localization/LocalizationService.cs b/src/Maple.Core/Services/Localization/LocalizationService.cs deleted file mode 100644 index 36bd82b..0000000 --- a/src/Maple.Core/Services/Localization/LocalizationService.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - public class LocalizationService : ObservableObject, ILocalizationService - { - public ITranslationProvider TranslationProvider { get; private set; } - public readonly ILoggingService _log; - - private CultureInfo _currentLanguage; - public CultureInfo CurrentLanguage - { - get { return _currentLanguage; } - set { SetValue(ref _currentLanguage, value, () => Thread.CurrentThread.CurrentUICulture = value); } - } - - public IEnumerable Languages - { - get - { - if (TranslationProvider != null) - return TranslationProvider.Languages; - - return Enumerable.Empty(); - } - } - - public LocalizationService(ITranslationProvider provider, ILoggingService log) - { - _log = log ?? throw new ArgumentNullException(nameof(log), $"{nameof(log)} {Resources.IsRequired}"); - TranslationProvider = provider ?? throw new ArgumentNullException(nameof(provider), $"{nameof(provider)} {Resources.IsRequired}"); - _currentLanguage = Thread.CurrentThread.CurrentUICulture; - } - - public string Translate(string key) - { - if (TranslationProvider != null) - { - if (Thread.CurrentThread.CurrentUICulture != CurrentLanguage) - Thread.CurrentThread.CurrentUICulture = CurrentLanguage; - - var translatedValue = TranslationProvider.Translate(key); - if (!string.IsNullOrEmpty(translatedValue)) - return translatedValue; - } - - return $"!{key}!"; - } - - public void Save() - { - Properties.Settings.Default.StartUpCulture = CurrentLanguage; - Properties.Settings.Default.Save(); - } - - public void Load() - { - _log.Info($"{Resources.Loading} {GetType().Name}"); - Thread.CurrentThread.CurrentCulture = Properties.Settings.Default.StartUpCulture; - } - - public Task SaveAsync() - { - Save(); - return Task.CompletedTask; - } - - public Task LoadAsync() - { - Load(); - return Task.CompletedTask; - } - } -} diff --git a/src/Maple.Core/Services/Localization/Providers/ResxTranslationProvider.cs b/src/Maple.Core/Services/Localization/Providers/ResxTranslationProvider.cs deleted file mode 100644 index dd375a8..0000000 --- a/src/Maple.Core/Services/Localization/Providers/ResxTranslationProvider.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Collections.Generic; -using System.Globalization; -using System.Resources; -using Maple.Domain; - -namespace Maple.Core -{ - public class ResxTranslationProvider : ITranslationProvider - { - private readonly ResourceManager _resourceManager; - - /// - /// Initializes a new instance of the class. - /// - /// Name of the base. - /// The assembly. - public ResxTranslationProvider() - { - _resourceManager = new ResourceManager(typeof(Localization.Properties.Resources)); - } - - /// - /// See - /// - public string Translate(string key) - { - return _resourceManager.GetString(key); - } - - /// - /// See - /// - /// - /// The available languages. - /// - public IEnumerable Languages - { - get - { - yield return new CultureInfo("de"); - yield return new CultureInfo("en"); - } - } - } -} diff --git a/src/Maple.Core/Services/LogNotifcationService.cs b/src/Maple.Core/Services/LogNotifcationService.cs deleted file mode 100644 index e8e05c8..0000000 --- a/src/Maple.Core/Services/LogNotifcationService.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - public class LoggingNotifcationService : ILoggingNotifcationService - { - private readonly ILoggingService _log; - private readonly IMessenger _messenger; - - public LoggingNotifcationService(IMessenger messenger, ILoggingService log) - { - _log = log ?? throw new ArgumentNullException(nameof(log), $"{nameof(log)} {Resources.IsRequired}"); - _messenger = messenger ?? throw new ArgumentNullException(nameof(messenger), $"{nameof(messenger)} {Resources.IsRequired}"); - } - - public void Info(object message) - { - _log.Info(message); - - if (message is string text) - _messenger.Publish(new LogMessageReceivedMessage(this, text)); - } - - public void Warn(object message) - { - _log.Warn(message); - } - - public void Error(object message, Exception exception) - { - _log.Error(message, exception); - } - - public void Fatal(object message, Exception exception) - { - _log.Fatal(message, exception); - } - } -} diff --git a/src/Maple.Core/Services/LoggingService.cs b/src/Maple.Core/Services/LoggingService.cs deleted file mode 100644 index 32d04b0..0000000 --- a/src/Maple.Core/Services/LoggingService.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System; -using log4net; -using Maple.Domain; - -namespace Maple.Core -{ - /// - /// - /// - /// - public class LoggingService : ILoggingService - { - private readonly ILog _log; - - /// - /// Initializes a new instance of the class. - /// - public LoggingService() - { - log4net.Config.XmlConfigurator.Configure(); - _log = LogManager.GetLogger(typeof(LoggingService)); - } - - public void Debug(object message) - { - var text = (string)message; - - System.Diagnostics.Debug.WriteLine(text); - _log.Debug(text); - } - - /// - /// Informations the specified message. - /// - /// The message. - /// The exception. - public void Debug(object message, Exception exception) - { - var text = (string)message; - - System.Diagnostics.Debug.WriteLine(text); - _log.Debug(message, exception); - } - - /// - /// Errors the specified message. - /// - /// The message. - public void Error(object message) - { - _log.Error(message); - } - - /// - /// Errors the specified message. - /// - /// The message. - /// The exception. - public void Error(object message, Exception exception) - { - _log.Error(message, exception); - } - - public void Fatal(object message) - { - _log.Fatal(message); - } - - public void Fatal(object message, Exception exception) - { - _log.Fatal(message, exception); - } - - public void Info(object message) - { - var text = (string)message; - - _log.Info(text); - } - - /// - /// Informations the specified message. - /// - /// The message. - /// The exception. - public void Info(object message, Exception exception) - { - var text = (string)message; - - _log.Info(message, exception); - } - - /// - /// Warns the specified message. - /// - /// The message. - public void Warn(object message) - { - _log.Warn(message); - } - - /// - /// Warns the specified message. - /// - /// The message. - /// The exception. - public void Warn(object message, Exception exception) - { - _log.Warn(message, exception); - } - } -} diff --git a/src/Maple.Core/Services/MrlExtractionService.cs b/src/Maple.Core/Services/MrlExtractionService.cs deleted file mode 100644 index 630b572..0000000 --- a/src/Maple.Core/Services/MrlExtractionService.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Collections.Generic; -using YoutubeExtractor; - -namespace Maple.Core -{ - public static class MrlExtractionService - { - public static IEnumerable GetMrls(string url) - { - var normalizedUrl = string.Empty; - - if (DownloadUrlResolver.TryNormalizeYoutubeUrl(url, out normalizedUrl)) - { - var videoInfos = DownloadUrlResolver.GetDownloadUrls(normalizedUrl); - - foreach (var item in videoInfos) - yield return item.DownloadUrl; - } - } - } -} diff --git a/src/Maple.Core/Services/ViewModelServiceContainer.cs b/src/Maple.Core/Services/ViewModelServiceContainer.cs deleted file mode 100644 index 8612b20..0000000 --- a/src/Maple.Core/Services/ViewModelServiceContainer.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple.Core -{ - public class ViewModelServiceContainer - { - public ILoggingNotifcationService NotificationService { get; } - public ILocalizationService LocalizationService { get; } - public ISequenceService SequenceService { get; } - public IMessenger Messenger { get; } - public ILoggingService Log { get; } - - public ViewModelServiceContainer(ILoggingService log, ILoggingNotifcationService notificationService, ILocalizationService localizationService, IMessenger messenger, ISequenceService sequenceService) - { - Log = log ?? throw new ArgumentNullException(nameof(log), $"{nameof(log)} {Resources.IsRequired}"); - LocalizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService), $"{nameof(localizationService)} {Resources.IsRequired}"); - SequenceService = sequenceService ?? throw new ArgumentNullException(nameof(sequenceService), $"{nameof(sequenceService)} {Resources.IsRequired}"); - Messenger = messenger ?? throw new ArgumentNullException(nameof(messenger), $"{nameof(messenger)} {Resources.IsRequired}"); - NotificationService = notificationService ?? throw new ArgumentNullException(nameof(notificationService), $"{nameof(notificationService)} {Resources.IsRequired}"); - } - } -} diff --git a/src/Maple.Core/StringBuilderCache.cs b/src/Maple.Core/StringBuilderCache.cs deleted file mode 100644 index a94b4bb..0000000 --- a/src/Maple.Core/StringBuilderCache.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Diagnostics; -using System.Text; - -namespace Maple.Core -{ - /// - /// Provides a cached reusable instance of per thread - /// it is an optimization that reduces the number of instances constructed and collected. - /// - /// A StringBuilder instance is cached in Thread Local Storage and so there is one per thread. - /// - /// - public static class StringBuilderCache - { - [ThreadStatic] - private static StringBuilder _cache; - - /// - /// Acquires a cached instance of if one exists otherwise a new instance. - /// - /// An instance of - [DebuggerStepThrough] - public static StringBuilder Acquire() - { - var result = _cache; - if (result == null) - return new StringBuilder(); - - result.Clear(); - _cache = null; // of that if caller forgets to release and return it is not kept alive by this class - return result; - } - - /// - /// Gets the string representation of the and releases it to the cache. - /// - /// The - /// The string representation of the - [DebuggerStepThrough] - public static string GetStringAndRelease(StringBuilder builder) - { - var result = builder.ToString(); - _cache = builder; - return result; - } - } -} diff --git a/src/Maple.Core/app.config b/src/Maple.Core/app.config deleted file mode 100644 index 486c484..0000000 --- a/src/Maple.Core/app.config +++ /dev/null @@ -1,52 +0,0 @@ - - - - -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - en - - - - diff --git a/src/Maple.Data/App.config b/src/Maple.Data/App.config deleted file mode 100644 index 46eb4d4..0000000 --- a/src/Maple.Data/App.config +++ /dev/null @@ -1,52 +0,0 @@ - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Maple.Data/DB/CreateSeedDatabaseIfNotExists.cs b/src/Maple.Data/DB/CreateSeedDatabaseIfNotExists.cs deleted file mode 100644 index e19a43f..0000000 --- a/src/Maple.Data/DB/CreateSeedDatabaseIfNotExists.cs +++ /dev/null @@ -1,285 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data.Entity; -using System.Diagnostics; -using Maple.Domain; -using SQLite.CodeFirst; - -namespace Maple.Data -{ - public class CreateSeedDatabaseIfNotExists : SqliteDropCreateDatabaseWhenModelChanges - where TContext : PlaylistContext - { - private const int saveThresHold = 100; - - private readonly List _playlistTitles = new List() - { - "Memories Of A Time To Come", - "A Twist In The Myth", - "At The Edge Of Time", - "Beyond The Red Mirror", - "Battalions Of Fear", - "Follow The Blind", - "Tales From The Twilight World", - "Somewhere Far Beyond", - "Tokyo Tales", - "Imaginations From The Other Side", - "The Forgotten Tales", - "Nightfall In Middle Earth", - "A Night At The Opera", - "Infinite", - "The Slim Shady LP", - "Marshall Mathers", - "The Eminem Show", - "Encore", - "Relapse", - "Recovery", - }; - - private readonly List _mediaItemTitles = new List() - { - "The Ninth Wave", - "Twilight Of The Gods", - "Prophecies", - "At The Edge Of Time", - "Ashes Of Eternity", - "Distant Memories", - "The Holy Grail", - "The Throne", - "Sacred Mind", - "Miracle Machine", - "Grand Parade", - "My Name Is", - "Guilty Conscience", - "Brain Damage", - "Paul", - "If I Had", - "'97 Bonnie & Clyde", - "Bitch", - "Role Model", - }; - - public CreateSeedDatabaseIfNotExists(DbModelBuilder builder) - : base(builder) - { - } - - public CreateSeedDatabaseIfNotExists(DbModelBuilder modelBuilder, Type historyEntityType) - : base(modelBuilder, historyEntityType) - { - } - - protected override void Seed(TContext context) - { - if (!Debugger.IsAttached) - { - base.Seed(context); - return; - } - - base.Seed(context); - - SeedTestData(context); - SeedMediaPlayers(context); - - context.SaveChanges(); - } - - private void SeedTestData(TContext context) - { - context.Playlists - .Add(new PlaylistModel - { - Title = "MP3 Files", - Description = "Test playlist with mp3 files", - Id = 0, - IsShuffeling = false, - Location = "https://www.youtube.com/watch?v=WxfcsmbBd00&t=0s", - PrivacyStatus = 0, - RepeatMode = 1, - Sequence = 0, - CreatedBy = "SYSTEM", - UpdatedBy = "SYSTEM", - CreatedOn = DateTime.UtcNow, - UpdatedOn = DateTime.UtcNow, - }); - - context.MediaItems - .Add(new MediaItemModel - { - Title = "Universe Words", - Description = "http://freemusicarchive.org/music/Artofescapism/", - Duration = 60_000_000, - Id = 0, - Location = ".\\Resources\\Art_Of_Escapism_-_Universe_Words.mp3", - Playlist = context.Playlists.Find(0), - PrivacyStatus = 0, - Sequence = 0, - MediaItemType = (int)MediaItemType.LocalFile, - CreatedBy = "SYSTEM", - UpdatedBy = "SYSTEM", - CreatedOn = DateTime.UtcNow, - UpdatedOn = DateTime.UtcNow, - }); - - var index = 0; - for (var i = 1; i < _playlistTitles.Count; i++) - { - context.Playlists - .Add(new PlaylistModel - { - Title = _playlistTitles[i], - Description = "Test playlist with 3 entries", - Id = i, - IsShuffeling = false, - Location = "https://www.youtube.com/watch?v=WxfcsmbBd00&t=0s", - PrivacyStatus = 0, - RepeatMode = 1, - Sequence = i, - CreatedBy = "SYSTEM", - UpdatedBy = "SYSTEM", - CreatedOn = DateTime.UtcNow, - UpdatedOn = DateTime.UtcNow, - }); - - for (var j = 1; j < _mediaItemTitles.Count; j++) - { - context.MediaItems - .Add(new MediaItemModel - { - Title = _mediaItemTitles[j], - Description = "A popular youtube video", - Duration = 60_000_000, - Id = j, - Location = "https://www.youtube.com/watch?v=oHg5SJYRHA0", - Playlist = context.Playlists.Find(i), - PrivacyStatus = 0, - Sequence = j, - CreatedBy = "SYSTEM", - UpdatedBy = "SYSTEM", - CreatedOn = DateTime.UtcNow, - UpdatedOn = DateTime.UtcNow, - }); - index++; - - if (index % saveThresHold == 0) - context.SaveChanges(); - } - } - - } - - private void SeedMediaPlayers(TContext context) - { - if (context.Mediaplayers.Find(1) == null) - context.Mediaplayers - .Add(new MediaPlayerModel - { - Id = 1, - IsPrimary = true, - Name = "Main", - Playlist = context.Playlists.Find(1), - Sequence = 0, - CreatedBy = "SYSTEM", - UpdatedBy = "SYSTEM", - CreatedOn = DateTime.UtcNow, - UpdatedOn = DateTime.UtcNow, - }); - } - - private void SeedOptions(TContext context) - { - if (context.Options.Find(1) == null) - context.Options - .Add(new OptionModel - { - Id = 1, - Key = "SelectedPlaylist", - Sequence = 0, - Type = (int)OptionType.Playlist, - Value = "1", - CreatedBy = "SYSTEM", - UpdatedBy = "SYSTEM", - CreatedOn = DateTime.UtcNow, - UpdatedOn = DateTime.UtcNow, - }); - - if (context.Options.Find(2) == null) - context.Options - .Add(new OptionModel - { - Id = 2, - Key = "SelectedMediaItem", - Sequence = 10, - Type = (int)OptionType.MediaItem, - Value = "", - CreatedBy = "SYSTEM", - UpdatedBy = "SYSTEM", - CreatedOn = DateTime.UtcNow, - UpdatedOn = DateTime.UtcNow, - }); - - if (context.Options.Find(3) == null) - context.Options - .Add(new OptionModel - { - Id = 3, - Key = "SelectedMediaPlayer", - Sequence = 20, - Type = (int)OptionType.MediaPlayer, - Value = "1", - CreatedBy = "SYSTEM", - UpdatedBy = "SYSTEM", - CreatedOn = DateTime.UtcNow, - UpdatedOn = DateTime.UtcNow, - }); - - // 4 - - if (context.Options.Find(5) == null) - context.Options - .Add(new OptionModel - { - Id = 5, - Key = "SelectedPrimary", - Sequence = 40, - Type = (int)OptionType.ColorProfile, - Value = "", - CreatedBy = "SYSTEM", - UpdatedBy = "SYSTEM", - CreatedOn = DateTime.UtcNow, - UpdatedOn = DateTime.UtcNow, - }); - - if (context.Options.Find(6) == null) - context.Options - .Add(new OptionModel - { - Id = 6, - Key = "SelectedAccent", - Sequence = 50, - Type = (int)OptionType.ColorProfile, - Value = "", - CreatedBy = "SYSTEM", - UpdatedBy = "SYSTEM", - CreatedOn = DateTime.UtcNow, - UpdatedOn = DateTime.UtcNow, - }); - - if (context.Options.Find(7) == null) - context.Options - .Add(new OptionModel - { - Id = 7, - Key = "SelectedScene", - Sequence = 60, - Type = (int)OptionType.Scene, - Value = "", - CreatedBy = "SYSTEM", - UpdatedBy = "SYSTEM", - CreatedOn = DateTime.UtcNow, - UpdatedOn = DateTime.UtcNow, - }); - } - } -} diff --git a/src/Maple.Data/DB/ModelConfiguration.cs b/src/Maple.Data/DB/ModelConfiguration.cs deleted file mode 100644 index 4aaf29b..0000000 --- a/src/Maple.Data/DB/ModelConfiguration.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Data.Entity; -using Maple.Domain; - -namespace Maple.Data -{ - public static class ModelConfiguration - { - public static void Configure(DbModelBuilder modelBuilder) - { - ConfigureCoachEntity(modelBuilder); - ConfigureMediaItemEntity(modelBuilder); - } - - private static void ConfigureCoachEntity(DbModelBuilder modelBuilder) - { - modelBuilder.Entity() - .HasRequired(p => p.Playlist); - } - - private static void ConfigureMediaItemEntity(DbModelBuilder modelBuilder) - { - modelBuilder.Entity() - .HasRequired(p => p.Playlist) - .WithMany(mediaItem => mediaItem.MediaItems) - .WillCascadeOnDelete(true); - } - } -} diff --git a/src/Maple.Data/DB/PlaylistContext.cs b/src/Maple.Data/DB/PlaylistContext.cs deleted file mode 100644 index c5425f2..0000000 --- a/src/Maple.Data/DB/PlaylistContext.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Data.Entity; -using Maple.Domain; - -namespace Maple.Data -{ - public class PlaylistContext : DbContext - { - public DbSet Playlists { get; set; } - public DbSet MediaItems { get; set; } - public DbSet Mediaplayers { get; set; } - public DbSet Options { get; set; } - public DbSet Data { get; set; } - - public PlaylistContext() - : base("Main") - { - Configuration.ProxyCreationEnabled = false; - Configuration.LazyLoadingEnabled = false; - } - - protected override void OnModelCreating(DbModelBuilder modelBuilder) - { - ModelConfiguration.Configure(modelBuilder); - Database.SetInitializer(new CreateSeedDatabaseIfNotExists(modelBuilder)); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - } - } -} diff --git a/src/Maple.Data/Maple.Data.csproj b/src/Maple.Data/Maple.Data.csproj deleted file mode 100644 index bea4727..0000000 --- a/src/Maple.Data/Maple.Data.csproj +++ /dev/null @@ -1,112 +0,0 @@ - - - - Debug - AnyCPU - {B3CD46BE-3C08-4BAE-AE60-A6D84A62400C} - Library - Properties - Maple.Data - Maple.Data - v4.7.1 - 512 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - AnyCPU - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - - - - - - - - Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - - - - False - Microsoft .NET Framework 4.5.2 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 - false - - - - - Designer - - - - - {9d7d05a6-8271-4836-a7bb-5b2abeccbd81} - Maple.Domain - - - - \ No newline at end of file diff --git a/src/Maple.Data/Properties/AssemblyInfo.cs b/src/Maple.Data/Properties/AssemblyInfo.cs deleted file mode 100644 index e9b3386..0000000 --- a/src/Maple.Data/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,5 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("Maple.Data")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] diff --git a/src/Maple.Data/Repository/Base/IMediaItemRepository.cs b/src/Maple.Data/Repository/Base/IMediaItemRepository.cs deleted file mode 100644 index fa4f713..0000000 --- a/src/Maple.Data/Repository/Base/IMediaItemRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Threading.Tasks; -using Maple.Domain; - -namespace Maple.Data -{ - public interface IMediaItemRepository : IMapleRepository - { - Task GetMediaItemByPlaylistIdAsync(int id); - } -} \ No newline at end of file diff --git a/src/Maple.Data/Repository/Base/IMediaPlayerRepository.cs b/src/Maple.Data/Repository/Base/IMediaPlayerRepository.cs deleted file mode 100644 index bdc5e88..0000000 --- a/src/Maple.Data/Repository/Base/IMediaPlayerRepository.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Maple.Domain; - -namespace Maple.Data -{ - public interface IMediaPlayerRepository : IMapleRepository - { - Task GetMainMediaPlayerAsync(); - Task> GetOptionalMediaPlayersAsync(); - } -} \ No newline at end of file diff --git a/src/Maple.Data/Repository/Base/IPlaylistRepository.cs b/src/Maple.Data/Repository/Base/IPlaylistRepository.cs deleted file mode 100644 index 0b5d03b..0000000 --- a/src/Maple.Data/Repository/Base/IPlaylistRepository.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Maple.Domain; - -namespace Maple.Data -{ - public interface IPlaylistRepository : IMapleRepository - { - } -} \ No newline at end of file diff --git a/src/Maple.Data/Repository/Base/MaplePlaylistRepository.cs b/src/Maple.Data/Repository/Base/MaplePlaylistRepository.cs deleted file mode 100644 index a17b0ed..0000000 --- a/src/Maple.Data/Repository/Base/MaplePlaylistRepository.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data.Entity; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using Maple.Domain; - -namespace Maple.Data -{ - public abstract class MaplePlaylistRepository : IMapleRepository - where T : class, IBaseObject - { - public void Save(T item) - { - using (var context = new PlaylistContext()) - SaveInternal(item, context); - } - - protected abstract DbSet GetEntities(PlaylistContext context); - - protected virtual void SaveInternal(T item, PlaylistContext context) - { - if (item.IsNew) - Create(item, context); - else - { - if (item.IsDeleted) - { - context.Database.Log = (message) => Debug.WriteLine(message); - Delete(item, context); - } - else - Update(item, context); - } - - context.SaveChanges(); - } - - protected virtual void Delete(T item, PlaylistContext context) - { - context.Set().Remove(item); - } - - protected virtual void Create(T item, PlaylistContext context) - { - item.CreatedBy = System.Security.Principal.WindowsIdentity.GetCurrent().User.Value; - item.CreatedOn = DateTime.UtcNow; - - context.Set().Add(item); - } - - protected virtual void Update(T item, PlaylistContext context) - { - var entity = GetEntities(context).Find(item.Id); - - if (entity == null) - return; - - item.UpdatedOn = DateTime.UtcNow; - item.UpdatedBy = System.Security.Principal.WindowsIdentity.GetCurrent().User.Value; - - - context.Entry(entity).CurrentValues.SetValues(item); - } - - public Task GetByIdAsync(int Id) - { - return Task.Run(() => - { - using (var context = new PlaylistContext()) - return GetByIdInternalAsync(Id, context); - }); - } - - protected virtual T GetByIdInternalAsync(int id, PlaylistContext context) - { - return GetEntities(context).FirstOrDefault(p => p.Id == id); - } - - public Task> GetAsync() - { - return Task.Run(() => - { - using (var context = new PlaylistContext()) - return GetInternalAsync(context); - }); - } - - protected virtual IReadOnlyCollection GetInternalAsync(PlaylistContext context) - { - return GetEntities(context).ToList(); - } - } -} \ No newline at end of file diff --git a/src/Maple.Data/Repository/MediaItemRepository.cs b/src/Maple.Data/Repository/MediaItemRepository.cs deleted file mode 100644 index 1bf662c..0000000 --- a/src/Maple.Data/Repository/MediaItemRepository.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Data.Entity; -using System.Linq; -using System.Threading.Tasks; -using Maple.Domain; - -namespace Maple.Data -{ - public class MediaItemRepository : MaplePlaylistRepository, IMediaItemRepository - { - public Task GetMediaItemByPlaylistIdAsync(int id) - { - return Task.Run(() => - { - using (var context = new PlaylistContext()) - return GetMediaItemByPlaylistIdInternalAsync(id, context); - }); - } - - protected override DbSet GetEntities(PlaylistContext context) - { - return context.MediaItems; - } - - private MediaItemModel GetMediaItemByPlaylistIdInternalAsync(int id, PlaylistContext context) - { - return context.MediaItems.FirstOrDefault(p => p.Playlist.Id == id); - } - } -} diff --git a/src/Maple.Data/Repository/MediaPlayerRepository.cs b/src/Maple.Data/Repository/MediaPlayerRepository.cs deleted file mode 100644 index 70ebbee..0000000 --- a/src/Maple.Data/Repository/MediaPlayerRepository.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Collections.Generic; -using System.Data.Entity; -using System.Linq; -using System.Threading.Tasks; -using Maple.Domain; - -namespace Maple.Data -{ - public class MediaPlayerRepository : MaplePlaylistRepository, IMediaPlayerRepository - { - public Task GetMainMediaPlayerAsync() - { - return Task.Run(() => - { - using (var context = new PlaylistContext()) - return GetMainMediaPlayerInternal(context); - }); - } - - private MediaPlayerModel GetMainMediaPlayerInternal(PlaylistContext context) - { - return GetEntities(context).Include(p => p.Playlist) - .Include(p => p.Playlist.MediaItems) - .FirstOrDefault(p => p.IsPrimary); - } - - public Task> GetOptionalMediaPlayersAsync() - { - return Task.Run(() => - { - using (var context = new PlaylistContext()) - return GetOptionalMediaPlayersInternal(context); - }); - } - - private IReadOnlyCollection GetOptionalMediaPlayersInternal(PlaylistContext context) - { - return GetEntities(context).Include(p => p.Playlist) - .Where(p => !p.IsPrimary) - .ToList(); - } - - protected override IReadOnlyCollection GetInternalAsync(PlaylistContext context) - { - return GetEntities(context).Include(p => p.Playlist).ToList(); - } - - protected override DbSet GetEntities(PlaylistContext context) - { - return context.Mediaplayers; - } - } -} diff --git a/src/Maple.Data/Repository/PlaylistRepository.cs b/src/Maple.Data/Repository/PlaylistRepository.cs deleted file mode 100644 index bfad325..0000000 --- a/src/Maple.Data/Repository/PlaylistRepository.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Collections.Generic; -using System.Data.Entity; -using System.Linq; -using Maple.Domain; - -namespace Maple.Data -{ - public class PlaylistRepository : MaplePlaylistRepository, IPlaylistRepository - { - protected override DbSet GetEntities(PlaylistContext context) - { - return context.Playlists; - } - - protected override IReadOnlyCollection GetInternalAsync(PlaylistContext context) - { - return GetEntities(context).Include(p => p.MediaItems).ToList(); - } - } -} diff --git a/src/Maple.Domain/Enums/DeviceType.cs b/src/Maple.Domain/Enums/DeviceType.cs new file mode 100644 index 0000000..2bf7597 --- /dev/null +++ b/src/Maple.Domain/Enums/DeviceType.cs @@ -0,0 +1,11 @@ +namespace Maple.Domain +{ + public enum DeviceType + { + None = 0, + WaveOut = 1, + DirectSound = 2, + WASAPI = 3, + ASIO = 4, + } +} diff --git a/src/Maple.Domain/Enums/PackIconKind.cs b/src/Maple.Domain/Enums/PackIconKind.cs index 5454594..a36a78d 100644 --- a/src/Maple.Domain/Enums/PackIconKind.cs +++ b/src/Maple.Domain/Enums/PackIconKind.cs @@ -1,8 +1,9 @@ -namespace Maple.Domain +namespace Maple.Domain { public enum PackIconKind { None = 0, ApplicationIcon = 1 << 0, + Monstercat = 1 << 1, } } diff --git a/src/Maple.Domain/Enums/RepeatMode.cs b/src/Maple.Domain/Enums/RepeatMode.cs index a2638d4..1dd4403 100644 --- a/src/Maple.Domain/Enums/RepeatMode.cs +++ b/src/Maple.Domain/Enums/RepeatMode.cs @@ -1,8 +1,5 @@ -namespace Maple.Domain +namespace Maple.Domain { - /// - /// defines what happens when the last of is and the is requested - /// public enum RepeatMode { None = 0, // play everything thats in the playlist once diff --git a/src/Maple.Domain/Interfaces/AudioDeviceExtensions.cs b/src/Maple.Domain/Interfaces/AudioDeviceExtensions.cs new file mode 100644 index 0000000..28d5066 --- /dev/null +++ b/src/Maple.Domain/Interfaces/AudioDeviceExtensions.cs @@ -0,0 +1,29 @@ +namespace Maple.Domain +{ + public static class AudioDeviceExtensions + { + public static int GetKey(this IAudioDevice device) + { + var hCode = device.OsId.GetHashCode() ^ device.AudioDeviceTypeId; + return hCode.GetHashCode(); + } + + public static AudioDeviceModel GetModel(this IAudioDevice instance) + { + return new AudioDeviceModel() + { + Id = instance.Id, + Name = instance.Name, + Sequence = instance.Sequence, + + OsId = instance.OsId, + AudioDeviceTypeId = instance.AudioDeviceTypeId, + + CreatedBy = instance.CreatedBy, + CreatedOn = instance.CreatedOn, + UpdatedBy = instance.UpdatedBy, + UpdatedOn = instance.UpdatedOn, + }; + } + } +} diff --git a/src/Maple.Domain/Interfaces/AudioDeviceTypeExtensions.cs b/src/Maple.Domain/Interfaces/AudioDeviceTypeExtensions.cs new file mode 100644 index 0000000..0b03db7 --- /dev/null +++ b/src/Maple.Domain/Interfaces/AudioDeviceTypeExtensions.cs @@ -0,0 +1,22 @@ +namespace Maple.Domain +{ + public static class AudioDeviceTypeExtensions + { + public static AudioDeviceTypeModel GetModel(this IAudioDeviceTypeModel instance) + { + return new AudioDeviceTypeModel() + { + Id = instance.Id, + Name = instance.Name, + Sequence = instance.Sequence, + + DeviceType = instance.DeviceType, + + CreatedBy = instance.CreatedBy, + CreatedOn = instance.CreatedOn, + UpdatedBy = instance.UpdatedBy, + UpdatedOn = instance.UpdatedOn, + }; + } + } +} diff --git a/src/Maple.Domain/Interfaces/EntityExtensions.cs b/src/Maple.Domain/Interfaces/EntityExtensions.cs new file mode 100644 index 0000000..914f0d0 --- /dev/null +++ b/src/Maple.Domain/Interfaces/EntityExtensions.cs @@ -0,0 +1,10 @@ +namespace Maple.Domain +{ + public static class EntityExtensions + { + public static bool IsNew(this IEntity entity) + { + return entity.Id.Equals(default(TKey)); + } + } +} diff --git a/src/Maple.Domain/Interfaces/IAudioDevice.cs b/src/Maple.Domain/Interfaces/IAudioDevice.cs deleted file mode 100644 index 10ca374..0000000 --- a/src/Maple.Domain/Interfaces/IAudioDevice.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.ComponentModel; - -namespace Maple.Domain -{ - public interface IAudioDevice : INotifyPropertyChanged - { - int Channels { get; set; } - bool IsSelected { get; set; } - string Name { get; set; } - int Sequence { get; set; } - - string ToString(); - } -} \ No newline at end of file diff --git a/src/Maple.Domain/Interfaces/IBaseObject.cs b/src/Maple.Domain/Interfaces/IBaseObject.cs deleted file mode 100644 index c1740cb..0000000 --- a/src/Maple.Domain/Interfaces/IBaseObject.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace Maple.Domain -{ - public interface IBaseObject - { - string CreatedBy { get; set; } - DateTime CreatedOn { get; set; } - int Id { get; set; } - bool IsDeleted { get; set; } - bool IsNew { get; } - byte[] RowVersion { get; set; } - int Sequence { get; set; } - string UpdatedBy { get; set; } - DateTime UpdatedOn { get; set; } - } -} \ No newline at end of file diff --git a/src/Maple.Domain/Interfaces/IChangeState.cs b/src/Maple.Domain/Interfaces/IChangeState.cs deleted file mode 100644 index bc36a0f..0000000 --- a/src/Maple.Domain/Interfaces/IChangeState.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Maple.Domain -{ - public interface IChangeState - { - /// - /// Gets a value indicating whether this instance is new. - /// - /// - /// true if this instance is new; otherwise, false. - /// - bool IsNew { get; } - /// - /// Gets a value indicating whether this instance is deleted. - /// - /// - /// true if this instance is deleted; otherwise, false. - /// - bool IsDeleted { get; } - } -} diff --git a/src/Maple.Domain/Interfaces/IIdentifier.cs b/src/Maple.Domain/Interfaces/IIdentifier.cs deleted file mode 100644 index 1c62518..0000000 --- a/src/Maple.Domain/Interfaces/IIdentifier.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Maple.Domain -{ - public interface IIdentifier - { - int Id { get; } - } -} diff --git a/src/Maple.Domain/Interfaces/IIocFrameworkElement.cs b/src/Maple.Domain/Interfaces/IIocFrameworkElement.cs new file mode 100644 index 0000000..76a5891 --- /dev/null +++ b/src/Maple.Domain/Interfaces/IIocFrameworkElement.cs @@ -0,0 +1,11 @@ +using System.ComponentModel; +using MvvmScarletToolkit.Abstractions; + +namespace Maple +{ + public interface IIocFrameworkElement + { + ILocalizationService LocalizationService { get; } + IScarletEventManager WeakEventManager { get; } + } +} diff --git a/src/Maple.Domain/Interfaces/IIsSelected.cs b/src/Maple.Domain/Interfaces/IIsSelected.cs deleted file mode 100644 index 760b07b..0000000 --- a/src/Maple.Domain/Interfaces/IIsSelected.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Maple.Domain -{ - public interface IIsSelected - { - bool IsSelected { get; set; } - } -} diff --git a/src/Maple.Domain/Interfaces/ILoggingNotifcationService.cs b/src/Maple.Domain/Interfaces/ILoggingNotifcationService.cs deleted file mode 100644 index 806f4b0..0000000 --- a/src/Maple.Domain/Interfaces/ILoggingNotifcationService.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace Maple.Domain -{ - /// - /// forwards user friendly messages to the UI and to a - /// - /// - public interface ILoggingNotifcationService - { - void Info(object message); - void Warn(object message); - void Error(object message, Exception exception); - void Fatal(object message, Exception exception); - } -} \ No newline at end of file diff --git a/src/Maple.Domain/Interfaces/ILoggingService.cs b/src/Maple.Domain/Interfaces/ILoggingService.cs deleted file mode 100644 index d5d3c25..0000000 --- a/src/Maple.Domain/Interfaces/ILoggingService.cs +++ /dev/null @@ -1,183 +0,0 @@ -using System; - -namespace Maple.Domain -{ - public interface ILoggingService - { - // - // Summary: - // Logs a message object with the log4net.Core.Level.Error level. - // - // Parameters: - // message: - // The message object to log. - // - // Remarks: - // This method first checks if this logger is ERROR enabled by comparing the level - // of this logger with the log4net.Core.Level.Error level. If this logger is ERROR - // enabled, then it converts the message object (passed as parameter) to a string - // by invoking the appropriate log4net.ObjectRenderer.IObjectRenderer. It then proceeds - // to call all the registered appenders in this logger and also higher in the hierarchy - // depending on the value of the additivity flag. - // WARNING Note that passing an System.Exception to this method will print the name - // of the System.Exception but no stack trace. To print a stack trace use the Error(object,Exception) - // form instead. - /// - /// Errors the specified message. - /// - /// The message. - void Error(object message); - // - // Summary: - // Log a message object with the log4net.Core.Level.Error level including the stack - // trace of the System.Exception passed as a parameter. - // - // Parameters: - // message: - // The message object to log. - // - // exception: - // The exception to log, including its stack trace. - // - // Remarks: - // See the Error(object) form for more detailed information. - /// - /// Errors the specified message. - /// - /// The message. - /// The exception. - void Error(object message, Exception exception); - - // - // Summary: - // Log a message object with the log4net.Core.Level.Fatal level. - // - // Parameters: - // message: - // The message object to log. - // - // Remarks: - // This method first checks if this logger is FATAL enabled by comparing the level - // of this logger with the log4net.Core.Level.Fatal level. If this logger is FATAL - // enabled, then it converts the message object (passed as parameter) to a string - // by invoking the appropriate log4net.ObjectRenderer.IObjectRenderer. It then proceeds - // to call all the registered appenders in this logger and also higher in the hierarchy - // depending on the value of the additivity flag. - // WARNING Note that passing an System.Exception to this method will print the name - // of the System.Exception but no stack trace. To print a stack trace use the Fatal(object,Exception) - // form instead. - /// - /// Fatals the specified message. - /// - /// The message. - void Fatal(object message); - // - // Summary: - // Log a message object with the log4net.Core.Level.Fatal level including the stack - // trace of the System.Exception passed as a parameter. - // - // Parameters: - // message: - // The message object to log. - // - // exception: - // The exception to log, including its stack trace. - // - // Remarks: - // See the Fatal(object) form for more detailed information. - /// - /// Fatals the specified message. - /// - /// The message. - /// The exception. - void Fatal(object message, Exception exception); - - // - // Summary: - // Logs a message object with the log4net.Core.Level.Info level. - // - // Parameters: - // message: - // The message object to log. - // - // Remarks: - // This method first checks if this logger is INFO enabled by comparing the level - // of this logger with the log4net.Core.Level.Info level. If this logger is INFO - // enabled, then it converts the message object (passed as parameter) to a string - // by invoking the appropriate log4net.ObjectRenderer.IObjectRenderer. It then proceeds - // to call all the registered appenders in this logger and also higher in the hierarchy - // depending on the value of the additivity flag. - // WARNING Note that passing an System.Exception to this method will print the name - // of the System.Exception but no stack trace. To print a stack trace use the Info(object,Exception) - // form instead. - /// - /// Informations the specified message. - /// - /// The message. - void Info(object message); - // - // Summary: - // Logs a message object with the INFO level including the stack trace of the System.Exception - // passed as a parameter. - // - // Parameters: - // message: - // The message object to log. - // - // exception: - // The exception to log, including its stack trace. - // - // Remarks: - // See the Info(object) form for more detailed information. - /// - /// Informations the specified message. - /// - /// The message. - /// The exception. - void Info(object message, Exception exception); - - // - // Summary: - // Log a message object with the log4net.Core.Level.Warn level. - // - // Parameters: - // message: - // The message object to log. - // - // Remarks: - // This method first checks if this logger is WARN enabled by comparing the level - // of this logger with the log4net.Core.Level.Warn level. If this logger is WARN - // enabled, then it converts the message object (passed as parameter) to a string - // by invoking the appropriate log4net.ObjectRenderer.IObjectRenderer. It then proceeds - // to call all the registered appenders in this logger and also higher in the hierarchy - // depending on the value of the additivity flag. - // WARNING Note that passing an System.Exception to this method will print the name - // of the System.Exception but no stack trace. To print a stack trace use the Warn(object,Exception) - // form instead. - /// - /// Warns the specified message. - /// - /// The message. - void Warn(object message); - // - // Summary: - // Log a message object with the log4net.Core.Level.Warn level including the stack - // trace of the System.Exception passed as a parameter. - // - // Parameters: - // message: - // The message object to log. - // - // exception: - // The exception to log, including its stack trace. - // - // Remarks: - // See the Warn(object) form for more detailed information. - /// - /// Warns the specified message. - /// - /// The message. - /// The exception. - void Warn(object message, Exception exception); - } -} diff --git a/src/Maple.Domain/Interfaces/IMapleRepository.cs b/src/Maple.Domain/Interfaces/IMapleRepository.cs deleted file mode 100644 index e5a4434..0000000 --- a/src/Maple.Domain/Interfaces/IMapleRepository.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Maple.Domain -{ - public interface IMapleRepository - where T : class, IBaseObject - { - Task> GetAsync(); - Task GetByIdAsync(int Id); - void Save(T item); - } -} \ No newline at end of file diff --git a/src/Maple.Domain/Interfaces/IRangeObservableCollection.cs b/src/Maple.Domain/Interfaces/IRangeObservableCollection.cs deleted file mode 100644 index fc425b8..0000000 --- a/src/Maple.Domain/Interfaces/IRangeObservableCollection.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Runtime.CompilerServices; - -namespace Maple.Domain -{ - public interface IRangeObservableCollection : IEnumerable, ICollection, INotifyPropertyChanged, IList, INotifyCollectionChanged - { - void AddRange(IEnumerable items); - void OnPropertyChanged([CallerMemberName] string propertyName = null); - void RemoveRange(IEnumerable items); - } -} \ No newline at end of file diff --git a/src/Maple.Domain/Interfaces/IRefreshable.cs b/src/Maple.Domain/Interfaces/IRefreshable.cs deleted file mode 100644 index fdb721b..0000000 --- a/src/Maple.Domain/Interfaces/IRefreshable.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Threading.Tasks; - -namespace Maple.Domain -{ - public interface IRefreshable - { - void Save(); - Task LoadAsync(); - } -} diff --git a/src/Maple.Domain/Interfaces/ITranslationProvider.cs b/src/Maple.Domain/Interfaces/ITranslationProvider.cs deleted file mode 100644 index 6248970..0000000 --- a/src/Maple.Domain/Interfaces/ITranslationProvider.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Collections.Generic; -using System.Globalization; - -namespace Maple.Domain -{ - public interface ITranslationProvider - { - /// - /// Translates the key into a localized value - /// - /// The key. - /// - string Translate(string key); - - /// - /// Gets the available languages. - /// - /// The available languages. - IEnumerable Languages { get; } - } -} diff --git a/src/Maple.Domain/Interfaces/MediaItemExtensions.cs b/src/Maple.Domain/Interfaces/MediaItemExtensions.cs new file mode 100644 index 0000000..9b92a27 --- /dev/null +++ b/src/Maple.Domain/Interfaces/MediaItemExtensions.cs @@ -0,0 +1,24 @@ +namespace Maple.Domain +{ + public static class MediaItemExtensions + { + public static MediaItemModel GetModel(this IMediaItem instance) + { + return new MediaItemModel() + { + Id = instance.Id, + Name = instance.Name, + Sequence = instance.Sequence, + + Duration = instance.Duration, + PrivacyStatus = instance.PrivacyStatus, + MediaItemType = instance.MediaItemType, + + CreatedBy = instance.CreatedBy, + CreatedOn = instance.CreatedOn, + UpdatedBy = instance.UpdatedBy, + UpdatedOn = instance.UpdatedOn, + }; + } + } +} diff --git a/src/Maple.Domain/Interfaces/MediaPlayerExtensions.cs b/src/Maple.Domain/Interfaces/MediaPlayerExtensions.cs new file mode 100644 index 0000000..1bdc710 --- /dev/null +++ b/src/Maple.Domain/Interfaces/MediaPlayerExtensions.cs @@ -0,0 +1,24 @@ +namespace Maple.Domain +{ + public static class MediaPlayerExtensions + { + public static MediaPlayerModel GetModel(this IMediaPlayer instance) + { + return new MediaPlayerModel() + { + Id = instance.Id, + Name = instance.Name, + Sequence = instance.Sequence, + + AudioDeviceId = instance.AudioDeviceId, + IsPrimary = instance.IsPrimary, + PlaylistId = instance.PlaylistId, + + CreatedBy = instance.CreatedBy, + CreatedOn = instance.CreatedOn, + UpdatedBy = instance.UpdatedBy, + UpdatedOn = instance.UpdatedOn, + }; + } + } +} diff --git a/src/Maple.Domain/Interfaces/Models/IAudioDevice.cs b/src/Maple.Domain/Interfaces/Models/IAudioDevice.cs new file mode 100644 index 0000000..01db37e --- /dev/null +++ b/src/Maple.Domain/Interfaces/Models/IAudioDevice.cs @@ -0,0 +1,8 @@ +namespace Maple.Domain +{ + public interface IAudioDevice : IEntity + { + int AudioDeviceTypeId { get; } + string OsId { get; } + } +} diff --git a/src/Maple.Domain/Interfaces/Models/IAudioDeviceType.cs b/src/Maple.Domain/Interfaces/Models/IAudioDeviceType.cs new file mode 100644 index 0000000..888e221 --- /dev/null +++ b/src/Maple.Domain/Interfaces/Models/IAudioDeviceType.cs @@ -0,0 +1,7 @@ +namespace Maple.Domain +{ + public interface IAudioDeviceTypeModel : IEntity + { + DeviceType DeviceType { get; } + } +} diff --git a/src/Maple.Domain/Interfaces/Models/IEntity.cs b/src/Maple.Domain/Interfaces/Models/IEntity.cs new file mode 100644 index 0000000..b1cc92f --- /dev/null +++ b/src/Maple.Domain/Interfaces/Models/IEntity.cs @@ -0,0 +1,17 @@ +using System; + +namespace Maple.Domain +{ + public interface IEntity : ISequence + { + string Name { get; } + + string CreatedBy { get; } + DateTime CreatedOn { get; } + + string UpdatedBy { get; } + DateTime UpdatedOn { get; } + + bool IsDeleted { get; } + } +} diff --git a/src/Maple.Domain/Interfaces/Models/IEntity_generic.cs b/src/Maple.Domain/Interfaces/Models/IEntity_generic.cs new file mode 100644 index 0000000..7dd2a2f --- /dev/null +++ b/src/Maple.Domain/Interfaces/Models/IEntity_generic.cs @@ -0,0 +1,9 @@ +namespace Maple.Domain +{ + public interface IEntity : IEntity + { + TKey Id { get; } + + public bool IsNew => Id.Equals(default(TKey)); + } +} diff --git a/src/Maple.Domain/Interfaces/IMediaItem.cs b/src/Maple.Domain/Interfaces/Models/IMediaItem.cs similarity index 50% rename from src/Maple.Domain/Interfaces/IMediaItem.cs rename to src/Maple.Domain/Interfaces/Models/IMediaItem.cs index 342288d..37f6fef 100644 --- a/src/Maple.Domain/Interfaces/IMediaItem.cs +++ b/src/Maple.Domain/Interfaces/Models/IMediaItem.cs @@ -1,11 +1,9 @@ -using System; +using System; namespace Maple.Domain { - public interface IMediaItem : IIsSelected, ISequence, IIdentifier, IChangeState + public interface IMediaItem : IEntity { - string Title { get; } - string Location { get; } TimeSpan Duration { get; } PrivacyStatus PrivacyStatus { get; } MediaItemType MediaItemType { get; } diff --git a/src/Maple.Domain/Interfaces/Models/IMediaPlayer.cs b/src/Maple.Domain/Interfaces/Models/IMediaPlayer.cs new file mode 100644 index 0000000..1981dec --- /dev/null +++ b/src/Maple.Domain/Interfaces/Models/IMediaPlayer.cs @@ -0,0 +1,9 @@ +namespace Maple.Domain +{ + public interface IMediaPlayer : IEntity + { + int? AudioDeviceId { get; } + bool IsPrimary { get; } + int? PlaylistId { get; } + } +} diff --git a/src/Maple.Domain/Interfaces/Models/IPlaylist.cs b/src/Maple.Domain/Interfaces/Models/IPlaylist.cs new file mode 100644 index 0000000..4cc564d --- /dev/null +++ b/src/Maple.Domain/Interfaces/Models/IPlaylist.cs @@ -0,0 +1,9 @@ +namespace Maple.Domain +{ + public interface IPlaylist : IEntity + { + bool IsShuffeling { get; } + PrivacyStatus PrivacyStatus { get; } + RepeatMode RepeatMode { get; } + } +} diff --git a/src/Maple.Domain/Interfaces/ISequence.cs b/src/Maple.Domain/Interfaces/Models/ISequence.cs similarity index 100% rename from src/Maple.Domain/Interfaces/ISequence.cs rename to src/Maple.Domain/Interfaces/Models/ISequence.cs diff --git a/src/Maple.Domain/Interfaces/PlaylistExtensions.cs b/src/Maple.Domain/Interfaces/PlaylistExtensions.cs new file mode 100644 index 0000000..a4d08c3 --- /dev/null +++ b/src/Maple.Domain/Interfaces/PlaylistExtensions.cs @@ -0,0 +1,24 @@ +namespace Maple.Domain +{ + public static class PlaylistExtensions + { + public static PlaylistModel GetModel(this IPlaylist instance) + { + return new PlaylistModel() + { + Id = instance.Id, + Name = instance.Name, + Sequence = instance.Sequence, + + IsShuffeling = instance.IsShuffeling, + PrivacyStatus = instance.PrivacyStatus, + RepeatMode = instance.RepeatMode, + + CreatedBy = instance.CreatedBy, + CreatedOn = instance.CreatedOn, + UpdatedBy = instance.UpdatedBy, + UpdatedOn = instance.UpdatedOn, + }; + } + } +} diff --git a/src/Maple.Domain/Interfaces/IMediaPlayer.cs b/src/Maple.Domain/Interfaces/Services/IPlaybackService.cs similarity index 88% rename from src/Maple.Domain/Interfaces/IMediaPlayer.cs rename to src/Maple.Domain/Interfaces/Services/IPlaybackService.cs index 69eb616..bea0e19 100644 --- a/src/Maple.Domain/Interfaces/IMediaPlayer.cs +++ b/src/Maple.Domain/Interfaces/Services/IPlaybackService.cs @@ -1,8 +1,8 @@ -using System; +using System; namespace Maple.Domain { - public interface IMediaPlayer : IDisposable + public interface IPlaybackService : IDisposable { /// /// Gets a value indicating whether this instance is playing. @@ -17,10 +17,12 @@ public interface IMediaPlayer : IDisposable /// /// The item. bool Play(IMediaItem item); + /// /// Pauses this instance. /// void Pause(); + /// /// Stops this instance. /// @@ -33,6 +35,7 @@ public interface IMediaPlayer : IDisposable /// true if this instance can stop; otherwise, false. /// bool CanStop(); + /// /// Determines whether this instance can pause. /// @@ -40,6 +43,7 @@ public interface IMediaPlayer : IDisposable /// true if this instance can pause; otherwise, false. /// bool CanPause(); + /// /// Determines whether this instance can play the specified item. /// @@ -56,6 +60,7 @@ public interface IMediaPlayer : IDisposable /// The volume. /// int Volume { get; set; } + /// /// Gets the volume maximum. /// @@ -63,6 +68,7 @@ public interface IMediaPlayer : IDisposable /// The volume maximum. /// int VolumeMax { get; } + /// /// Gets the volume minimum. /// @@ -70,12 +76,5 @@ public interface IMediaPlayer : IDisposable /// The volume minimum. /// int VolumeMin { get; } - /// - /// Gets or sets the audio device. - /// - /// - /// The audio device. - /// - IAudioDevice AudioDevice { get; set; } } } diff --git a/src/Maple.Domain/Interfaces/ISequenceService.cs b/src/Maple.Domain/Interfaces/Services/ISequenceService.cs similarity index 100% rename from src/Maple.Domain/Interfaces/ISequenceService.cs rename to src/Maple.Domain/Interfaces/Services/ISequenceService.cs diff --git a/src/Maple.Domain/Interfaces/IVersionService.cs b/src/Maple.Domain/Interfaces/Services/IVersionService.cs similarity index 98% rename from src/Maple.Domain/Interfaces/IVersionService.cs rename to src/Maple.Domain/Interfaces/Services/IVersionService.cs index b6a4bd1..8e69375 100644 --- a/src/Maple.Domain/Interfaces/IVersionService.cs +++ b/src/Maple.Domain/Interfaces/Services/IVersionService.cs @@ -4,4 +4,4 @@ public interface IVersionService { string Get(); } -} \ No newline at end of file +} diff --git a/src/Maple.Domain/Maple.Domain.csproj b/src/Maple.Domain/Maple.Domain.csproj index 2050693..4ca75be 100644 --- a/src/Maple.Domain/Maple.Domain.csproj +++ b/src/Maple.Domain/Maple.Domain.csproj @@ -1,81 +1,16 @@ - - - - - Debug - AnyCPU - {9D7D05A6-8271-4836-A7BB-5B2ABECCBD81} - Library - Properties - Maple.Domain - Maple.Domain - v4.7.1 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + netstandard2.1 + false + Library + False + 8.0 + + + + + + + + + diff --git a/src/Maple.Domain/Models/AudioDeviceModel.cs b/src/Maple.Domain/Models/AudioDeviceModel.cs new file mode 100644 index 0000000..326a694 --- /dev/null +++ b/src/Maple.Domain/Models/AudioDeviceModel.cs @@ -0,0 +1,12 @@ +using System.Diagnostics; + +namespace Maple.Domain +{ + [DebuggerDisplay("AudioDeviceModel: {Sequence}, {Name}")] + public class AudioDeviceModel : Entity, IAudioDevice + { + public string OsId { get; set; } + public AudioDeviceTypeModel AudioDeviceType { get; set; } + public int AudioDeviceTypeId { get; set; } + } +} diff --git a/src/Maple.Domain/Models/AudioDeviceTypeModel.cs b/src/Maple.Domain/Models/AudioDeviceTypeModel.cs new file mode 100644 index 0000000..edd1e7a --- /dev/null +++ b/src/Maple.Domain/Models/AudioDeviceTypeModel.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Diagnostics; + +namespace Maple.Domain +{ + [DebuggerDisplay("AudioDeviceTypeModel: {Sequence}, {Name}")] + public class AudioDeviceTypeModel : Entity, IAudioDeviceTypeModel + { + public DeviceType DeviceType { get; set; } + + public virtual List AudioDevices { get; set; } + + public AudioDeviceTypeModel() + { + AudioDevices = new List(); + } + } +} diff --git a/src/Maple.Domain/Models/Base/BaseObject.cs b/src/Maple.Domain/Models/Base/BaseObject.cs deleted file mode 100644 index 84b225c..0000000 --- a/src/Maple.Domain/Models/Base/BaseObject.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; - -namespace Maple.Domain -{ - public abstract class BaseObject : IBaseObject - { - [Key] - [Column(Order = 1)] - public int Id { get; set; } - [Column(Order = 2)] - public int Sequence { get; set; } - - public DateTime CreatedOn { get; set; } - public string CreatedBy { get; set; } - - public DateTime UpdatedOn { get; set; } - public string UpdatedBy { get; set; } - - [Timestamp] - public byte[] RowVersion { get; set; } - - [NotMapped] - public bool IsDeleted { get; set; } - - [NotMapped] - public bool IsNew => Id == 0; - } -} diff --git a/src/Maple.Domain/Models/Base/Entity.cs b/src/Maple.Domain/Models/Base/Entity.cs new file mode 100644 index 0000000..6d037df --- /dev/null +++ b/src/Maple.Domain/Models/Base/Entity.cs @@ -0,0 +1,20 @@ +using System; + +namespace Maple.Domain +{ + public abstract class Entity : IEntity + { + public TKey Id { get; set; } + + public int Sequence { get; set; } + + public string Name { get; set; } + + public DateTime CreatedOn { get; set; } + public string CreatedBy { get; set; } + public DateTime UpdatedOn { get; set; } + public string UpdatedBy { get; set; } + + public bool IsDeleted { get; set; } + } +} diff --git a/src/Maple.Domain/Models/MediaItemModel.cs b/src/Maple.Domain/Models/MediaItemModel.cs index 92d84e0..55b998c 100644 --- a/src/Maple.Domain/Models/MediaItemModel.cs +++ b/src/Maple.Domain/Models/MediaItemModel.cs @@ -1,31 +1,18 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; +using System; using System.Diagnostics; namespace Maple.Domain { - [DebuggerDisplay("{Title}, {Sequence}")] - public class MediaItemModel : BaseObject + [DebuggerDisplay("MediaItemModel: {Sequence}, {Name}")] + public class MediaItemModel : Entity, IMediaItem { - public int PlaylistId { get; set; } - [ForeignKey(nameof(PlaylistId))] - public PlaylistModel Playlist { get; set; } + public TimeSpan Duration { get; set; } - public RawModel Raw { get; set; } + public PrivacyStatus PrivacyStatus { get; set; } + public MediaItemType MediaItemType { get; set; } - /// - /// Ticks - /// - public long Duration { get; set; } - public int PrivacyStatus { get; set; } - public int MediaItemType { get; set; } - public string Description { get; set; } + public int PlaylistId { get; set; } - [Required] - [MaxLength(50)] - public string Title { get; set; } - [Required] - [MaxLength(2048)] - public string Location { get; set; } + public virtual PlaylistModel Playlist { get; set; } } } diff --git a/src/Maple.Domain/Models/MediaPlayerModel.cs b/src/Maple.Domain/Models/MediaPlayerModel.cs index 4775b57..a9b424f 100644 --- a/src/Maple.Domain/Models/MediaPlayerModel.cs +++ b/src/Maple.Domain/Models/MediaPlayerModel.cs @@ -1,22 +1,18 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; using System.Diagnostics; namespace Maple.Domain { - [DebuggerDisplay("{Name}, {DeviceName}, {Sequence}")] - public class MediaPlayerModel : BaseObject + [DebuggerDisplay("MediaPlayerModel: {Sequence}, {Name}")] + public class MediaPlayerModel : Entity, IMediaPlayer { - public int PlaylistId { get; set; } - [ForeignKey(nameof(PlaylistId))] - public PlaylistModel Playlist { get; set; } - - [MaxLength(100)] - public string DeviceName { get; set; } public bool IsPrimary { get; set; } - [Required] - [MaxLength(50)] - public string Name { get; set; } + public int? PlaylistId { get; set; } + + public virtual PlaylistModel Playlist { get; set; } + + public int? AudioDeviceId { get; set; } + + public virtual AudioDeviceModel AudioDevice { get; set; } } } diff --git a/src/Maple.Domain/Models/OptionModel.cs b/src/Maple.Domain/Models/OptionModel.cs index ec27dc4..efb4225 100644 --- a/src/Maple.Domain/Models/OptionModel.cs +++ b/src/Maple.Domain/Models/OptionModel.cs @@ -1,16 +1,13 @@ -using System.ComponentModel.DataAnnotations; using System.Diagnostics; namespace Maple.Domain { [DebuggerDisplay("{Key}, {Value}, {Type}")] - public class OptionModel : BaseObject + public class OptionModel : Entity { public string Value { get; set; } public int Type { get; set; } - - [Required] public string Key { get; set; } } } diff --git a/src/Maple.Domain/Models/PlaylistModel.cs b/src/Maple.Domain/Models/PlaylistModel.cs index 8d96ad8..53f5f4e 100644 --- a/src/Maple.Domain/Models/PlaylistModel.cs +++ b/src/Maple.Domain/Models/PlaylistModel.cs @@ -1,31 +1,23 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; +using System.Collections.Generic; using System.Diagnostics; namespace Maple.Domain { - // tutorial http://www.entityframeworktutorial.net/code-first/configure-one-to-many-relationship-in-code-first.aspx - - [DebuggerDisplay("{Title}, {SelectedItem}, {Sequence}")] - public class PlaylistModel : BaseObject + [DebuggerDisplay("PlaylistModel: {Sequence}, {Name}")] + public class PlaylistModel : Entity, IPlaylist { - private ICollection _mediaItems; - public virtual ICollection MediaItems - { - get { return _mediaItems ?? (_mediaItems = new HashSet()); } - set { _mediaItems = value; } - } - - [MaxLength(100)] - public string Description { get; set; } - public string Location { get; set; } public bool IsShuffeling { get; set; } - public int PrivacyStatus { get; set; } - public int RepeatMode { get; set; } + public PrivacyStatus PrivacyStatus { get; set; } + public RepeatMode RepeatMode { get; set; } - [Required] - [MaxLength(50)] - public string Title { get; set; } + public virtual List MediaPlayers { get; set; } + public virtual List MediaItems { get; set; } + + public PlaylistModel() + { + MediaItems = new List(); + MediaPlayers = new List(); + } } } diff --git a/src/Maple.Domain/Models/RawModel.cs b/src/Maple.Domain/Models/RawModel.cs deleted file mode 100644 index 182e8cf..0000000 --- a/src/Maple.Domain/Models/RawModel.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Maple.Domain -{ - public class RawModel : BaseObject - { - public byte[] Data { get; set; } - } -} diff --git a/src/Maple.Domain/Properties/AssemblyInfo.cs b/src/Maple.Domain/Properties/AssemblyInfo.cs index 405721d..a6e9b04 100644 --- a/src/Maple.Domain/Properties/AssemblyInfo.cs +++ b/src/Maple.Domain/Properties/AssemblyInfo.cs @@ -1,9 +1,8 @@ using System.Reflection; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("Maple.Interfaces")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] - diff --git a/src/Maple.Localization/Maple.Localization.csproj b/src/Maple.Localization/Maple.Localization.csproj deleted file mode 100644 index 32f1b99..0000000 --- a/src/Maple.Localization/Maple.Localization.csproj +++ /dev/null @@ -1,78 +0,0 @@ - - - - Debug - AnyCPU - {A073FC92-90E3-4541-8B52-6F7293187871} - Library - Properties - Maple.Localization - Maple.Localization - v4.7.1 - 512 - - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - AnyCPU - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - Properties\SharedAssemblyInfo.cs - - - Resources.en.resx - True - True - - - True - True - Resources.resx - - - - - - PublicResXFileCodeGenerator - Resources.en.Designer.cs - - - PublicResXFileCodeGenerator - Resources.Designer.cs - - - - - \ No newline at end of file diff --git a/src/Maple.Localization/Properties/AssemblyInfo.cs b/src/Maple.Localization/Properties/AssemblyInfo.cs deleted file mode 100644 index bab173d..0000000 --- a/src/Maple.Localization/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,5 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("Maple.Localization")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] diff --git a/src/Maple.Localization/Properties/Resources.Designer.cs b/src/Maple.Localization/Properties/Resources.Designer.cs deleted file mode 100644 index fbdb378..0000000 --- a/src/Maple.Localization/Properties/Resources.Designer.cs +++ /dev/null @@ -1,783 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Maple.Localization.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Maple.Localization.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to Ok. - /// - public static string Accept { - get { - return ResourceManager.GetString("Accept", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Hinzufügen. - /// - public static string Add { - get { - return ResourceManager.GetString("Add", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Anwendung wird gestartet. - /// - public static string AppStart { - get { - return ResourceManager.GetString("AppStart", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Wiedergabegerät. - /// - public static string AudioDevice { - get { - return ResourceManager.GetString("AudioDevice", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Abbrechen. - /// - public static string Cancel { - get { - return ResourceManager.GetString("Cancel", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Leeren. - /// - public static string Clear { - get { - return ResourceManager.GetString("Clear", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Schließen. - /// - public static string Close { - get { - return ResourceManager.GetString("Close", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Zu den Farbprofilen wechseln. - /// - public static string ColorOptionsCommand { - get { - return ResourceManager.GetString("ColorOptionsCommand", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Anzahl. - /// - public static string Count { - get { - return ResourceManager.GetString("Count", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Löschen. - /// - public static string Delete { - get { - return ResourceManager.GetString("Delete", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Beschreibung. - /// - public static string Description { - get { - return ResourceManager.GetString("Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Es ist bereits ein Dialog geöffnet. Es kann kein Weiterer geöffnet werden. - /// - public static string DialogOpenAlready { - get { - return ResourceManager.GetString("DialogOpenAlready", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Dirigent. - /// - public static string Director { - get { - return ResourceManager.GetString("Director", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Speichert geleert. - /// - public static string DisposedState { - get { - return ResourceManager.GetString("DisposedState", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Speicher wird geleert. - /// - public static string DisposingState { - get { - return ResourceManager.GetString("DisposingState", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Dauer. - /// - public static string Duration { - get { - return ResourceManager.GetString("Duration", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Ändern. - /// - public static string Edit { - get { - return ResourceManager.GetString("Edit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Sprache ändern. - /// - public static string EditLanguage { - get { - return ResourceManager.GetString("EditLanguage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Liste darf nicht null oder leer sein.. - /// - public static string ExceptionMessageCollectionNullOrEmpty { - get { - return ResourceManager.GetString("ExceptionMessageCollectionNullOrEmpty", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Werte müssen gleich sein.. - /// - public static string ExceptionMessageEqualValues { - get { - return ResourceManager.GetString("ExceptionMessageEqualValues", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Die angegebene Bedingung ist falsch.. - /// - public static string ExceptionMessageFalseCondition { - get { - return ResourceManager.GetString("ExceptionMessageFalseCondition", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Folgendes Verzeichnis wurde nicht gefunden:. - /// - public static string ExceptionMessageMissingDirectory { - get { - return ResourceManager.GetString("ExceptionMessageMissingDirectory", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Folgende Datei wurde nicht gefunden:. - /// - public static string ExceptionMessageMissingFile { - get { - return ResourceManager.GetString("ExceptionMessageMissingFile", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Werte dürfen nicht gleich sein.. - /// - public static string ExceptionMessageNotEqualValues { - get { - return ResourceManager.GetString("ExceptionMessageNotEqualValues", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to String darf nicht null, leer oder nur Leerraum enthalten.. - /// - public static string ExceptionMessageStringNullEmpyOrWhiteSpace { - get { - return ResourceManager.GetString("ExceptionMessageStringNullEmpyOrWhiteSpace", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Die angegebene Bedingung ist wahr.. - /// - public static string ExceptionMessageTrueCondition { - get { - return ResourceManager.GetString("ExceptionMessageTrueCondition", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Ein unerwarteter Fehler ist aufgetreten.. - /// - public static string ExceptionMessageUnhandled { - get { - return ResourceManager.GetString("ExceptionMessageUnhandled", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Eine Wiedergabeliste aus einer Datei importieren. - /// - public static string FilePlaylistImport { - get { - return ResourceManager.GetString("FilePlaylistImport", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Filter. - /// - public static string Filter { - get { - return ResourceManager.GetString("Filter", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Eine Wiedergabeliste anhand eines Ordners aus dem Dateisystem generieren und importieren. - /// - public static string FolderPlaylistImport { - get { - return ResourceManager.GetString("FolderPlaylistImport", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Projektseite auf GitHub.com öffnen. - /// - public static string GithubPageCommand { - get { - return ResourceManager.GetString("GithubPageCommand", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to https://github.com/Insire/InsireBot-V2. - /// - public static string GithubProjectLink { - get { - return ResourceManager.GetString("GithubProjectLink", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Auf der Datenbank befinden sich eine ungültige Anzahl an Einträgen für den Standardmediaplayer. - /// - public static string InvalidMediaplayerCountOnDBException { - get { - return ResourceManager.GetString("InvalidMediaplayerCountOnDBException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to darf nicht leer sein. - /// - public static string IsRequired { - get { - return ResourceManager.GetString("IsRequired", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Sprachen. - /// - public static string Languages { - get { - return ResourceManager.GetString("Languages", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Lade. - /// - public static string Loading { - get { - return ResourceManager.GetString("Loading", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Ort. - /// - public static string Location { - get { - return ResourceManager.GetString("Location", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Standardmediaplayer. - /// - public static string MainMediaplayer { - get { - return ResourceManager.GetString("MainMediaplayer", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Es können keine weiteren Wiedergabelisten angelegt werden, da die maximale Anzahl erreicht wurde. - /// - public static string MaxPlaylistCountReachedException { - get { - return ResourceManager.GetString("MaxPlaylistCountReachedException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Wiedergabetitel. - /// - public static string MediaItem { - get { - return ResourceManager.GetString("MediaItem", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Wiedergabetitel. - /// - public static string MediaItems { - get { - return ResourceManager.GetString("MediaItems", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Zur Wiedergabeliste wechseln. - /// - public static string MediaPlayerCommand { - get { - return ResourceManager.GetString("MediaPlayerCommand", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Mediaplayers. - /// - public static string MediaPlayers { - get { - return ResourceManager.GetString("MediaPlayers", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Navigation wird geladen. - /// - public static string NavigationLoad { - get { - return ResourceManager.GetString("NavigationLoad", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Navigation geladen. - /// - public static string NavigationLoaded { - get { - return ResourceManager.GetString("NavigationLoaded", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Neu. - /// - public static string New { - get { - return ResourceManager.GetString("New", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Weiter. - /// - public static string Next { - get { - return ResourceManager.GetString("Next", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Einstellungen. - /// - public static string Options { - get { - return ResourceManager.GetString("Options", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Zu den Einstellungen wechseln. - /// - public static string OptionsCommand { - get { - return ResourceManager.GetString("OptionsCommand", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Analysieren. - /// - public static string Parse { - get { - return ResourceManager.GetString("Parse", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Wiedergabe. - /// - public static string Playback { - get { - return ResourceManager.GetString("Playback", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Wiedergabemodus. - /// - public static string PlaybackMode { - get { - return ResourceManager.GetString("PlaybackMode", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Alle Titel wiederholen. - /// - public static string PlaybackModeAll { - get { - return ResourceManager.GetString("PlaybackModeAll", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Keinen Titel wiederholen. - /// - public static string PlaybackModeNone { - get { - return ResourceManager.GetString("PlaybackModeNone", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Einen Titel wiederholen. - /// - public static string PlaybackModeOne { - get { - return ResourceManager.GetString("PlaybackModeOne", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Zufällige Wiedergabe. - /// - public static string PlaybackShuffle { - get { - return ResourceManager.GetString("PlaybackShuffle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Wiedergabeliste. - /// - public static string Playlist { - get { - return ResourceManager.GetString("Playlist", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Wiedergabeliste hinzufügen. - /// - public static string PlaylistAdd { - get { - return ResourceManager.GetString("PlaylistAdd", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Aktuelle Wiedergabeliste. - /// - public static string PlaylistCurrent { - get { - return ResourceManager.GetString("PlaylistCurrent", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Wiedergabelisten. - /// - public static string Playlists { - get { - return ResourceManager.GetString("Playlists", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Zurück. - /// - public static string Previous { - get { - return ResourceManager.GetString("Previous", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Aktualisieren. - /// - public static string Refresh { - get { - return ResourceManager.GetString("Refresh", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Entfernen. - /// - public static string Remove { - get { - return ResourceManager.GetString("Remove", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Keine Beschränkung. - /// - public static string ResctrictionNone { - get { - return ResourceManager.GetString("ResctrictionNone", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Zugriffsbeschränkung. - /// - public static string Restriction { - get { - return ResourceManager.GetString("Restriction", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Kein Zugriff. - /// - public static string RestrictionRestricted { - get { - return ResourceManager.GetString("RestrictionRestricted", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Änderungen gespeichert. - /// - public static string SavedState { - get { - return ResourceManager.GetString("SavedState", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Speichere. - /// - public static string Saving { - get { - return ResourceManager.GetString("Saving", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Änderungen werden gespeichert. - /// - public static string SavingState { - get { - return ResourceManager.GetString("SavingState", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Auswählen. - /// - public static string Select { - get { - return ResourceManager.GetString("Select", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Dateiauswahl. - /// - public static string SelectFiles { - get { - return ResourceManager.GetString("SelectFiles", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Ordnerauswahl. - /// - public static string SelectFolder { - get { - return ResourceManager.GetString("SelectFolder", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Maple. - /// - public static string ShellTitle { - get { - return ResourceManager.GetString("ShellTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Farbprofile. - /// - public static string Themes { - get { - return ResourceManager.GetString("Themes", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Titel. - /// - public static string Title { - get { - return ResourceManager.GetString("Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Video hinzufügen. - /// - public static string VideoAdd { - get { - return ResourceManager.GetString("VideoAdd", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Lautstärke. - /// - public static string Volume { - get { - return ResourceManager.GetString("Volume", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Youtubeservice wird geladen. - /// - public static string YoutubeLoad { - get { - return ResourceManager.GetString("YoutubeLoad", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Youtubeservice geladen. - /// - public static string YoutubeLoaded { - get { - return ResourceManager.GetString("YoutubeLoaded", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Eine Widergabeliste von Youtube importieren. - /// - public static string YoutubePlaylistImport { - get { - return ResourceManager.GetString("YoutubePlaylistImport", resourceCulture); - } - } - } -} diff --git a/src/Maple.Localization/Properties/Resources.resx b/src/Maple.Localization/Properties/Resources.resx deleted file mode 100644 index a9f7870..0000000 --- a/src/Maple.Localization/Properties/Resources.resx +++ /dev/null @@ -1,360 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Wiedergabe - - - Wiedergabelisten - - - Video hinzufügen - - - Wiedergabeliste hinzufügen - - - Farbprofile - - - Navigation wird geladen - - - Navigation geladen - - - https://github.com/Insire/InsireBot-V2 - @Invariant - - Einstellungen - - - Maple - - - Sprachen - - - darf nicht leer sein - - - Wiedergabeliste - - - Wiedergabegerät - - - Wiedergabemodus - - - Zufällige Wiedergabe - - - Dirigent - - - Standardmediaplayer - - - Auf der Datenbank befinden sich eine ungültige Anzahl an Einträgen für den Standardmediaplayer - - - Hinzufügen - - - Entfernen - - - Leeren - - - Neu - - - Es können keine weiteren Wiedergabelisten angelegt werden, da die maximale Anzahl erreicht wurde - - - Änderungen werden gespeichert - - - Änderungen gespeichert - - - Speicher wird geleert - - - Speichert geleert - - - Titel - - - Beschreibung - - - Eine Widergabeliste von Youtube importieren - - - Eine Wiedergabeliste anhand eines Ordners aus dem Dateisystem generieren und importieren - - - Eine Wiedergabeliste aus einer Datei importieren - - - Ok - - - Schließen - - - Abbrechen - - - Dauer - - - Ort - - - Weiter - - - Zurück - - - Lautstärke - - - Keinen Titel wiederholen - - - Einen Titel wiederholen - - - Alle Titel wiederholen - - - Zugriffsbeschränkung - - - Analysieren - - - Keine Beschränkung - - - Kein Zugriff - - - Anzahl - - - Es ist bereits ein Dialog geöffnet. Es kann kein Weiterer geöffnet werden - - - Youtubeservice wird geladen - - - Youtubeservice geladen - - - Aktuelle Wiedergabeliste - - - Lade - - - Speichere - - - Ordnerauswahl - - - Dateiauswahl - - - Anwendung wird gestartet - - - Projektseite auf GitHub.com öffnen - - - Zur Wiedergabeliste wechseln - - - Zu den Farbprofilen wechseln - - - Zu den Einstellungen wechseln - - - Ändern - - - Sprache ändern - - - Filter - - - Mediaplayers - - - Wiedergabetitel - - - Wiedergabetitel - - - Die angegebene Bedingung ist falsch. - - - Die angegebene Bedingung ist wahr. - - - Werte müssen gleich sein. - - - Werte dürfen nicht gleich sein. - - - Liste darf nicht null oder leer sein. - - - String darf nicht null, leer oder nur Leerraum enthalten. - - - Folgendes Verzeichnis wurde nicht gefunden: - - - Folgende Datei wurde nicht gefunden: - - - Ein unerwarteter Fehler ist aufgetreten. - - - Auswählen - - - Löschen - - - Aktualisieren - - \ No newline at end of file diff --git a/src/Maple.Test/DependencyInjectionFactoryTests.cs b/src/Maple.Test/DependencyInjectionFactoryTests.cs deleted file mode 100644 index a168d9c..0000000 --- a/src/Maple.Test/DependencyInjectionFactoryTests.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using DryIoc; -using Maple.Core; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using NSubstitute; - -namespace Maple.Test -{ - [TestClass] - public sealed class DependencyInjectionFactoryTests - { - - [TestMethod] - public async Task SanityMapleGetContainerTest() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - container.VerifyResolutions(); - } - - [TestMethod] - public async Task ResolveMessengerTest() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - - var messenger = Substitute.For(); - container.UseInstance(typeof(IMessenger), messenger, IfAlreadyRegistered: IfAlreadyRegistered.Replace); - - Assert.AreEqual(messenger, container.Resolve()); - } - - [TestMethod] - public async Task ResolveLoadablesAsList() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - - var factory = Substitute.For(); - container.UseInstance(factory); - - var loadables = container.Resolve>(); - - Assert.IsNotNull(loadables); - Assert.IsTrue(loadables?.Count > 3, $"Only {loadables.Count} instance(s) found"); - } - - [TestMethod] - public async Task ResolveManyLoadablesAsList() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - - var factory = Substitute.For(); - container.UseInstance(factory); - - var loadables = container.ResolveMany().ToList(); - - Assert.IsNotNull(loadables); - Assert.IsTrue(loadables?.Count > 3, $"Only {loadables.Count} instance(s) found"); - } - } -} diff --git a/src/Maple.Test/DiagnosticReportTests.cs b/src/Maple.Test/DiagnosticReportTests.cs deleted file mode 100644 index bac4fa6..0000000 --- a/src/Maple.Test/DiagnosticReportTests.cs +++ /dev/null @@ -1,269 +0,0 @@ -using Maple.Core; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public sealed class DiagnosticReportTests - { - [TestMethod, Ignore("can only be run on system with EN OS")] - public void When_generating_full_report() - { - var report = DiagnosticReport.Generate(); - report.ShouldNotBeNull(); - report.Length.ShouldBeGreaterThan(1000); - - report.ShouldStartWith("/\r\n|Diagnostic Report generated at:"); - report.ShouldContain("\r\n|\r\n|System|..."); - report.ShouldContain("\r\n|\r\n|Process|..."); - report.ShouldContain("\r\n|\r\n|Drives|..."); - report.ShouldContain("\r\n|\r\n|Assemblies|..."); - report.ShouldContain("\r\n|\r\n|Networking|..."); - report.ShouldContain("|\r\n|\t. Windows IP Configuration\r\n|"); - report.ShouldEndWith("\\"); - } - - [TestMethod, Ignore("can only be run on system with EN OS")] - public void When_generating_full_report_with_flag() - { - // ReSharper disable once RedundantArgumentDefaultValue - var report = DiagnosticReport.Generate(DiagnosticReportType.Full); - report.ShouldNotBeNull(); - report.Length.ShouldBeGreaterThan(1000); - - report.ShouldStartWith("/\r\n|Diagnostic Report generated at:"); - report.ShouldContain("\r\n|\r\n|System|..."); - report.ShouldContain("\r\n|\r\n|Process|..."); - report.ShouldContain("\r\n|\r\n|Drives|..."); - report.ShouldContain("\r\n|\r\n|Assemblies|..."); - report.ShouldContain("\r\n|\r\n|Networking|..."); - report.ShouldContain("|\r\n|\t. Windows IP Configuration\r\n|"); - report.ShouldEndWith("\\"); - } - - [TestMethod] - public void When_generating_system_report_with_flag() - { - var report = DiagnosticReport.Generate(DiagnosticReportType.System); - report.ShouldNotBeNull(); - report.Length.ShouldBeGreaterThan(100); - - report.ShouldStartWith("/\r\n|Diagnostic Report generated at:"); - report.ShouldContain("\r\n|\r\n|System|..."); - report.ShouldNotContain("\r\n|\r\n|Process|..."); - report.ShouldNotContain("\r\n|\r\n|Drives|..."); - report.ShouldNotContain("\r\n|\r\n|Assemblies|..."); - report.ShouldNotContain("\r\n|\r\n|Networking|..."); - report.ShouldNotContain("|\r\n|\t. Windows IP Configuration\r\n|"); - report.ShouldEndWith("\\"); - } - - [TestMethod] - public void When_generating_process_report_with_flag() - { - var report = DiagnosticReport.Generate(DiagnosticReportType.Process); - report.ShouldNotBeNull(); - report.Length.ShouldBeGreaterThan(100); - - report.ShouldStartWith("/\r\n|Diagnostic Report generated at:"); - report.ShouldNotContain("\r\n|\r\n|System|..."); - report.ShouldContain("\r\n|\r\n|Process|..."); - report.ShouldNotContain("\r\n|\r\n|Drives|..."); - report.ShouldNotContain("\r\n|\r\n|Assemblies|..."); - report.ShouldNotContain("\r\n|\r\n|Networking|..."); - report.ShouldNotContain("|\r\n|\t. Windows IP Configuration\r\n|"); - report.ShouldEndWith("\\"); - } - - [TestMethod] - public void When_generating_drives_report_with_flag() - { - var report = DiagnosticReport.Generate(DiagnosticReportType.Drives); - report.ShouldNotBeNull(); - report.Length.ShouldBeGreaterThan(100); - - report.ShouldStartWith("/\r\n|Diagnostic Report generated at:"); - report.ShouldNotContain("\r\n|\r\n|System|..."); - report.ShouldNotContain("\r\n|\r\n|Process|..."); - report.ShouldContain("\r\n|\r\n|Drives|..."); - report.ShouldNotContain("\r\n|\r\n|Assemblies|..."); - report.ShouldNotContain("\r\n|\r\n|Networking|..."); - report.ShouldNotContain("|\r\n|\t. Windows IP Configuration\r\n|"); - report.ShouldEndWith("\\"); - } - - [TestMethod] - public void When_generating_assemblies_report_with_flag() - { - var report = DiagnosticReport.Generate(DiagnosticReportType.Assemblies); - report.ShouldNotBeNull(); - report.Length.ShouldBeGreaterThan(100); - - report.ShouldStartWith("/\r\n|Diagnostic Report generated at:"); - report.ShouldNotContain("\r\n|\r\n|System|..."); - report.ShouldNotContain("\r\n|\r\n|Process|..."); - report.ShouldNotContain("\r\n|\r\n|Drives|..."); - report.ShouldContain("\r\n|\r\n|Assemblies|..."); - report.ShouldNotContain("\r\n|\r\n|Networking|..."); - report.ShouldNotContain("|\r\n|\t. Windows IP Configuration\r\n|"); - report.ShouldEndWith("\\"); - } - - [TestMethod, Ignore("can only be run on system with EN OS")] - public void When_generating_networking_report_with_flag() - { - var report = DiagnosticReport.Generate(DiagnosticReportType.Networking); - report.ShouldNotBeNull(); - report.Length.ShouldBeGreaterThan(100); - - report.ShouldStartWith("/\r\n|Diagnostic Report generated at:"); - report.ShouldNotContain("\r\n|\r\n|System|..."); - report.ShouldNotContain("\r\n|\r\n|Process|..."); - report.ShouldNotContain("\r\n|\r\n|Drives|..."); - report.ShouldNotContain("\r\n|\r\n|Assemblies|..."); - report.ShouldContain("\r\n|\r\n|Networking|..."); - report.ShouldContain("|\r\n|\t. Windows IP Configuration\r\n|"); - report.ShouldEndWith("\\"); - } - - [TestMethod] - public void When_generating_system_and_process_report() - { - var flags = DiagnosticReportType.System | DiagnosticReportType.Process; - var report = DiagnosticReport.Generate(flags); - report.ShouldNotBeNull(); - report.Length.ShouldBeGreaterThan(100); - - report.ShouldStartWith("/\r\n|Diagnostic Report generated at:"); - report.ShouldContain("\r\n|\r\n|System|..."); - report.ShouldContain("\r\n|\r\n|Process|..."); - report.ShouldNotContain("\r\n|\r\n|Drives|..."); - report.ShouldNotContain("\r\n|\r\n|Assemblies|..."); - report.ShouldNotContain("\r\n|\r\n|Networking|..."); - report.ShouldNotContain("|\r\n|\t. Windows IP Configuration\r\n|"); - report.ShouldEndWith("\\"); - } - - [TestMethod] - public void When_generating_system_and_drives_report() - { - var flags = DiagnosticReportType.System | DiagnosticReportType.Drives; - var report = DiagnosticReport.Generate(flags); - report.ShouldNotBeNull(); - report.Length.ShouldBeGreaterThan(100); - - report.ShouldStartWith("/\r\n|Diagnostic Report generated at:"); - report.ShouldContain("\r\n|\r\n|System|..."); - report.ShouldNotContain("\r\n|\r\n|Process|..."); - report.ShouldContain("\r\n|\r\n|Drives|..."); - report.ShouldNotContain("\r\n|\r\n|Assemblies|..."); - report.ShouldNotContain("\r\n|\r\n|Networking|..."); - report.ShouldNotContain("|\r\n|\t. Windows IP Configuration\r\n|"); - report.ShouldEndWith("\\"); - } - - [TestMethod] - public void When_generating_system_and_assemblies_report() - { - var flags = DiagnosticReportType.System | DiagnosticReportType.Assemblies; - var report = DiagnosticReport.Generate(flags); - report.ShouldNotBeNull(); - report.Length.ShouldBeGreaterThan(100); - - report.ShouldStartWith("/\r\n|Diagnostic Report generated at:"); - report.ShouldContain("\r\n|\r\n|System|..."); - report.ShouldNotContain("\r\n|\r\n|Process|..."); - report.ShouldNotContain("\r\n|\r\n|Drives|..."); - report.ShouldContain("\r\n|\r\n|Assemblies|..."); - report.ShouldNotContain("\r\n|\r\n|Networking|..."); - report.ShouldNotContain("|\r\n|\t. Windows IP Configuration\r\n|"); - report.ShouldEndWith("\\"); - } - - [TestMethod, Ignore("can only be run on system with EN OS")] - public void When_generating_system_and_networking_report() - { - var flags = DiagnosticReportType.System | DiagnosticReportType.Networking; - var report = DiagnosticReport.Generate(flags); - report.ShouldNotBeNull(); - report.Length.ShouldBeGreaterThan(100); - - report.ShouldStartWith("/\r\n|Diagnostic Report generated at:"); - report.ShouldContain("\r\n|\r\n|System|..."); - report.ShouldNotContain("\r\n|\r\n|Process|..."); - report.ShouldNotContain("\r\n|\r\n|Drives|..."); - report.ShouldNotContain("\r\n|\r\n|Assemblies|..."); - report.ShouldContain("\r\n|\r\n|Networking|..."); - report.ShouldContain("|\r\n|\t. Windows IP Configuration\r\n|"); - report.ShouldEndWith("\\"); - } - - - [TestMethod, Ignore("can only be run on system with EN OS")] - public void When_generating_system_and_process_and_drives_and_assemblies_and_environment_variables_and_networking_report() - { - var flags = DiagnosticReportType.System - | DiagnosticReportType.Process - | DiagnosticReportType.Drives - | DiagnosticReportType.Assemblies - | DiagnosticReportType.Networking; - - var report = DiagnosticReport.Generate(flags); - report.ShouldNotBeNull(); - report.Length.ShouldBeGreaterThan(1000); - - report.ShouldStartWith("/\r\n|Diagnostic Report generated at:"); - report.ShouldContain("\r\n|\r\n|System|..."); - report.ShouldContain("\r\n|\r\n|Process|..."); - report.ShouldContain("\r\n|\r\n|Drives|..."); - report.ShouldContain("\r\n|\r\n|Assemblies|..."); - report.ShouldContain("\r\n|\r\n|Networking|..."); - report.ShouldContain("|\r\n|\t. Windows IP Configuration\r\n|"); - report.ShouldEndWith("\\"); - } - - [TestMethod, Ignore("can only be run on system with EN OS")] - public void When_generating_process_and_assemblies_and_networking_report() - { - var flags = DiagnosticReportType.Process - | DiagnosticReportType.Assemblies - | DiagnosticReportType.Networking; - - var report = DiagnosticReport.Generate(flags); - report.ShouldNotBeNull(); - report.Length.ShouldBeGreaterThan(500); - - report.ShouldStartWith("/\r\n|Diagnostic Report generated at:"); - report.ShouldNotContain("\r\n|\r\n|System|..."); - report.ShouldContain("\r\n|\r\n|Process|..."); - report.ShouldNotContain("\r\n|\r\n|Drives|..."); - report.ShouldContain("\r\n|\r\n|Assemblies|..."); - report.ShouldContain("\r\n|\r\n|Networking|..."); - report.ShouldContain("|\r\n|\t. Windows IP Configuration\r\n|"); - report.ShouldEndWith("\\"); - } - - [TestMethod, Ignore("can only be run on system with EN OS")] - public void When_generating_process_and_assemblies_and_networking_and_full_report() - { - var flags = DiagnosticReportType.Process - | DiagnosticReportType.Assemblies - | DiagnosticReportType.Networking - | DiagnosticReportType.Full; - - var report = DiagnosticReport.Generate(flags); - report.ShouldNotBeNull(); - report.Length.ShouldBeGreaterThan(1000); - - report.ShouldStartWith("/\r\n|Diagnostic Report generated at:"); - report.ShouldContain("\r\n|\r\n|System|..."); - report.ShouldContain("\r\n|\r\n|Process|..."); - report.ShouldContain("\r\n|\r\n|Drives|..."); - report.ShouldContain("\r\n|\r\n|Assemblies|..."); - report.ShouldContain("\r\n|\r\n|Networking|..."); - report.ShouldContain("|\r\n|\t. Windows IP Configuration\r\n|"); - report.ShouldEndWith("\\"); - } - } -} \ No newline at end of file diff --git a/src/Maple.Test/DynamicDictionaryTests.cs b/src/Maple.Test/DynamicDictionaryTests.cs deleted file mode 100644 index ac76e9a..0000000 --- a/src/Maple.Test/DynamicDictionaryTests.cs +++ /dev/null @@ -1,267 +0,0 @@ -using System; -using System.Collections.Generic; -using Maple.Core; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public sealed class DynamicDictionaryTests - { - [TestMethod] - public void When_testing_as_concrete_type() - { - var dic = new DynamicDictionary(); - dic.Count.ShouldBe(0); - - dic["A"] = "A"; - dic["B"] = "B"; - dic["C"] = "C"; - dic["D"] = 1; - - dic.Count.ShouldBe(4); - dic["A"].ShouldBe("A"); - dic["a"].ShouldBe("A"); - dic["B"].ShouldBe("B"); - dic["b"].ShouldBe("B"); - dic["C"].ShouldBe("C"); - dic["c"].ShouldBe("C"); - dic["D"].ShouldBe(1); - dic["d"].ShouldBe(1); - - dic.Keys.ShouldBe(new[] { "A", "B", "C", "D" }); - dic.Values.ShouldBe(new object[] { "A", "B", "C", 1 }); - - dic["non-existent"].ShouldBeNull(); - } - - [TestMethod] - public void When_testing_as_dynamic_type() - { - dynamic dic = new DynamicDictionary(); - ((int)dic.Count).ShouldBe(0); - - dic["A"] = "A"; - dic["B"] = "B"; - dic["C"] = "C"; - dic["D"] = 1; - -#pragma warning disable IDE0039 // Use local function - Func someFunc = () => 1234; -#pragma warning restore IDE0039 // Use local function - dic.action = someFunc; - - ((int)dic.Count).ShouldBe(5); - ((string)dic["A"]).ShouldBe("A"); - ((string)dic["a"]).ShouldBe("A"); - ((string)dic["B"]).ShouldBe("B"); - ((string)dic["b"]).ShouldBe("B"); - ((string)dic["C"]).ShouldBe("C"); - ((string)dic["c"]).ShouldBe("C"); - ((int)dic["D"]).ShouldBe(1); - ((int)dic["d"]).ShouldBe(1); - - ((int)dic.action()).ShouldBe(1234); - ((int)dic.ACTION()).ShouldBe(1234); - - ((string)dic.A).ShouldBe("A"); - ((string)dic.a).ShouldBe("A"); - ((int)dic.D).ShouldBe(1); - ((int)dic.d).ShouldBe(1); - - ((ICollection)dic.Keys).ShouldBe(new[] { "A", "B", "C", "D", "action" }); - ((ICollection)dic.Values).ShouldBe(new object[] { "A", "B", "C", 1, someFunc }); - - ((string)dic["non-existent"]).ShouldBeNull(); - - dic.foo = "foo"; - ((string)dic["foo"]).ShouldBe("foo"); - ((string)dic["Foo"]).ShouldBe("foo"); - } - - [TestMethod] - public void When_testing_case_sensitivity() - { - var caseSensetiveDic = new DynamicDictionary(false) - { - ["A"] = 1, - ["Id"] = 66 - }; - - caseSensetiveDic["A"].ShouldBe(1); - caseSensetiveDic["Id"].ShouldBe(66); - - caseSensetiveDic["a"].ShouldBeNull(); - caseSensetiveDic["ID"].ShouldBeNull(); - caseSensetiveDic["iD"].ShouldBeNull(); - - dynamic dynCaseSensetiveDic = caseSensetiveDic; - dynCaseSensetiveDic.A = "sample"; - ((string)dynCaseSensetiveDic.A).ShouldBe("sample"); - ((int)dynCaseSensetiveDic.Id).ShouldBe(66); - - ((string)dynCaseSensetiveDic.a).ShouldBeNull(); - ((string)dynCaseSensetiveDic.ID).ShouldBeNull(); - - var caseInSensetiveDic = new DynamicDictionary() - { - ["A"] = 1, - ["Id"] = 66 - }; - - caseInSensetiveDic["A"].ShouldBe(1); - caseInSensetiveDic["Id"].ShouldBe(66); - - caseInSensetiveDic["a"].ShouldBe(1); - caseInSensetiveDic["ID"].ShouldBe(66); - caseInSensetiveDic["iD"].ShouldBe(66); - - dynamic dynCaseInSensetiveDic = caseInSensetiveDic; - dynCaseInSensetiveDic.A = "sample"; - ((string)dynCaseInSensetiveDic.A).ShouldBe("sample"); - ((string)dynCaseInSensetiveDic.a).ShouldBe("sample"); - - ((int)dynCaseInSensetiveDic.Id).ShouldBe(66); - ((int)dynCaseInSensetiveDic.ID).ShouldBe(66); - ((int)dynCaseInSensetiveDic.id).ShouldBe(66); - } - - [TestMethod] - public void When_enumerating_as_dynamic() - { - dynamic dic = new DynamicDictionary(); - ((int)dic.Count).ShouldBe(0); - - dic["A"] = "1"; - dic["B"] = "2"; - dic["C"] = "3"; - dic["D"] = 66; - - foreach (KeyValuePair pair in dic) - { - pair.Key.ShouldBeOfType(); - - if (pair.Key == "A") - { - pair.Value.ShouldBeOfType(); - pair.Value.ShouldBe("1"); - } - - if (pair.Key == "B") - { - pair.Value.ShouldBeOfType(); - pair.Value.ShouldBe("2"); - } - - if (pair.Key == "C") - { - pair.Value.ShouldBeOfType(); - pair.Value.ShouldBe("3"); - } - - if (pair.Key == "D") - { - pair.Value.ShouldBeOfType(); - pair.Value.ShouldBe(66); - } - } - } - - [TestMethod] - public void When_enumerating_as_original_type() - { - var dic = new DynamicDictionary(); - dic.Count.ShouldBe(0); - - dic["A"] = "1"; - dic["B"] = "2"; - dic["C"] = "3"; - dic["D"] = 66; - - foreach (var pair in dic) - { - pair.Key.ShouldBeOfType(); - - if (pair.Key == "A") - { - pair.Value.ShouldBeOfType(); - pair.Value.ShouldBe("1"); - } - - if (pair.Key == "B") - { - pair.Value.ShouldBeOfType(); - pair.Value.ShouldBe("2"); - } - - if (pair.Key == "C") - { - pair.Value.ShouldBeOfType(); - pair.Value.ShouldBe("3"); - } - - if (pair.Key == "D") - { - pair.Value.ShouldBeOfType(); - pair.Value.ShouldBe(66); - } - } - } - - [TestMethod] - public void When_getting_a_model_as_dynamic_dictionary() - { - var model = new Child { Name = "Foo", Age = 10 }; - var dicWithInherittedProp = model.ToDynamic(); - - dicWithInherittedProp.ShouldNotBeNull(); - dicWithInherittedProp.Count.ShouldBe(3); - dicWithInherittedProp["OriginalName"].ShouldBe("PaPa"); - dicWithInherittedProp["Name"].ShouldBe("Foo"); - dicWithInherittedProp["Age"].ShouldBe(10); - - var dicWithDeclaredProp = model.ToDynamic(false); - - dicWithDeclaredProp.ShouldNotBeNull(); - dicWithDeclaredProp.Count.ShouldBe(2); - dicWithDeclaredProp["OriginalName"].ShouldBeNull(); - dicWithDeclaredProp["Name"].ShouldBe("Foo"); - dicWithDeclaredProp["Age"].ShouldBe(10); - } - - [TestMethod] - public void When_getting_a_model_as_dynamic() - { - var model = new Child { Name = "Foo", Age = 10 }; - dynamic dicWithInherittedProp = model.ToDynamic(); - - ((DynamicDictionary)dicWithInherittedProp).ShouldNotBeNull(); - ((DynamicDictionary)dicWithInherittedProp).Count.ShouldBe(3); - - ((string)dicWithInherittedProp["OriginalName"]).ShouldBe("PaPa"); - ((string)dicWithInherittedProp["Name"]).ShouldBe("Foo"); - ((int)dicWithInherittedProp["Age"]).ShouldBe(10); - - dynamic dicWithDeclaredProp = model.ToDynamic(false); - - ((DynamicDictionary)dicWithDeclaredProp).ShouldNotBeNull(); - ((DynamicDictionary)dicWithDeclaredProp).Count.ShouldBe(2); - - ((string)dicWithDeclaredProp["OriginalName"]).ShouldBeNull(); - ((string)dicWithDeclaredProp["Name"]).ShouldBe("Foo"); - ((int)dicWithDeclaredProp["Age"]).ShouldBe(10); - } - - private class Base - { - public string OriginalName => "PaPa"; - } - - private sealed class Child : Base - { - public string Name { get; set; } - public int Age { get; set; } - } - } -} diff --git a/src/Maple.Test/Ensure/EnsuringCollectionNotNullOrEmptyTest.cs b/src/Maple.Test/Ensure/EnsuringCollectionNotNullOrEmptyTest.cs deleted file mode 100644 index 8cb4fc4..0000000 --- a/src/Maple.Test/Ensure/EnsuringCollectionNotNullOrEmptyTest.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using Maple.Core; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public class EnsuringCollectionNotNullOrEmptyTest - { - [TestMethod] - public void When_checking_a_null_string_collection() - { - List collection = null; - - Should.Throw(() => - { - Ensure.NotNullOrEmpty(collection); - }, "Because collection is null."); - } - - [TestMethod] - public void When_checking_an_empty_string_collection() - { - var collection = Enumerable.Empty().ToList(); - - Action action = () => Ensure.NotNullOrEmpty(collection); - - action.ShouldThrow("Because collection is empty."); - } - - [TestMethod] - public void When_checking_a_non_empty_collection() - { - var collection = new List { "Item One" }; - - ICollection returnedValue = new Collection(); - Action action = () => returnedValue = Ensure.NotNullOrEmpty(collection); - - action.ShouldNotThrow("Because collection is not empty."); - returnedValue.ShouldBeSameAs(collection); - } - } -} diff --git a/src/Maple.Test/Ensure/EnsuringEqualTests.cs b/src/Maple.Test/Ensure/EnsuringEqualTests.cs deleted file mode 100644 index 4884ce7..0000000 --- a/src/Maple.Test/Ensure/EnsuringEqualTests.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System; -using Maple.Core; -using Maple.Localization.Properties; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public class EnsuringEqualTests - { - [TestMethod] - public void When_comparing_equal_strings() - { - const string FirstString = "One"; - const string SecondString = "One"; - - Action action = () => Ensure.Equal(FirstString, SecondString); - - action.ShouldNotThrow("Because the two strings are equal"); - } - - [TestMethod] - public void When_comparing_equal_integers() - { - const int FirstInteger = 1; - const int SecondInteger = 1; - - Action action = () => Ensure.Equal(FirstInteger, SecondInteger); - - action.ShouldNotThrow("Because the two integers are equal"); - } - - [TestMethod] - public void When_comparing_different_types_with_equal_values() - { - const string FirstString = "One"; - object secondString = "One"; - - Action action = () => Ensure.Equal(FirstString, secondString); - - action.ShouldNotThrow("Because the two objects are equal"); - } - - [TestMethod] - public void When_comparing_different_strings() - { - const string FirstString = "One"; - const string SecondString = "Two"; - - Action action = () => Ensure.Equal(FirstString, SecondString); - - action.ShouldThrow("Because the two strings are different").Message.ShouldBe(Resources.ExceptionMessageEqualValues); - } - - [TestMethod] - public void When_comparing_different_integers() - { - const int FirstInteger = 1; - const int SecondInteger = 2; - - Action action = () => Ensure.Equal(FirstInteger, SecondInteger); - - action.ShouldThrow("Because the two integers are different").Message.ShouldBe(Resources.ExceptionMessageEqualValues); - } - - [TestMethod] - public void When_comparing_string_against_null_object() - { - const string FirstString = "Sample"; - string secondString = null; - - Action action = () => Ensure.Equal(FirstString, secondString); - - action.ShouldThrow("Because the objects are different").Message.ShouldBe(Resources.ExceptionMessageEqualValues); - } - - [TestMethod] - public void When_comparing_null_object_against_string() - { - string firstString = null; - const string SecondString = "Sample"; - - Action action = () => Ensure.Equal(firstString, SecondString); - - action.ShouldThrow("Because the first object is null"); - } - - [TestMethod] - public void When_comparing_two_null_objects() - { - string firstString = null; - string secondSTring = null; - - Action action = () => Ensure.Equal(firstString, secondSTring); - - action.ShouldThrow(); - } - } -} diff --git a/src/Maple.Test/Ensure/EnsuringExistsTests.cs b/src/Maple.Test/Ensure/EnsuringExistsTests.cs deleted file mode 100644 index bb2595a..0000000 --- a/src/Maple.Test/Ensure/EnsuringExistsTests.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System.IO; -using Maple.Core; -using Maple.Localization.Properties; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public sealed class EnsuringExistsTests - { - [TestMethod] - public void When_ensuring_directoryInfo_exists() - { - var nonExistingDirectoryPath = Path.GetRandomFileName(); - var nonExistingDirInfo = new DirectoryInfo(nonExistingDirectoryPath); - - Should.Throw(() => Ensure.Exists(nonExistingDirInfo)).Message.ShouldBe($"{Resources.ExceptionMessageMissingDirectory}{nonExistingDirInfo.FullName}"); - - nonExistingDirInfo.Create(); - - var existingDirInfo = nonExistingDirInfo; - - Should.NotThrow(() => Ensure.Exists(existingDirInfo)); - Ensure.Exists(existingDirInfo).ShouldBe(existingDirInfo); - - try - { - existingDirInfo.Delete(); - } - catch { /* ignored */ } - } - - [TestMethod] - public void When_ensuring_fileInfo_exists() - { - var nonExistingFilePath = Path.GetRandomFileName(); - var nonExistingFileInfo = new FileInfo(nonExistingFilePath); - - Should.Throw(() => Ensure.Exists(nonExistingFileInfo)).Message.ShouldBe($"{Resources.ExceptionMessageMissingFile}{nonExistingFileInfo.FullName}"); - - nonExistingFileInfo.Create(); - - var existingFileInfo = nonExistingFileInfo; - - Should.NotThrow(() => Ensure.Exists(existingFileInfo)); - Ensure.Exists(existingFileInfo).ShouldBe(existingFileInfo); - - try - { - existingFileInfo.Delete(); - } - catch { /* ignored */ } - } - } -} diff --git a/src/Maple.Test/Ensure/EnsuringNotEqualTests.cs b/src/Maple.Test/Ensure/EnsuringNotEqualTests.cs deleted file mode 100644 index 4ecbeff..0000000 --- a/src/Maple.Test/Ensure/EnsuringNotEqualTests.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System; -using Maple.Core; -using Maple.Localization.Properties; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public class EnsuringNotEqualTests - { - [TestMethod] - public void When_comparing_equal_strings() - { - const string FirstString = "One"; - const string SecondString = "One"; - - Action action = () => Ensure.NotEqual(FirstString, SecondString); - - action.ShouldThrow("Because the two strings are equal").Message.ShouldBe(Resources.ExceptionMessageNotEqualValues); - } - - [TestMethod] - public void When_comparing_equal_integers() - { - const int FirstInteger = 1; - const int SecondInteger = 1; - - Action action = () => Ensure.NotEqual(FirstInteger, SecondInteger); - - action.ShouldThrow("Because the two integers are equal").Message.ShouldBe(Resources.ExceptionMessageNotEqualValues); - } - - [TestMethod] - public void When_comparing_different_types_with_equal_values() - { - const string FirstString = "One"; - object secondString = "One"; - - Action action = () => Ensure.NotEqual(FirstString, secondString); - - action.ShouldThrow("Because the two objects are equal").Message.ShouldBe(Resources.ExceptionMessageNotEqualValues); - } - - [TestMethod] - public void When_comparing_different_strings() - { - const string FirstString = "One"; - const string SecondString = "Two"; - - Action action = () => Ensure.NotEqual(FirstString, SecondString); - - action.ShouldNotThrow("Because the two strings are different"); - } - - [TestMethod] - public void When_comparing_different_integers() - { - const int FirstInteger = 1; - const int SecondInteger = 2; - - Action action = () => Ensure.NotEqual(FirstInteger, SecondInteger); - - action.ShouldNotThrow("Because the two integers are different"); - } - - [TestMethod] - public void When_comparing_string_against_null_object() - { - const string FirstString = "Sample"; - string secondString = null; - - Action action = () => Ensure.NotEqual(FirstString, secondString); - - action.ShouldNotThrow(); - } - - [TestMethod] - public void When_comparing_null_object_against_string() - { - string firstString = null; - const string SecondString = "Sample"; - - Action action = () => Ensure.NotEqual(firstString, SecondString); - - action.ShouldThrow("Because the first object is null"); - } - - [TestMethod] - public void When_comparing_two_null_objects() - { - string firstString = null; - string secondSTring = null; - - Action action = () => Ensure.NotEqual(firstString, secondSTring); - - action.ShouldThrow(); - } - } -} diff --git a/src/Maple.Test/Ensure/EnsuringNotNullTests.cs b/src/Maple.Test/Ensure/EnsuringNotNullTests.cs deleted file mode 100644 index 73bb334..0000000 --- a/src/Maple.Test/Ensure/EnsuringNotNullTests.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using Maple.Core; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public class EnsuringNotNullTests - { - [TestMethod] - public void When_ensuring_null_string() - { - string nullStr = null; - Should.Throw(() => Ensure.NotNull(nullStr, "nullStr")); - } - - [TestMethod] - public void When_ensuring_null_object() - { - object nullObj = null; - Should.Throw(() => Ensure.NotNull(nullObj, "nullObj")); - } - - [TestMethod] - public void When_ensuring_non_null_object() - { - object nonNullObj = 1; - Should.NotThrow(() => Ensure.NotNull(nonNullObj, "nonNullObj"), - "Because nonNullObject is not null"); - } - - [TestMethod] - public void When_ensuring_non_null_object_with_null_argument_name() - { - object anyObject = 120; - Should.NotThrow(() => Ensure.NotNull(anyObject, null), - "Because object is not null"); - } - - [TestMethod] - public void When_ensuring_null_object_with_null_argument_name() - { - object nullObject = null; - Should.Throw(() => Ensure.NotNull(nullObject, null)); - } - } -} diff --git a/src/Maple.Test/Ensure/EnsuringNotTests.cs b/src/Maple.Test/Ensure/EnsuringNotTests.cs deleted file mode 100644 index 3cdb38b..0000000 --- a/src/Maple.Test/Ensure/EnsuringNotTests.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using Maple.Core; -using Maple.Localization.Properties; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public class EnsuringNotTests - { - [TestMethod] - public void When_ensuring_true_condition() - { - Should.Throw(() => Ensure.Not(true)).Message.ShouldBe(Resources.ExceptionMessageFalseCondition); - } - - [TestMethod] - public void When_ensuring_true_condition_with_custom_exception() - { - Should.Throw(() => Ensure.Not(true)).Message.ShouldBe(Resources.ExceptionMessageTrueCondition); - } - - [TestMethod] - public void When_ensuring_true_condition_with_custom_message() - { - Should.Throw(() => Ensure.Not(true, "Cause I say so!")).Message.ShouldBe("Cause I say so!"); - } - - [TestMethod] - public void When_ensuring_false_condition_with_default_exception() - { - Should.NotThrow(() => Ensure.Not(false), Resources.ExceptionMessageFalseCondition); - } - - [TestMethod] - public void When_ensuring_false_condition_with_custom_exception() - { - Should.Throw(() => Ensure.Not(true)).Message.ShouldBe(Resources.ExceptionMessageTrueCondition); - } - - [TestMethod] - public void When_ensuring_false_condition_with_custom_message() - { - Should.Throw(() => Ensure.Not(true, "Cause I say so!")).Message.ShouldBe("Cause I say so!"); - } - } -} diff --git a/src/Maple.Test/Ensure/EnsuringThatTests.cs b/src/Maple.Test/Ensure/EnsuringThatTests.cs deleted file mode 100644 index 08f61f1..0000000 --- a/src/Maple.Test/Ensure/EnsuringThatTests.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using Maple.Core; -using Maple.Localization.Properties; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public class EnsuringThatTests - { - [TestMethod] - public void When_ensuring_true_condition() - { - Should.NotThrow(() => Ensure.That(true), Resources.ExceptionMessageTrueCondition); - } - - [TestMethod] - public void When_ensuring_true_condition_with_custom_exception() - { - Should.NotThrow(() => Ensure.That(true), Resources.ExceptionMessageTrueCondition); - } - - [TestMethod] - public void When_ensuring_true_condition_with_custom_message() - { - Should.NotThrow(() => Ensure.That(true), Resources.ExceptionMessageTrueCondition); - } - - [TestMethod] - public void When_ensuring_false_condition_with_default_exception() - { - Should.Throw(() => Ensure.That(false), Resources.ExceptionMessageFalseCondition).Message.ShouldBe(Resources.ExceptionMessageFalseCondition); - } - - [TestMethod] - public void When_ensuring_false_condition_with_custom_exception() - { - Should.Throw(() => Ensure.That(false)).Message.ShouldBe(Resources.ExceptionMessageFalseCondition); - } - - [TestMethod] - public void When_ensuring_false_condition_with_custom_message() - { - Should.Throw(() => Ensure.That(false, "Cause I say so!"), Resources.ExceptionMessageFalseCondition).Message.ShouldBe("Cause I say so!"); - } - } -} diff --git a/src/Maple.Test/Maple.Test.csproj b/src/Maple.Test/Maple.Test.csproj deleted file mode 100644 index eb633d0..0000000 --- a/src/Maple.Test/Maple.Test.csproj +++ /dev/null @@ -1,132 +0,0 @@ - - - Debug - AnyCPU - {60F95B05-E714-4E0F-BA97-44711EC74210} - Library - Properties - Maple.Test - Maple.Test - v4.7.1 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 15.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - UnitTest - - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Designer - - - - - {21fa5854-0692-42e2-924e-a38cf3c7ff71} - Maple.Core - - - {b3cd46be-3c08-4bae-ae60-a6d84a62400c} - Maple.Data - - - {9d7d05a6-8271-4836-a7bb-5b2abeccbd81} - Maple.Domain - - - {a073fc92-90e3-4541-8b52-6f7293187871} - Maple.Localization - - - {b5be546f-8d9f-4fb9-b235-af05fd553f9e} - Maple.Youtube - - - {fbd5595b-6859-4e8e-bdfa-c3169ef34985} - Maple - - - - - 2.12.5 - - - 1.2.0 - - - 1.2.0 - - - 3.1.0 - - - 2.8.3 - - - - - \ No newline at end of file diff --git a/src/Maple.Test/MapleMessengerTests.cs b/src/Maple.Test/MapleMessengerTests.cs deleted file mode 100644 index 337d873..0000000 --- a/src/Maple.Test/MapleMessengerTests.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System; -using Maple.Core; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Maple.Test -{ - [TestClass, Ignore] - public class MapleMessengerTests - { - //[TestMethod] - //public void Dispose_WithValidHubReference_UnregistersWithHub() - //{ - // var messengerMock = NSubstitute.Substitute.For(); - // messengerMock.Setup((messenger) => messenger.Unsubscribe(Moq.It.IsAny())).Verifiable(); - // var token = new MapleMessageSubscriptionToken(messengerMock, typeof(TestMessage)); - - // token.Dispose(); - - // messengerMock.VerifyAll(); - //} - - //[TestMethod] - //public void Dispose_WithInvalidHubReference_DoesNotThrow() - //{ - // var token = UtilityMethods.GetTokenWithOutOfScopeMessenger(); - // GC.Collect(); - // GC.WaitForFullGCComplete(2000); - - // token.Dispose(); - //} - - //[TestMethod] - //[ExpectedException(typeof(ArgumentNullException))] - //public void Ctor_NullHub_ThrowsArgumentNullException() - //{ - // var messenger = UtilityMethods.GetMessenger(); - - // var token = new MapleMessageSubscriptionToken(null, typeof(IMapleMessage)); - //} - - //[TestMethod] - //[ExpectedException(typeof(ArgumentOutOfRangeException))] - //public void Ctor_InvalidMessageType_ThrowsArgumentOutOfRangeException() - //{ - // var messenger = UtilityMethods.GetMessenger(); - - // var token = new MapleMessageSubscriptionToken(messenger, typeof(object)); - //} - - //[TestMethod] - //public void Ctor_ValidHubAndMessageType_DoesNotThrow() - //{ - // var messenger = UtilityMethods.GetMessenger(); - - // var token = new MapleMessageSubscriptionToken(messenger, typeof(TestMessage)); - //} - - public class TestMessage : MapleMessageBase - { - public TestMessage(object sender) : base(sender) - { - - } - } - - public class DerivedMessage : TestMessage - { - public TThings Things { get; set; } - - public DerivedMessage(object sender) - : base(sender) - { - } - } - - public interface ITestMessageInterface : IMapleMessage - { - - } - - public class InterfaceDerivedMessage : ITestMessageInterface - { - public object Sender { get; private set; } - - public TThings Things { get; set; } - - public InterfaceDerivedMessage(object sender) - { - Sender = sender; - } - } - - public class TestProxy : IMapleMessageProxy - { - public IMapleMessage Message { get; private set; } - - public void Deliver(IMapleMessage message, IMapleMessageSubscription subscription) - { - Message = message; - subscription.Deliver(message); - } - } - - public class TestSubscriptionErrorHandler : ISubscriberErrorHandler - { - public void Handle(IMapleMessage message, Exception exception) - { - throw exception; - } - } - - public class UtilityMethods - { - //public static IMapleMessengerHub GetMessenger() - //{ - // return new MapleMessengerHub(); - //} - - //public static IMapleMessengerHub GetMessengerWithSubscriptionErrorHandler() - //{ - // return new MapleMessengerHub(new TestSubscriptionErrorHandler()); - //} - - public static void FakeDeliveryAction(T message) - where T : IMapleMessage - { - } - - public static bool FakeMessageFilter(T message) - where T : IMapleMessage - { - return true; - } - - //public static MapleMessageSubscriptionToken GetTokenWithOutOfScopeMessenger() - //{ - // var messenger = UtilityMethods.GetMessenger(); - - // var token = new MapleMessageSubscriptionToken(messenger, typeof(TestMessage)); - - // return token; - //} - } - } -} diff --git a/src/Maple.Test/Properties/AssemblyInfo.cs b/src/Maple.Test/Properties/AssemblyInfo.cs deleted file mode 100644 index a25706d..0000000 --- a/src/Maple.Test/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,5 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("Maple.Test")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] diff --git a/src/Maple.Test/StringBuilderCacheTests.cs b/src/Maple.Test/StringBuilderCacheTests.cs deleted file mode 100644 index 1a8a771..0000000 --- a/src/Maple.Test/StringBuilderCacheTests.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.Text; -using Maple.Core; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public sealed class StringBuilderCacheTests - { - [TestMethod] - public void When_acquiring_multiple_instances() - { - var builderOne = StringBuilderCache.Acquire(); - var builderTwo = StringBuilderCache.Acquire(); - - builderOne.ShouldNotBeSameAs(builderTwo); - - builderOne.Append("Hello"); - - var builderOneStr = StringBuilderCache.GetStringAndRelease(builderOne); - - builderOneStr.ShouldBe("Hello"); - - var builderThree = StringBuilderCache.Acquire(); - builderThree.ShouldBeSameAs(builderOne); - - var builderTwoStr = StringBuilderCache.GetStringAndRelease(builderTwo); - - builderTwoStr.ShouldBeEmpty(); - - builderThree.ShouldNotBeSameAs(builderTwo); - } - - [TestMethod] - public void When_returning_an_instance_to_the_cache() - { - var builderOne = new StringBuilder(); - builderOne.Append("Foo"); - - var builderOneFirstStr = builderOne.ToString(); - builderOneFirstStr.ShouldBe("Foo"); - - var builderOneSecondStr = StringBuilderCache.GetStringAndRelease(builderOne); - builderOneSecondStr.ShouldBe("Foo"); - - var builderTwo = StringBuilderCache.Acquire(); - - builderOne.ShouldBeSameAs(builderTwo); - - builderTwo.Capacity.ShouldBe(builderOne.Capacity); - - var builderTwoThirdStr = builderTwo.ToString(); - builderTwoThirdStr.ShouldBeEmpty(); - - var builderTwoFourthStr = StringBuilderCache.GetStringAndRelease(builderTwo); - builderTwoFourthStr.ShouldBeEmpty(); - } - } -} \ No newline at end of file diff --git a/src/Maple.Test/TestUtils/ContainerContextExtensions.cs b/src/Maple.Test/TestUtils/ContainerContextExtensions.cs deleted file mode 100644 index 283d43c..0000000 --- a/src/Maple.Test/TestUtils/ContainerContextExtensions.cs +++ /dev/null @@ -1,62 +0,0 @@ -using DryIoc; -using Maple.Core; -using Maple.Domain; -using NSubstitute; - -namespace Maple.Test -{ - public static class ContainerContextExtensions - { - public static Playlists CreatePlaylists(this IContainer container) - { - return new Playlists(container.CreateViewModelServiceContainer(), container.Resolve(), () => container.Resolve()); - } - - public static ViewModelServiceContainer CreateViewModelServiceContainer(this IContainer container) - { - return new ViewModelServiceContainer(CreateLoggingService(), CreateILoggingNotifcationService(), CreateILocalizationService(), container.Resolve(), CreateSequenceService()); - } - - public static Playlist CreatePlaylist(this IContainer container, PlaylistModel model) - { - var mapper = container.Resolve(); - return mapper.Get(model); - } - - public static MediaItem CreateMediaItem(this IContainer container, MediaItemModel model) - { - var mapper = container.Resolve(); - return mapper.Get(model); - } - - public static ISequenceService CreateSequenceService() - { - return Substitute.For(); - } - - public static ILocalizationService CreateILocalizationService() - { - return Substitute.For(); - } - - public static ILoggingNotifcationService CreateILoggingNotifcationService() - { - return Substitute.For(); - } - - public static ILoggingService CreateLoggingService() - { - return Substitute.For(); - } - - public static IDialogViewModel CreateDialogViewModel() - { - return Substitute.For(); - } - - public static IMediaRepository CreateRepository() - { - return Substitute.For(); - } - } -} diff --git a/src/Maple.Test/TestUtils/MediaItemModelContextModelExtensions.cs b/src/Maple.Test/TestUtils/MediaItemModelContextModelExtensions.cs deleted file mode 100644 index 7b1f73c..0000000 --- a/src/Maple.Test/TestUtils/MediaItemModelContextModelExtensions.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using Maple.Domain; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Maple.Test -{ - public static class MediaItemModelContextModelExtensions - { - public static MediaItemModel CreateModelMediaItem(this TestContext context) - { - return new MediaItemModel() - { - CreatedBy = context.FullyQualifiedTestClassName, - CreatedOn = DateTime.UtcNow, - UpdatedOn = DateTime.UtcNow, - UpdatedBy = context.FullyQualifiedTestClassName, - Description = $"Description for {context.FullyQualifiedTestClassName} single MediaItem", - Duration = 0, - Id = 1, - IsDeleted = false, - Location = "Memory", - PrivacyStatus = (int)PrivacyStatus.None, - Sequence = 1, - Title = $"Title for {context.FullyQualifiedTestClassName} single MediaItem", - }; - } - } -} diff --git a/src/Maple.Test/TestUtils/PlaylistModelContextExtensions.cs b/src/Maple.Test/TestUtils/PlaylistModelContextExtensions.cs deleted file mode 100644 index 46e040b..0000000 --- a/src/Maple.Test/TestUtils/PlaylistModelContextExtensions.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Collections.Generic; -using Maple.Domain; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Maple.Test -{ - public static class PlaylistModelContextExtensions - { - public static PlaylistModel CreateModelPlaylist(this TestContext context) - { - var playlist = new PlaylistModel() - { - CreatedBy = context.FullyQualifiedTestClassName, - CreatedOn = DateTime.UtcNow, - Description = $"Description for {context.FullyQualifiedTestClassName} Playlist", - Id = 1, - IsDeleted = false, - IsShuffeling = false, - Location = "Memory", - MediaItems = new List(), - PrivacyStatus = (int)PrivacyStatus.None, - RepeatMode = (int)RepeatMode.None, - Sequence = 1, - Title = $"Title for {context.FullyQualifiedTestClassName} Playlist", - UpdatedBy = context.FullyQualifiedTestClassName, - UpdatedOn = DateTime.UtcNow, - }; - - return PopulatePlaylist(context, playlist); - } - - public static PlaylistModel PopulatePlaylist(this TestContext context, PlaylistModel playlist) - { - for (var i = 0; i < 4; i++) - { - playlist.MediaItems.Add(new MediaItemModel() - { - CreatedBy = context.FullyQualifiedTestClassName, - CreatedOn = DateTime.UtcNow, - UpdatedOn = DateTime.UtcNow, - UpdatedBy = context.FullyQualifiedTestClassName, - Description = $"Description for {context.FullyQualifiedTestClassName} MediaItem number {i}", - Duration = 0, - Id = 1, - IsDeleted = false, - Location = "Memory", - Playlist = playlist, - PlaylistId = playlist.Id, - PrivacyStatus = (int)PrivacyStatus.None, - Sequence = 0, - Title = $"Title for {context.FullyQualifiedTestClassName} MediaItem number {i}", - }); - } - - return playlist; - } - } -} diff --git a/src/Maple.Test/TypeExtension/CheckingATypeForDefaultConstructorTests.cs b/src/Maple.Test/TypeExtension/CheckingATypeForDefaultConstructorTests.cs deleted file mode 100644 index 64b63cc..0000000 --- a/src/Maple.Test/TypeExtension/CheckingATypeForDefaultConstructorTests.cs +++ /dev/null @@ -1,137 +0,0 @@ -using System; -using Maple.Core; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public sealed class CheckingATypeForDefaultConstructorTests - { - [TestMethod] - public void RunHasDefaultConstructorExtensionsTests() - { - typeof(SampleClassA).HasDefaultConstructor().ShouldBeFalse(); - typeof(SampleClassAA).HasDefaultConstructor().ShouldBeTrue(); - typeof(SampleClassB).HasDefaultConstructor().ShouldBeTrue(); - typeof(SampleClassC).HasDefaultConstructor().ShouldBeTrue(); - typeof(SampleClassD).HasDefaultConstructor().ShouldBeTrue(); - typeof(SampleClassE).HasDefaultConstructor().ShouldBeTrue(); - - typeof(SampleClassPA).HasDefaultConstructor().ShouldBeFalse(); - typeof(SampleClassPAA).HasDefaultConstructor().ShouldBeTrue(); - typeof(SampleClassPB).HasDefaultConstructor().ShouldBeTrue(); - typeof(SampleClassPC).HasDefaultConstructor().ShouldBeTrue(); - typeof(SampleClassPD).HasDefaultConstructor().ShouldBeTrue(); - typeof(SampleClassPE).HasDefaultConstructor().ShouldBeTrue(); - - typeof(StaticClass).HasDefaultConstructor().ShouldBeFalse(); - - typeof(SampleStructA).HasDefaultConstructor().ShouldBeTrue(); - typeof(SampleStructB).HasDefaultConstructor().ShouldBeTrue(); - - typeof(DateTime).HasDefaultConstructor().ShouldBeTrue(); - typeof(TimeSpan).HasDefaultConstructor().ShouldBeTrue(); - - typeof(string).HasDefaultConstructor().ShouldBeFalse(); - } - - private class SampleClassA - { - private SampleClassA() - { } - } - - private class SampleClassAA - { - static SampleClassAA() - { } - } - - private class SampleClassB - { } - - private class SampleClassC - { - public SampleClassC() - { } - } - - private class SampleClassD - { - public SampleClassD() - { } - - public SampleClassD(int id) - { } - } - - private class SampleClassE - { - static SampleClassE() - { } - - public SampleClassE() - { } - - public SampleClassE(int id) - { } - } - - internal class SampleClassPA - { - private SampleClassPA() - { } - } - - internal class SampleClassPAA - { - static SampleClassPAA() - { } - } - - internal class SampleClassPB - { } - - internal class SampleClassPC - { - public SampleClassPC() - { } - } - - internal class SampleClassPD - { - public SampleClassPD() - { } - - public SampleClassPD(int id) - { } - } - - internal class SampleClassPE - { - static SampleClassPE() - { } - - public SampleClassPE() - { } - - public SampleClassPE(int id) - { } - } - - private static class StaticClass - { } - - private struct SampleStructA - { } - - private struct SampleStructB - { - public SampleStructB(int age) - { - - } - } - } -} \ No newline at end of file diff --git a/src/Maple.Test/TypeExtension/CheckingATypeImplementsTests.cs b/src/Maple.Test/TypeExtension/CheckingATypeImplementsTests.cs deleted file mode 100644 index bce3339..0000000 --- a/src/Maple.Test/TypeExtension/CheckingATypeImplementsTests.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Maple.Core; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public sealed class CheckingATypeImplementsTests - { - [TestMethod] - public void RunImplementsExtensionsTests() - { - typeof(MyClassBase).Implements().ShouldBeTrue(); - typeof(MyClassBase).Implements().ShouldBeFalse(); - typeof(MyClassBase).Implements().ShouldBeFalse(); - - typeof(MyClassA).Implements().ShouldBeTrue(); - typeof(MyClassA).Implements().ShouldBeTrue(); - typeof(MyClassB).Implements().ShouldBeTrue(); - typeof(MyClassA).Implements().ShouldBeFalse(); - - typeof(IMyInterface).Implements().ShouldBeTrue(); - typeof(MyClassC).Implements().ShouldBeTrue(); - typeof(IMyInterface).Implements().ShouldBeFalse(); - typeof(MyClassD).Implements().ShouldBeTrue(); - typeof(MyClassA).Implements().ShouldBeFalse(); - - typeof(IMyInterface).Implements().ShouldBeFalse(); - typeof(MyClassD).Implements().ShouldBeTrue(); - typeof(MyClassD).Implements().ShouldBeFalse(); - - typeof(MyStructA).Implements().ShouldBeTrue(); - typeof(MyStructB).Implements().ShouldBeTrue(); - typeof(MyStructB).Implements().ShouldBeFalse(); - typeof(MyStructA).Implements().ShouldBeFalse(); - } - - private class MyClassBase { } - private class MyClassA : MyClassBase { } - private class MyClassB : MyClassA { } - private interface IMyInterface { } - private class MyClassC : IMyInterface { } - private class MyClassD : MyClassA, IMyInterface { } - private struct MyStructA { } - private struct MyStructB : IMyInterface { } - } -} \ No newline at end of file diff --git a/src/Maple.Test/TypeExtension/CheckingATypeIsSimpleTests.cs b/src/Maple.Test/TypeExtension/CheckingATypeIsSimpleTests.cs deleted file mode 100644 index d3b099b..0000000 --- a/src/Maple.Test/TypeExtension/CheckingATypeIsSimpleTests.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using Maple.Core; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public sealed class CheckingATypeIsSimpleTests - { - [TestMethod] - public void RunIsSimpleTypeExtenionsTests() - { - typeof(byte[]).IsSimpleType().ShouldBeTrue(); - typeof(byte).IsSimpleType().ShouldBeTrue(); - typeof(sbyte).IsSimpleType().ShouldBeTrue(); - typeof(short).IsSimpleType().ShouldBeTrue(); - typeof(ushort).IsSimpleType().ShouldBeTrue(); - typeof(int).IsSimpleType().ShouldBeTrue(); - typeof(uint).IsSimpleType().ShouldBeTrue(); - typeof(long).IsSimpleType().ShouldBeTrue(); - typeof(ulong).IsSimpleType().ShouldBeTrue(); - typeof(float).IsSimpleType().ShouldBeTrue(); - typeof(double).IsSimpleType().ShouldBeTrue(); - typeof(decimal).IsSimpleType().ShouldBeTrue(); - typeof(bool).IsSimpleType().ShouldBeTrue(); - typeof(string).IsSimpleType().ShouldBeTrue(); - typeof(char).IsSimpleType().ShouldBeTrue(); - typeof(Guid).IsSimpleType().ShouldBeTrue(); - typeof(DateTime).IsSimpleType().ShouldBeTrue(); - typeof(DateTimeOffset).IsSimpleType().ShouldBeTrue(); - typeof(TimeSpan).IsSimpleType().ShouldBeTrue(); - - typeof(MyEnum).IsSimpleType().ShouldBeTrue(); - - typeof(MyClass).IsSimpleType().ShouldBeFalse(); - typeof(MyStruct).IsSimpleType().ShouldBeFalse(); - typeof(IMyInterface).IsSimpleType().ShouldBeFalse(); - } - - private enum MyEnum - { - None = 0 - } - - private class MyClass - { } - - private struct MyStruct - { } - - private interface IMyInterface - { } - } -} \ No newline at end of file diff --git a/src/Maple.Test/TypeExtension/CheckingIfTypeIsASequenceTests.cs b/src/Maple.Test/TypeExtension/CheckingIfTypeIsASequenceTests.cs deleted file mode 100644 index f091003..0000000 --- a/src/Maple.Test/TypeExtension/CheckingIfTypeIsASequenceTests.cs +++ /dev/null @@ -1,375 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Collections.Specialized; -using Maple.Core; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public sealed class CheckingIfTypeIsASequenceTests - { - [TestMethod] - public void When_checking_type_of_null() - { - var e = Should.Throw(() => - { - Type nullType = null; - // ReSharper disable once ExpressionIsAlwaysNull - nullType.IsSequence(out var sequenceType); - }); - - e.ParamName.ShouldBe("type"); - } - - [TestMethod] - public void When_checking_type_of_string() - { - typeof(string).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.String); - } - - [TestMethod] - public void When_checking_a_non_sequence_type() - { - typeof(NonSequenceTypeOne).IsSequence(out var sequenceType) - .ShouldBeFalse(); - - sequenceType.ShouldBe(SequenceType.Invalid); - } - - [TestMethod] - public void When_checking_a_non_sequence_type_which_implements_an_interface() - { - typeof(NonSequenceTypeTwo).IsSequence(out var sequenceType) - .ShouldBeFalse(); - - sequenceType.ShouldBe(SequenceType.Invalid); - } - - [TestMethod] - public void When_checking_a_generic_sequence_type() - { - typeof(GenericSequenceType).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.GenericCustom); - } - - [TestMethod] - public void When_checking_a_non_generic_sequence_type() - { - typeof(NonGenericSequenceType).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.Custom); - } - - [TestMethod] - public void When_checking_an_array() - { - typeof(int[]).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.Array); - } - - [TestMethod] - public void When_checking_an_array_list() - { - typeof(ArrayList).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.ArrayList); - } - - [TestMethod] - public void When_checking_a_queue() - { - typeof(Queue).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.Queue); - } - - [TestMethod] - public void When_checking_a_stack() - { - typeof(Stack).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.Stack); - } - - [TestMethod] - public void When_checking_a_bit_array() - { - typeof(BitArray).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.BitArray); - } - - [TestMethod] - public void When_checking_a_list_dictionary() - { - typeof(ListDictionary).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.ListDictionary); - } - - [TestMethod] - public void When_checking_a_sorted_list() - { - typeof(SortedList).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.SortedList); - } - - [TestMethod] - public void When_checking_a_hash_table() - { - typeof(Hashtable).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.Hashtable); - } - - [TestMethod] - public void When_checking_an_interface_of_ilist() - { - typeof(IList).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.IList); - } - - [TestMethod] - public void When_checking_an_interface_of_icollection() - { - typeof(ICollection).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.ICollection); - } - - [TestMethod] - public void When_checking_an_interface_of_idictionary() - { - typeof(IDictionary).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.IDictionary); - } - - [TestMethod] - public void When_checking_an_interface_of_ienumerable() - { - typeof(IEnumerable).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.IEnumerable); - } - - [TestMethod] - public void When_checking_an_generic_list() - { - typeof(List).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.GenericList); - } - - [TestMethod] - public void When_checking_a_generic_hash_set() - { - typeof(HashSet).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.GenericHashSet); - } - - [TestMethod] - public void When_checking_a_generic_collection() - { - typeof(Collection).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.GenericCollection); - } - - [TestMethod] - public void When_checking_a_generic_linked_list() - { - typeof(LinkedList).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.GenericLinkedList); - } - - [TestMethod] - public void When_checking_a_generic_stack() - { - typeof(Stack).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.GenericStack); - } - - [TestMethod] - public void When_checking_a_generic_queue() - { - typeof(Queue).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.GenericQueue); - } - - [TestMethod] - public void When_checking_an_interface_of_generic_ilist() - { - typeof(IList).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.GenericIList); - } - - [TestMethod] - public void When_checking_an_interface_of_generic_icollection() - { - typeof(ICollection).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.GenericICollection); - } - - [TestMethod] - public void When_checking_an_interface_of_generic_ienumerable() - { - typeof(IEnumerable).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.GenericIEnumerable); - } - - [TestMethod] - public void When_checking_a_generic_dictionary() - { - typeof(Dictionary).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.GenericDictionary); - } - - [TestMethod] - public void When_checking_a_generic_sorted_dictionary() - { - typeof(SortedDictionary).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.GenericSortedDictionary); - } - - [TestMethod] - public void When_checking_a_generic_sorted_list() - { - typeof(SortedList).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.GenericSortedList); - } - - [TestMethod] - public void When_checking_an_interface_of_generic_idictionary() - { - typeof(IDictionary).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.GenericIDictionary); - } - - [TestMethod] - public void When_checking_an_interface_of_generic_icollection_of_key_value_pair() - { - typeof(ICollection>).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.GenericICollectionKeyValue); - } - - [TestMethod] - public void When_checking_an_interface_of_generic_ienumerable_of_key_value_pair() - { - typeof(IEnumerable>).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.GenericIEnumerableKeyValue); - } - - [TestMethod] - public void When_checking_a_generic_blocking_collection() - { - typeof(BlockingCollection).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.GenericBlockingCollection); - } - - [TestMethod] - public void When_checking_a_generic_concurrent_bag() - { - typeof(ConcurrentBag).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.GenericConcurrentBag); - } - - [TestMethod] - public void When_checking_a_generic_concurrent_dictionary() - { - typeof(ConcurrentDictionary).IsSequence(out var sequenceType) - .ShouldBeTrue(); - - sequenceType.ShouldBe(SequenceType.GenericConcurrentDictionary); - } - - private class NonSequenceTypeOne { } - - private class NonSequenceTypeTwo : ICloneable - { - public object Clone() - { - throw new NotImplementedException(); - } - } - - private class GenericSequenceType : IEnumerable - { - public IEnumerator GetEnumerator() - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } - - private class NonGenericSequenceType : IEnumerable - { - public IEnumerator GetEnumerator() - { - throw new NotImplementedException(); - } - } - } -} \ No newline at end of file diff --git a/src/Maple.Test/TypeExtension/CheckingTypeCodesTests.cs b/src/Maple.Test/TypeExtension/CheckingTypeCodesTests.cs deleted file mode 100644 index 5f63e68..0000000 --- a/src/Maple.Test/TypeExtension/CheckingTypeCodesTests.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Threading.Tasks; -using Maple.Core; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public sealed class CheckingTypeCodesTests - { - [TestMethod] - public void RunGetTypeCodeExtensionTests() - { - typeof(bool).GetTypeCode().ShouldBe(TypeCode.Boolean); - typeof(char).GetTypeCode().ShouldBe(TypeCode.Char); - typeof(sbyte).GetTypeCode().ShouldBe(TypeCode.SByte); - typeof(byte).GetTypeCode().ShouldBe(TypeCode.Byte); - typeof(short).GetTypeCode().ShouldBe(TypeCode.Int16); - typeof(ushort).GetTypeCode().ShouldBe(TypeCode.UInt16); - typeof(int).GetTypeCode().ShouldBe(TypeCode.Int32); - typeof(uint).GetTypeCode().ShouldBe(TypeCode.UInt32); - typeof(long).GetTypeCode().ShouldBe(TypeCode.Int64); - typeof(ulong).GetTypeCode().ShouldBe(TypeCode.UInt64); - typeof(float).GetTypeCode().ShouldBe(TypeCode.Single); - typeof(double).GetTypeCode().ShouldBe(TypeCode.Double); - typeof(decimal).GetTypeCode().ShouldBe(TypeCode.Decimal); - typeof(DateTime).GetTypeCode().ShouldBe(TypeCode.DateTime); - typeof(string).GetTypeCode().ShouldBe(TypeCode.String); - - typeof(TimeSpan).GetTypeCode().ShouldBe(TypeCode.Object); - typeof(Task).GetTypeCode().ShouldBe(TypeCode.Object); - } - } -} \ No newline at end of file diff --git a/src/Maple.Test/TypeExtension/CheckingTypeIsNumeric.cs b/src/Maple.Test/TypeExtension/CheckingTypeIsNumeric.cs deleted file mode 100644 index 1609322..0000000 --- a/src/Maple.Test/TypeExtension/CheckingTypeIsNumeric.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using Maple.Core; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public sealed class CheckingTypeIsNumeric - { - [TestMethod] - public void RunIsNumericExtenionsTests() - { - typeof(bool).IsNumeric().ShouldBeFalse(); - typeof(string).IsNumeric().ShouldBeFalse(); - typeof(DateTime).IsNumeric().ShouldBeFalse(); - typeof(TimeSpan).IsNumeric().ShouldBeFalse(); - - typeof(byte).IsNumeric().ShouldBeTrue(); - typeof(float).IsNumeric().ShouldBeTrue(); - typeof(decimal).IsNumeric().ShouldBeTrue(); - typeof(double).IsNumeric().ShouldBeTrue(); - typeof(short).IsNumeric().ShouldBeTrue(); - typeof(int).IsNumeric().ShouldBeTrue(); - typeof(long).IsNumeric().ShouldBeTrue(); - typeof(sbyte).IsNumeric().ShouldBeTrue(); - typeof(ushort).IsNumeric().ShouldBeTrue(); - typeof(uint).IsNumeric().ShouldBeTrue(); - typeof(ulong).IsNumeric().ShouldBeTrue(); - } - } -} \ No newline at end of file diff --git a/src/Maple.Test/TypeExtension/Context.cs b/src/Maple.Test/TypeExtension/Context.cs deleted file mode 100644 index 8de9a7a..0000000 --- a/src/Maple.Test/TypeExtension/Context.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using Maple.Core; - -namespace Maple.Test -{ - public class Context - { - protected IEnumerable PropertesWithAttribute; - - protected void When_getting_properties_with_specific_attribute_for_type(bool inherit) - where TA : Attribute - { - PropertesWithAttribute = typeof(T).GetPropertiesWithAttribute(inherit); - } - - protected class SampleParent - { - [My("_parentId")] - public int ParentId { get; set; } - - public string ParentName { get; set; } - - [My("_privateParentName")] - private string PrivateParentName { get; set; } - - [Obsolete("Just a test")] - public double ParentAge { get; set; } - } - - protected class SampleChild : SampleParent - { - [My("_childId")] - public int ChildId { get; set; } - - [My("_childAge")] - public double ChildAge { get; set; } - - public string ChildName { get; set; } - - [My("_privateChildName")] - private string PrivateChildName { get; set; } - - [Obsolete("Just another test")] - public decimal Salary { get; set; } - } - - [AttributeUsage(AttributeTargets.Property)] - protected sealed class MyAttribute : Attribute - { - public string Name { get; private set; } - - public MyAttribute(string name) - { - Ensure.NotNull(name, "name"); - Name = name; - } - } - } -} \ No newline at end of file diff --git a/src/Maple.Test/TypeExtension/GettingAllInstancePropertiesWithAttributes.cs b/src/Maple.Test/TypeExtension/GettingAllInstancePropertiesWithAttributes.cs deleted file mode 100644 index b1abd9c..0000000 --- a/src/Maple.Test/TypeExtension/GettingAllInstancePropertiesWithAttributes.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Linq; -using System.Reflection; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public sealed class GettingAllInstancePropertiesWithAttributes : Context - { - [TestInitialize] - public void TestInitialize() - { - When_getting_properties_with_specific_attribute_for_type(false); - } - - [TestMethod] - public void Then_property_infos_should_not_be_null_or_empty() - { - PropertesWithAttribute.ShouldNotBeNull(); - PropertesWithAttribute.ShouldNotBeEmpty(); - } - - [TestMethod] - public void Then_property_infos_should_have_correct_count() - { - PropertesWithAttribute.Count().ShouldBe(2); - } - - [TestMethod] - public void Then_correct_attributes_should_have_been_returned() - { - PropertesWithAttribute.Single(p => p.Name.Equals("ChildId")) - .GetCustomAttribute() - .Name.ShouldBe("_childId"); - - PropertesWithAttribute.Single(p => p.Name.Equals("ChildAge")) - .GetCustomAttribute() - .Name.ShouldBe("_childAge"); - } - } -} \ No newline at end of file diff --git a/src/Maple.Test/TypeExtension/GettingAllPropertiesWithAttributes.cs b/src/Maple.Test/TypeExtension/GettingAllPropertiesWithAttributes.cs deleted file mode 100644 index d0df47d..0000000 --- a/src/Maple.Test/TypeExtension/GettingAllPropertiesWithAttributes.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Linq; -using System.Reflection; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public sealed class GettingAllPropertiesWithAttributes : Context - { - [TestInitialize] - public void TestInitialize() - { - When_getting_properties_with_specific_attribute_for_type(true); - } - - [TestMethod] - public void Then_property_infos_should_not_be_null_or_empty() - { - PropertesWithAttribute.ShouldNotBeNull(); - PropertesWithAttribute.ShouldNotBeEmpty(); - } - - [TestMethod] - public void Then_property_infos_should_have_correct_count() - { - PropertesWithAttribute.Count().ShouldBe(3); - } - - [TestMethod] - public void Then_correct_attributes_should_have_been_returned() - { - PropertesWithAttribute.Single(p => p.Name.Equals("ParentId")) - .GetCustomAttribute() - .Name.ShouldBe("_parentId"); - - PropertesWithAttribute.Single(p => p.Name.Equals("ChildId")) - .GetCustomAttribute() - .Name.ShouldBe("_childId"); - - PropertesWithAttribute.Single(p => p.Name.Equals("ChildAge")) - .GetCustomAttribute() - .Name.ShouldBe("_childAge"); - } - } -} \ No newline at end of file diff --git a/src/Maple.Test/TypeExtension/GettingArgumentTypeOfGenericTypeTests.cs b/src/Maple.Test/TypeExtension/GettingArgumentTypeOfGenericTypeTests.cs deleted file mode 100644 index f822fbb..0000000 --- a/src/Maple.Test/TypeExtension/GettingArgumentTypeOfGenericTypeTests.cs +++ /dev/null @@ -1,174 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using Maple.Core; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public sealed class GettingArgumentTypeOfGenericTypeTests - { - [TestMethod] - public void When_checking_type_of_null() - { - var e = Should.Throw(() => - { - ((Type)null).TryGetGenericArguments(out var result); - }); - - e.ParamName.ShouldBe("type"); - } - - [TestMethod] - public void When_checking_type_of_non_generic_class() - { - typeof(NonGenericType) - .TryGetGenericArguments(out var result) - .ShouldBeFalse(); - - result.ShouldBeNull(); - } - - [TestMethod] - public void When_checking_type_of_generic_class_with_single_argument() - { - typeof(SingleGenericType) - .TryGetGenericArguments(out var result) - .ShouldBeTrue(); - - result.ShouldNotBeNull(); - result.Length.ShouldBe(1); - result[0].ShouldBe(typeof(string)); - } - - [TestMethod] - public void When_checking_type_of_generic_class_with_double_arguments() - { - typeof(DoubleGenericType) - .TryGetGenericArguments(out var result) - .ShouldBeTrue(); - - result.ShouldNotBeNull(); - result.Length.ShouldBe(2); - result[0].ShouldBe(typeof(int)); - result[1].ShouldBe(typeof(string)); - } - - [TestMethod] - public void When_checking_type_of_generic_class_with_multiple_arguments() - { - typeof(MultipleGenericType) - .TryGetGenericArguments(out var result) - .ShouldBeTrue(); - - result.ShouldNotBeNull(); - result.Length.ShouldBe(5); - result[0].ShouldBe(typeof(int)); - result[1].ShouldBe(typeof(string)); - result[2].ShouldBe(typeof(DateTime)); - result[3].ShouldBe(typeof(string)); - result[4].ShouldBe(typeof(short)); - } - - [TestMethod] - public void When_checking_type_of_generic_array() - { - typeof(int[]).TryGetGenericArguments(out var result) - .ShouldBeTrue(); - - result.Length.ShouldBe(1); - result[0].ShouldBe(typeof(int)); - } - - [TestMethod] - public void When_checking_type_of_generic_list() - { - typeof(List).TryGetGenericArguments(out var result) - .ShouldBeTrue(); - - result.Length.ShouldBe(1); - result[0].ShouldBe(typeof(byte)); - } - - [TestMethod] - public void When_checking_type_of_generic_queue() - { - typeof(Queue).TryGetGenericArguments(out var result) - .ShouldBeTrue(); - - result.Length.ShouldBe(1); - result[0].ShouldBe(typeof(DateTime)); - } - - [TestMethod] - public void When_checking_type_of_generic_stack() - { - typeof(Stack).TryGetGenericArguments(out var result) - .ShouldBeTrue(); - - result.Length.ShouldBe(1); - result[0].ShouldBe(typeof(DateTime)); - } - - [TestMethod] - public void When_checking_type_of_generic_collection() - { - typeof(Collection).TryGetGenericArguments(out var result) - .ShouldBeTrue(); - - result.Length.ShouldBe(1); - result[0].ShouldBe(typeof(DateTime)); - } - - [TestMethod] - public void When_checking_type_of_generic_hash_set() - { - typeof(HashSet).TryGetGenericArguments(out var result) - .ShouldBeTrue(); - - result.Length.ShouldBe(1); - result[0].ShouldBe(typeof(DateTime)); - } - - [TestMethod] - public void When_checking_type_of_generic_linked_list() - { - typeof(LinkedList).TryGetGenericArguments(out var result) - .ShouldBeTrue(); - - result.Length.ShouldBe(1); - result[0].ShouldBe(typeof(DateTime)); - } - - [TestMethod] - public void When_checking_type_of_generic_dictionary() - { - typeof(Dictionary).TryGetGenericArguments(out var result) - .ShouldBeTrue(); - - result.Length.ShouldBe(2); - result[0].ShouldBe(typeof(DateTime)); - result[1].ShouldBe(typeof(TimeSpan)); - } - - [TestMethod] - public void When_checking_type_of_generic_collection_of_key_value() - { - typeof(ICollection>).TryGetGenericArguments(out var result) - .ShouldBeTrue(); - - result.Length.ShouldBe(1); - result[0].ShouldBe(typeof(KeyValuePair)); - } - - private class NonGenericType { } - - private class SingleGenericType { } - - private class DoubleGenericType { } - - private class MultipleGenericType { } - } -} \ No newline at end of file diff --git a/src/Maple.Test/TypeExtension/GettingParentPropertiesWithAttributes.cs b/src/Maple.Test/TypeExtension/GettingParentPropertiesWithAttributes.cs deleted file mode 100644 index e7686b6..0000000 --- a/src/Maple.Test/TypeExtension/GettingParentPropertiesWithAttributes.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Linq; -using System.Reflection; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public sealed class GettingParentPropertiesWithAttributes : Context - { - [TestMethod] - [DataRow(true)] - [DataRow(false)] - public void Then_property_infos_should_not_be_null_or_empty(bool inherit) - { - When_getting_properties_with_specific_attribute_for_type(inherit); - - PropertesWithAttribute.ShouldNotBeNull(); - PropertesWithAttribute.ShouldNotBeEmpty(); - } - - [TestMethod] - [DataRow(true)] - [DataRow(false)] - public void Then_property_infos_should_have_correct_count(bool inherit) - { - When_getting_properties_with_specific_attribute_for_type(inherit); - - PropertesWithAttribute.Count().ShouldBe(1); - } - - [TestMethod] - [DataRow(true)] - [DataRow(false)] - public void Then_correct_attributes_should_have_been_returned(bool inherit) - { - When_getting_properties_with_specific_attribute_for_type(inherit); - - PropertesWithAttribute.Single(p => p.Name.Equals("ParentId")) - .GetCustomAttribute() - .Name.ShouldBe("_parentId"); - } - } -} \ No newline at end of file diff --git a/src/Maple.Test/TypeExtension/GettingPropertiesTests.cs b/src/Maple.Test/TypeExtension/GettingPropertiesTests.cs deleted file mode 100644 index cb1d448..0000000 --- a/src/Maple.Test/TypeExtension/GettingPropertiesTests.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Maple.Core; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Shouldly; - -namespace Maple.Test -{ - [TestClass] - public sealed class GettingPropertiesTests : Context - { - [TestMethod] - public void When_getting_valid_property_with_given_name() - { - typeof(SampleChild).TryGetInstanceProperty("ChildId", out var childIdProp).ShouldBeTrue(); - childIdProp.ShouldNotBeNull(); - childIdProp.PropertyType.ShouldBe(typeof(int)); - - typeof(SampleChild).TryGetInstanceProperty("PrivateChildName", out var privateChildNameProp).ShouldBeTrue(); - privateChildNameProp.ShouldNotBeNull(); - privateChildNameProp.PropertyType.ShouldBe(typeof(string)); - } - - [TestMethod] - public void When_getting_invalid_property_with_given_name() - { - typeof(SampleChild).TryGetInstanceProperty("foo", out var someProperty).ShouldBeFalse(); - someProperty.ShouldBeNull(); - } - - [TestMethod] - public void When_getting_all_public_properties() - { - var allProps = typeof(SampleChild).GetInstanceProperties(); - allProps.ShouldNotBeNull(); - allProps.ShouldNotBeEmpty(); - allProps.Length.ShouldBe(8); - - var declaredProps = typeof(SampleChild).GetInstanceProperties(false); - declaredProps.ShouldNotBeNull(); - declaredProps.ShouldNotBeEmpty(); - declaredProps.Length.ShouldBe(5); - } - } -} \ No newline at end of file diff --git a/src/Maple.Test/ViewModels/Playlists/PlaylistTests.cs b/src/Maple.Test/ViewModels/Playlists/PlaylistTests.cs deleted file mode 100644 index cd433c5..0000000 --- a/src/Maple.Test/ViewModels/Playlists/PlaylistTests.cs +++ /dev/null @@ -1,608 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using DryIoc; -using FluentValidation; -using FluentValidation.Results; -using Maple.Core; -using Maple.Domain; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using NSubstitute; - -namespace Maple.Test.ViewModels -{ - [TestClass, TestCategory("PlaylistTests")] - public class PlaylistTests - { - private static TestContext _context; - private static ValidationResult _defaultValidationResult; - - [ClassInitialize] - public static void ClassInitialize(TestContext context) - { - _context = context; - - _defaultValidationResult = new ValidationResult(Enumerable.Empty()); - } - - [TestMethod] - public async Task Playlist_ShouldRunConstructorWithoutErrors() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var model = _context.CreateModelPlaylist(); - var playlist = container.CreatePlaylist(model); - - Assert.AreEqual(_context.FullyQualifiedTestClassName, playlist.CreatedBy); - Assert.AreEqual(_context.FullyQualifiedTestClassName, playlist.UpdatedBy); - Assert.AreEqual(4, playlist.Count); - Assert.AreEqual($"Description for {_context.FullyQualifiedTestClassName} Playlist", playlist.Description); - Assert.AreEqual(false, playlist.HasErrors); - Assert.AreEqual(1, playlist.Id); - Assert.AreEqual(false, playlist.IsBusy); - Assert.AreEqual(false, playlist.IsChanged); - Assert.AreEqual(false, playlist.IsDeleted); - Assert.AreEqual(false, playlist.IsNew); - Assert.AreEqual(false, playlist.IsSelected); - Assert.AreEqual(false, playlist.IsShuffeling); - Assert.AreEqual(4, playlist.Items.Count); - Assert.AreEqual(model, playlist.Model); - Assert.AreEqual(PrivacyStatus.None, playlist.PrivacyStatus); - Assert.AreEqual(RepeatMode.None, playlist.RepeatMode); - Assert.AreEqual(playlist[0], playlist.SelectedItem); - Assert.AreEqual(1, playlist.Sequence); - Assert.AreEqual($"Title for {_context.FullyQualifiedTestClassName} Playlist", playlist.Title); - - Assert.IsNotNull(playlist.View); - Assert.IsNotNull(playlist.ClearCommand); - Assert.IsNotNull(playlist.LoadFromFileCommand); - Assert.IsNotNull(playlist.LoadFromFolderCommand); - Assert.IsNotNull(playlist.LoadFromUrlCommand); - Assert.IsNotNull(playlist.RemoveCommand); - Assert.IsNotNull(playlist.RemoveRangeCommand); - } - - [TestMethod] - public async Task Playlist_ShouldThrowForEmptyModel() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - Assert.ThrowsException(() => container.CreatePlaylist(default(PlaylistModel))); - } - - [TestMethod] - public async Task Playlist_ShouldThrowForEmptyContainer() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - Assert.ThrowsException(() => new Playlist(null, container.Resolve>(), container.Resolve(), container.Resolve(), _context.CreateModelPlaylist())); - } - - [TestMethod] - public async Task Playlist_ShouldThrowForEmptyValidator() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - Assert.ThrowsException(() => new Playlist(container.Resolve(), null, container.Resolve(), container.Resolve(), _context.CreateModelPlaylist())); - } - - [TestMethod] - public async Task Playlist_ShouldThrowForEmptyViewModel() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - Assert.ThrowsException(() => new Playlist(container.Resolve(), container.Resolve>(), null, container.Resolve(), _context.CreateModelPlaylist())); - } - - [TestMethod] - public async Task Playlist_ShouldThrowForEmptyMediaItemMapper() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - Assert.ThrowsException(() => new Playlist(container.Resolve(), container.Resolve>(), container.Resolve(), null, _context.CreateModelPlaylist())); - } - - [TestMethod] - public async Task Playlist_ShouldRunClear() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - - Assert.AreEqual(4, playlist.Count); - - playlist.Clear(); - - Assert.AreEqual(0, playlist.Count); - } - - [TestMethod] - public async Task Playlist_ShouldAdd() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var mediaItem = container.CreateMediaItem(_context.CreateModelMediaItem()); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - - Assert.AreEqual(4, playlist.Count); - - playlist.Add(mediaItem); - - Assert.AreEqual(5, playlist.Count); - } - - [TestMethod] - public async Task Playlist_ShouldThrowAddForNull() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - - Assert.ThrowsException(() => playlist.Add(null)); - } - - [TestMethod] - public async Task Playlist_ShouldAddRange() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var mediaItems = new[] - { - container.CreateMediaItem(_context.CreateModelMediaItem()), - container.CreateMediaItem(_context.CreateModelMediaItem()), - container.CreateMediaItem(_context.CreateModelMediaItem()), - }; - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - - Assert.AreEqual(4, playlist.Count); - - playlist.AddRange(mediaItems); - - Assert.AreEqual(7, playlist.Count); - } - - [TestMethod] - public async Task Playlist_ShouldHandleAddRangeForEmptyCollection() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var mediaItems = new List(); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - - Assert.AreEqual(4, playlist.Count); - - playlist.AddRange(mediaItems); - - Assert.AreEqual(4, playlist.Count); - } - - [TestMethod] - public async Task Playlist_ShouldThrowAddRangeForNull() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - - Assert.AreEqual(4, playlist.Count); - - Assert.ThrowsException(() => playlist.AddRange(null)); - } - - [TestMethod] - public async Task Playlist_ShouldHandleAddRangeForDuplicateEntries() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var mediaItem = container.CreateMediaItem(_context.CreateModelMediaItem()); - var mediaItems = new[] - { - mediaItem, - mediaItem, - mediaItem, - }; - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - - Assert.AreEqual(4, playlist.Count); - - playlist.AddRange(mediaItems); - - Assert.AreEqual(7, playlist.Count); - } - - [TestMethod] - public async Task Playlist_ShouldRemove() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - - Assert.AreEqual(4, playlist.Count); - - playlist.Remove(playlist[0]); - - Assert.AreEqual(3, playlist.Count); - } - - [TestMethod] - public async Task Playlist_ShouldThrowRemoveForNull() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - - Assert.ThrowsException(() => playlist.Remove(null)); - } - - [TestMethod] - public async Task Playlist_ShouldRemoveRange() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - var mediaItems = new[] - { - playlist[0], - playlist[1], - playlist[2], - }; - - Assert.AreEqual(4, playlist.Count); - - playlist.RemoveRange(mediaItems); - - Assert.AreEqual(1, playlist.Count); - } - - [TestMethod] - public async Task Playlist_ShouldThrowRemoveRangeForNull() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - - Assert.ThrowsException(() => playlist.RemoveRange(null)); - } - - [TestMethod] - public async Task Playlist_ShouldHandleRemoveRangeForSameItem() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - var mediaItems = new[] - { - playlist[0], - playlist[0], - playlist[0], - }; - - Assert.AreEqual(4, playlist.Count); - - playlist.RemoveRange(mediaItems); - - Assert.AreEqual(3, playlist.Count); - } - - [TestMethod] - public async Task Playlist_ShouldHandleRemoveRangeForUnknownItem() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - var mediaItems = new List() - { - container.CreateMediaItem(new MediaItemModel()), - }; - - Assert.AreEqual(4, playlist.Count); - - playlist.RemoveRange(mediaItems); - - Assert.AreEqual(4, playlist.Count); - } - - [TestMethod] - public async Task Playlist_ShouldHandleRemoveRangeForUnknownItems() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - var mediaItems = new[] - { - container.CreateMediaItem(new MediaItemModel()), - container.CreateMediaItem(new MediaItemModel()), - container.CreateMediaItem(new MediaItemModel()), - }; - - Assert.AreEqual(4, playlist.Count); - - playlist.RemoveRange(mediaItems); - - Assert.AreEqual(4, playlist.Count); - } - - [TestMethod] - public async Task Playlist_ShouldHandleRemoveRangeForEmptyCollection() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - var mediaItems = new List(); - - Assert.AreEqual(4, playlist.Count); - - playlist.RemoveRange(mediaItems); - - Assert.AreEqual(4, playlist.Count); - } - - [TestMethod] - public async Task Playlist_ShouldRunNext() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - playlist.RepeatMode = RepeatMode.None; - var mediaItem = playlist.Next(); - - Assert.IsNotNull(mediaItem); - Assert.AreEqual(playlist[1], mediaItem); - Assert.AreNotEqual(playlist.SelectedItem, mediaItem); - } - - [TestMethod] - public async Task Playlist_ShouldRunNextWithRepeatModeNone() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - playlist.RepeatMode = RepeatMode.None; - playlist.SelectedItem = playlist[3]; - - var mediaItem = playlist.Next(); - - Assert.IsNull(mediaItem); - } - - [TestMethod] - public async Task Playlist_ShouldRunNextWithRepeatModeAll() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - playlist.RepeatMode = RepeatMode.All; - playlist.SelectedItem = playlist[3]; - - var mediaItem = playlist.Next(); - - Assert.IsNotNull(mediaItem); - Assert.AreEqual(playlist[0], mediaItem); - } - - [TestMethod] - public async Task Playlist_ShouldRunNextWithRepeatModeAllWhileShuffeling() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - playlist.RepeatMode = RepeatMode.All; - playlist.IsShuffeling = true; - playlist.SelectedItem = playlist[3]; - - var mediaItem = playlist.Next(); - - Assert.IsNotNull(mediaItem); - Assert.AreNotEqual(playlist.SelectedItem, mediaItem); - } - - [TestMethod] - public async Task Playlist_ShouldRunNextWithRepeatModeNoneWhileShuffeling() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - playlist.RepeatMode = RepeatMode.None; - playlist.IsShuffeling = true; - playlist.SelectedItem = playlist[3]; - - var mediaItem = playlist.Next(); - - Assert.IsNotNull(mediaItem); - Assert.AreNotEqual(playlist.SelectedItem, mediaItem); - } - - [TestMethod] - public async Task Playlist_ShouldRunNextWithRepeatModeSingleWhileShuffeling() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - playlist.RepeatMode = RepeatMode.Single; - playlist.IsShuffeling = true; - - var mediaItem = playlist.Next(); - - Assert.IsNotNull(mediaItem); - Assert.AreEqual(playlist[0], mediaItem); - Assert.AreEqual(playlist.SelectedItem, mediaItem); - } - - [TestMethod] - public async Task Playlist_ShouldRunNextWithRepeatModeSingle() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - playlist.RepeatMode = RepeatMode.Single; - - var mediaItem = playlist.Next(); - - Assert.IsNotNull(mediaItem); - Assert.AreEqual(playlist[0], mediaItem); - Assert.AreEqual(playlist.SelectedItem, mediaItem); - } - - [TestMethod] - public async Task Playlist_ShouldRunPrevious() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - var messenger = container.Resolve(); - - messenger.Publish(new PlayingMediaItemMessage(this, playlist[0], playlist.Id)); - messenger.Publish(new PlayingMediaItemMessage(this, playlist[1], playlist.Id)); - messenger.Publish(new PlayingMediaItemMessage(this, playlist[2], playlist.Id)); - - var previous = playlist.Previous(); - Assert.AreEqual(playlist[2], previous); - Assert.AreEqual(true, previous.IsSelected); - Assert.AreEqual(1, playlist.Items.Where(p => p.IsSelected).Count()); - - previous = playlist.Previous(); - Assert.AreEqual(playlist[1], previous); - Assert.AreEqual(true, previous.IsSelected); - Assert.AreEqual(1, playlist.Items.Where(p => p.IsSelected).Count()); - - previous = playlist.Previous(); - Assert.AreEqual(playlist[0], previous); - Assert.AreEqual(true, previous.IsSelected); - Assert.AreEqual(1, playlist.Items.Where(p => p.IsSelected).Count()); - - previous = playlist.Previous(); - Assert.AreEqual(null, previous); - Assert.AreEqual(0, playlist.Items.Where(p => p.IsSelected).Count()); - - previous = playlist.Previous(); - Assert.AreEqual(null, previous); - Assert.AreEqual(0, playlist.Items.Where(p => p.IsSelected).Count()); - } - - [TestMethod] - public async Task Playlist_ShouldRaiseSelectionChanging() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var messenger = Substitute.For(); - container.UseInstance(typeof(IMessenger), messenger, IfAlreadyRegistered: IfAlreadyRegistered.Replace); - - Assert.AreEqual(messenger, container.Resolve()); - - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - - messenger.ClearReceivedCalls(); - playlist.SelectedItem = playlist[1]; - - messenger.Received(1).Publish(NSubstitute.Arg.Any>()); - } - - [TestMethod] - public async Task Playlist_ShouldRaiseSelectionChanged() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var messenger = Substitute.For(); - container.UseInstance(typeof(IMessenger), messenger, IfAlreadyRegistered: IfAlreadyRegistered.Replace); - - Assert.AreEqual(messenger, container.Resolve()); - - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - - messenger.ClearReceivedCalls(); - playlist.SelectedItem = playlist[1]; - - messenger.Received(1).Publish(NSubstitute.Arg.Any>()); - } - - [TestMethod] - public async Task Playlist_ShouldSynchronizeItemsWithModelWhenRemovingSelectedItem() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var model = _context.CreateModelPlaylist(); - var playlist = container.CreatePlaylist(model); - var selectedModel = playlist.SelectedItem.Model; - var next = playlist.Next(); - - Assert.AreEqual(model.MediaItems.Count, playlist.Count); - - playlist.Remove(playlist.SelectedItem); - - Assert.AreEqual(3, playlist.Count); - Assert.AreEqual(true, selectedModel.IsDeleted); - Assert.AreEqual(next, playlist.SelectedItem); - } - - [TestMethod] - public async Task Playlist_ShouldSynchronizeItemsWithModelWhenRemoving() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var model = _context.CreateModelPlaylist(); - var playlist = container.CreatePlaylist(model); - var mediaItem1 = playlist[1]; - var mediaItem2 = playlist[2]; - var mediaItem3 = playlist[3]; - - Assert.AreEqual(model.MediaItems.Count, playlist.Count); - - playlist.Remove(mediaItem1); - - Assert.AreEqual(3, playlist.Count); - Assert.AreEqual(true, mediaItem1.IsDeleted); - - playlist.RemoveRange(new[] { mediaItem2, mediaItem3 }); - - Assert.AreEqual(1, playlist.Count); - Assert.AreEqual(true, mediaItem2.IsDeleted); - Assert.AreEqual(true, mediaItem3.IsDeleted); - } - - [TestMethod] - public async Task Playlist_ShouldAddItemsFromFileDialog() - { - var tokenSource = new CancellationTokenSource(1000); - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var mediaItems = new[] -{ - container.CreateMediaItem(new MediaItemModel()), - container.CreateMediaItem(new MediaItemModel()), - container.CreateMediaItem(new MediaItemModel()), - }; - var dialogViewModel = Substitute.For(); - dialogViewModel.ShowMediaItemSelectionDialog(NSubstitute.Arg.Any(), NSubstitute.Arg.Any()).Returns((true, mediaItems)); - container.UseInstance(typeof(IDialogViewModel), dialogViewModel, IfAlreadyRegistered: IfAlreadyRegistered.Replace); - - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - - foreach (var item in mediaItems) - Assert.AreEqual(false, playlist.Items.Contains(item)); - - await playlist.LoadFromFileCommand.ExecuteAsync(tokenSource.Token).ConfigureAwait(false); - - foreach (var item in mediaItems) - Assert.AreEqual(true, playlist.Items.Contains(item)); - } - - [TestMethod] - public async Task Playlist_ShouldAddItemsFromFolderDialog() - { - var tokenSource = new CancellationTokenSource(1000); - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var mediaItems = new[] -{ - container.CreateMediaItem(new MediaItemModel()), - container.CreateMediaItem(new MediaItemModel()), - container.CreateMediaItem(new MediaItemModel()), - }; - var dialogViewModel = Substitute.For(); - dialogViewModel.ShowMediaItemFolderSelectionDialog(NSubstitute.Arg.Any(), NSubstitute.Arg.Any()).Returns((true, mediaItems)); - container.UseInstance(typeof(IDialogViewModel), dialogViewModel, IfAlreadyRegistered: IfAlreadyRegistered.Replace); - - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - - foreach (var item in mediaItems) - Assert.AreEqual(false, playlist.Items.Contains(item)); - - await playlist.LoadFromFolderCommand.ExecuteAsync(tokenSource.Token).ConfigureAwait(false); - - foreach (var item in mediaItems) - Assert.AreEqual(true, playlist.Items.Contains(item)); - } - - [TestMethod] - public async Task Playlist_ShouldAddItemsFromUrlDialog() - { - var tokenSource = new CancellationTokenSource(1000); - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var mediaItems = new[] -{ - container.CreateMediaItem(new MediaItemModel()), - container.CreateMediaItem(new MediaItemModel()), - container.CreateMediaItem(new MediaItemModel()), - }; - var dialogViewModel = Substitute.For(); - dialogViewModel.ShowUrlParseDialog(NSubstitute.Arg.Any()).Returns((mediaItems)); - container.UseInstance(typeof(IDialogViewModel), dialogViewModel, IfAlreadyRegistered: IfAlreadyRegistered.Replace); - - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - - foreach (var item in mediaItems) - Assert.AreEqual(false, playlist.Items.Contains(item)); - - await playlist.LoadFromUrlCommand.ExecuteAsync(tokenSource.Token).ConfigureAwait(false); - - foreach (var item in mediaItems) - Assert.AreEqual(true, playlist.Items.Contains(item)); - } - } -} diff --git a/src/Maple.Test/ViewModels/Playlists/PlaylistsTests.cs b/src/Maple.Test/ViewModels/Playlists/PlaylistsTests.cs deleted file mode 100644 index f887c96..0000000 --- a/src/Maple.Test/ViewModels/Playlists/PlaylistsTests.cs +++ /dev/null @@ -1,130 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using DryIoc; -using Maple.Domain; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using NSubstitute; - -namespace Maple.Test.ViewModels -{ - [TestClass, TestCategory("PlaylistsTests")] - public class PlaylistsTests - { - private static TestContext _context; - - [ClassInitialize] - public static void ClassInitialize(TestContext context) - { - _context = context; - } - - [TestMethod] - public async Task Playlists_ShouldRunConstructorWithErrors() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - - var playlists = container.CreatePlaylists(); - - Assert.AreEqual(false, playlists.IsBusy); - Assert.AreEqual(false, playlists.IsLoaded); - Assert.AreEqual(0, playlists.Count); - Assert.AreEqual(null, playlists.SelectedItem); - - Assert.AreNotEqual(null, playlists.View); - Assert.AreNotEqual(null, playlists.Items); - - Assert.AreNotEqual(null, playlists.AddCommand); - Assert.AreNotEqual(null, playlists.ClearCommand); - Assert.AreNotEqual(null, playlists.LoadCommand); - Assert.AreNotEqual(null, playlists.RefreshCommand); - Assert.AreNotEqual(null, playlists.RemoveCommand); - Assert.AreNotEqual(null, playlists.RemoveRangeCommand); - Assert.AreNotEqual(null, playlists.SaveCommand); - } - - [TestMethod] - public async Task Playlists_ShouldAdd() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var sequenceProvider = ContainerContextExtensions.CreateSequenceService(); - sequenceProvider.Get(default(List)).ReturnsForAnyArgs(5); - container.UseInstance(sequenceProvider); - - var playlists = (Playlists)container.Resolve(); - - Assert.AreEqual(0, playlists.Count); - sequenceProvider.ClearReceivedCalls(); - - playlists.Add(); - - sequenceProvider.Received(1).Get(NSubstitute.Arg.Any>()); - - Assert.AreEqual(1, playlists.Count); - Assert.AreEqual(5, playlists.Items.First().Sequence); - } - - [TestMethod] - public async Task Playlists_ShouldAddWithExplicitValue() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var sequenceProvider = ContainerContextExtensions.CreateSequenceService(); - sequenceProvider.Get(default(List)).ReturnsForAnyArgs(5); - container.UseInstance(sequenceProvider); - - var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); - var playlists = (Playlists)container.Resolve(); - - Assert.AreEqual(0, playlists.Count); - sequenceProvider.ClearReceivedCalls(); - - playlists.Add(playlist); - - sequenceProvider.Received(1).Get(NSubstitute.Arg.Any>()); - - Assert.AreEqual(1, playlists.Count); - Assert.AreEqual(playlist, playlists.Items.First()); - Assert.AreEqual(5, playlist.Sequence); - } - - [TestMethod] - public async Task Playlists_ShouldSave() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var repository = ContainerContextExtensions.CreateRepository(); - - container.UseInstance(repository); - - var playlists = container.Resolve(); - repository.ClearReceivedCalls(); - - playlists.Save(); - - repository.Received(1).Save(NSubstitute.Arg.Any()); - repository.Received(1).Dispose(); - } - - [TestMethod] - public async Task Playlists_ShouldLoad() - { - var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var dummyPlaylists = new List - { - container.CreatePlaylist(_context.CreateModelPlaylist()), - }; - var repository = ContainerContextExtensions.CreateRepository(); - repository.GetPlaylistsAsync().ReturnsForAnyArgs(dummyPlaylists); - container.UseInstance(repository); - - var playlists = (Playlists)container.Resolve(); - repository.ClearReceivedCalls(); - - await playlists.LoadAsync().ConfigureAwait(false); - await repository.Received(1).GetPlaylistsAsync().ConfigureAwait(false); - repository.Received(1).Dispose(); - - Assert.AreEqual(dummyPlaylists[0], playlists.SelectedItem); - Assert.AreEqual(1, playlists.Count); - } - } -} diff --git a/src/Maple.Test/app.config b/src/Maple.Test/app.config deleted file mode 100644 index fedd661..0000000 --- a/src/Maple.Test/app.config +++ /dev/null @@ -1,15 +0,0 @@ - - - -
- - - - - - - - - - - diff --git a/src/Maple.Youtube/IYoutubeApi.cs b/src/Maple.Youtube/IYoutubeApi.cs deleted file mode 100644 index bb6e51d..0000000 --- a/src/Maple.Youtube/IYoutubeApi.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Google.Apis.YouTube.v3.Data; -using Maple.Domain; - -namespace Maple.Youtube -{ - public interface IYoutubeApi - { - Task CreatePlaylist(PlaylistModel playlist, bool publicPlaylist = true); - Task DeletePlaylist(PlaylistModel playlist); - Task DeletePlaylistItems(ICollection playlistItems); - Task> GetPlaylistItems(string playlistId); - Task> GetPlaylists(string playlistId); - Task> GetVideo(string videoId); - } -} \ No newline at end of file diff --git a/src/Maple.Youtube/IYoutubeService.cs b/src/Maple.Youtube/IYoutubeService.cs new file mode 100644 index 0000000..ea5f8a0 --- /dev/null +++ b/src/Maple.Youtube/IYoutubeService.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Maple.Youtube +{ + public interface IYoutubeService + { + IEnumerable GetMrls(string url); + Task> Parse(string data); + } +} diff --git a/src/Maple.Youtube/IYoutubeUrlParser.cs b/src/Maple.Youtube/IYoutubeUrlParser.cs deleted file mode 100644 index ff027c1..0000000 --- a/src/Maple.Youtube/IYoutubeUrlParser.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Threading.Tasks; - -namespace Maple.Youtube -{ - public interface IYoutubeUrlParser - { - Task Parse(string data, ParseResultType type); - } -} diff --git a/src/Maple.Youtube/Maple.Youtube.csproj b/src/Maple.Youtube/Maple.Youtube.csproj index 7343835..0cb3ada 100644 --- a/src/Maple.Youtube/Maple.Youtube.csproj +++ b/src/Maple.Youtube/Maple.Youtube.csproj @@ -1,86 +1,17 @@ - - - Debug - AnyCPU - {B5BE546F-8D9F-4FB9-B235-AF05FD553F9E} - Library - Properties - Maple.Youtube - Maple.Youtube - v4.7.1 - 512 - - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - AnyCPU - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - 1.31.1.1063 - - - - - - - - - - - - - - - - - - Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - Designer - - - - - {21fa5854-0692-42e2-924e-a38cf3c7ff71} - Maple.Core - - - {9d7d05a6-8271-4836-a7bb-5b2abeccbd81} - Maple.Domain - - - {A073FC92-90E3-4541-8B52-6F7293187871} - Maple.Localization - - - - - \ No newline at end of file + + + netstandard2.0 + false + Library + False + 8.0 + + + + + + + 1.45.0.1929 + + + diff --git a/src/Maple.Youtube/Models/YoutubePlaylist.cs b/src/Maple.Youtube/Models/YoutubePlaylist.cs new file mode 100644 index 0000000..7e169b2 --- /dev/null +++ b/src/Maple.Youtube/Models/YoutubePlaylist.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Maple.Youtube +{ + public sealed class YoutubePlaylist : YoutubeRessource + { + public ICollection Items { get; set; } + } +} diff --git a/src/Maple.Youtube/Models/YoutubeRessource.cs b/src/Maple.Youtube/Models/YoutubeRessource.cs new file mode 100644 index 0000000..fccab55 --- /dev/null +++ b/src/Maple.Youtube/Models/YoutubeRessource.cs @@ -0,0 +1,13 @@ +namespace Maple.Youtube +{ + public abstract class YoutubeRessource + { + public string Title { get; set; } + + public string Description { get; set; } + + public string Location { get; set; } + + public int PrivacyStatus { get; set; } + } +} diff --git a/src/Maple.Youtube/Models/YoutubeVideo.cs b/src/Maple.Youtube/Models/YoutubeVideo.cs new file mode 100644 index 0000000..e05413d --- /dev/null +++ b/src/Maple.Youtube/Models/YoutubeVideo.cs @@ -0,0 +1,7 @@ +namespace Maple.Youtube +{ + public sealed class YoutubeVideo : YoutubeRessource + { + public long Duration { get; set; } + } +} diff --git a/src/Maple.Youtube/Utility/ParseResultType.cs b/src/Maple.Youtube/Utility/ParseResultType.cs deleted file mode 100644 index 7227b88..0000000 --- a/src/Maple.Youtube/Utility/ParseResultType.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Maple.Youtube -{ - [Flags] - public enum ParseResultType - { - None = 0, - Playlists = 1 << 0, - MediaItems = 1 << 1, - } -} diff --git a/src/Maple.Youtube/Utility/UrlParseResult.cs b/src/Maple.Youtube/Utility/UrlParseResult.cs deleted file mode 100644 index 0e0b797..0000000 --- a/src/Maple.Youtube/Utility/UrlParseResult.cs +++ /dev/null @@ -1,137 +0,0 @@ -using System; -using System.Collections.Generic; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple.Youtube -{ - public class UrlParseResult - { - private readonly ILoggingService _log; - - public int Count => RefreshCount(); - public ParseResultType Type { get; private set; } - public ICollection MediaItems { get; private set; } - public ICollection Playlists { get; private set; } - - private UrlParseResult(ILoggingService log) - { - _log = log ?? throw new ArgumentNullException(nameof(log), $"{nameof(log)} {Resources.IsRequired}"); - - Playlists = new List(); - MediaItems = new List(); - } - - public UrlParseResult(ILoggingService log, ParseResultType type) - : this(log) - { - Type = type; - } - - public UrlParseResult(ILoggingService log, List items) - : this(log, ParseResultType.Playlists) - { - Playlists = items; - - Log(); - } - - public UrlParseResult(ILoggingService log, List items, ParseResultType type) - : this(log, type) - { - Playlists = items; - - Log(); - } - - public UrlParseResult(ILoggingService log, PlaylistModel item) - : this(log, ParseResultType.Playlists) - { - Playlists = new List() - { - item - }; - - Log(); - } - - public UrlParseResult(ILoggingService log, PlaylistModel item, ParseResultType type) - : this(log, type) - { - Playlists = new List() - { - item - }; - - Log(); - } - - public UrlParseResult(ILoggingService log, MediaItemModel item) - : this(log, ParseResultType.MediaItems) - { - MediaItems = new List() - { - item - }; - - Log(); - } - - public UrlParseResult(ILoggingService log, MediaItemModel item, ParseResultType type) - : this(log, type) - { - MediaItems = new List() - { - item - }; - - Log(); - } - - public UrlParseResult(ILoggingService log, List items) - : this(log, ParseResultType.MediaItems) - { - MediaItems = items; - - Log(); - } - - public UrlParseResult(ILoggingService log, List items, ParseResultType type) - : this(log, type) - { - MediaItems = items; - - Log(); - } - - private void Log() - { - if (Count != 1) - _log.Info($"API Call for {Type} returned {Count} Entries"); // TODO localization - else - _log.Info($"API Call for {Type} returned {Count} Entry"); // TODO localization - } - - private int RefreshCount() - { - switch (Type) - { - case ParseResultType.MediaItems: - return MediaItems.Count; - - case ParseResultType.Playlists: - return Playlists.Count; - - case ParseResultType.None: - if (MediaItems.Count > 0) - return MediaItems.Count; - if (Playlists.Count > 0) - return Playlists.Count; - return 0; - default: - _log.Warn("DataParsingServiceResult misses an Implementation of DataParsingServiceResultType"); // TODO localization - return 0; - } - } - } -} diff --git a/src/Maple.Youtube/YoutubeApi.cs b/src/Maple.Youtube/YoutubeApi.cs index 09b9b9b..5fd474a 100644 --- a/src/Maple.Youtube/YoutubeApi.cs +++ b/src/Maple.Youtube/YoutubeApi.cs @@ -1,6 +1,7 @@ -using System; +using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Web; @@ -10,41 +11,33 @@ using Google.Apis.Util.Store; using Google.Apis.YouTube.v3; using Google.Apis.YouTube.v3.Data; -using Maple.Domain; -using Maple.Localization.Properties; namespace Maple.Youtube { - public class YoutubeApi : IYoutubeApi + internal sealed class YoutubeApi { private const string _videoBaseUrl = @"https://www.youtube.com/watch?v="; private const string _playListBaseUrl = @"https://www.youtube.com/playlist?list="; private volatile YouTubeService _service; - private readonly ILoggingService _log; - private readonly object _syncRoot; - - public YoutubeApi(ILoggingService log) - { - _log = log ?? throw new ArgumentNullException(nameof(log), $"{nameof(log)} {Resources.IsRequired}"); - _syncRoot = new object(); - } private async Task GetService() { if (_service != null) return _service; - _log.Info(Resources.YoutubeLoad); + var credentials = await GetCredential().ConfigureAwait(false); + if (credentials is null) + { + return null; + } _service = new YouTubeService(new BaseClientService.Initializer() { - HttpClientInitializer = await GetCredential().ConfigureAwait(false), + HttpClientInitializer = credentials, ApplicationName = GetType().ToString() }); - _log.Info(Resources.YoutubeLoaded); - return _service; } @@ -52,24 +45,36 @@ private async Task GetCredential() { using (var stream = new FileStream(@"Resources\client_secret.json", FileMode.Open, FileAccess.Read, FileShare.Read)) { - var secretes = GoogleClientSecrets.Load(stream).Secrets; + var secretCollection = GoogleClientSecrets.Load(stream); + + if (secretCollection is null || secretCollection.Secrets is null) + { + return null; + } + + var clientSecrets = secretCollection.Secrets; var store = new FileDataStore(GetType().ToString()); var scopes = new[] -{ + { YouTubeService.Scope.YoutubeReadonly, YouTubeService.Scope.Youtube }; - return await GoogleWebAuthorizationBroker.AuthorizeAsync(secretes, scopes, "user", CancellationToken.None, store) + return await GoogleWebAuthorizationBroker.AuthorizeAsync(clientSecrets, scopes, "user", CancellationToken.None, store) .ConfigureAwait(false); } } - public async Task> GetPlaylists(string playlistId) + public async Task> GetPlaylists(string playlistId) { - var result = new List(); + var result = new List(); var youtubeService = await GetService().ConfigureAwait(false); + if (youtubeService is null) + { + return Enumerable.Empty().ToList(); + } + var request = youtubeService.Playlists.List("snippet,contentDetails"); request.Id = playlistId; @@ -80,11 +85,11 @@ public async Task> GetPlaylists(string playlistId) var nextPageToken = ""; while (nextPageToken != null) { - var playlist = new Domain.PlaylistModel + var playlist = new YoutubePlaylist { Title = item.Snippet.Title, Location = $"{_playListBaseUrl}{item.Id}", - PrivacyStatus = string.IsNullOrEmpty(item.Status?.PrivacyStatus) ? (int)PrivacyStatus.None : (int)PrivacyStatus.Restricted, + PrivacyStatus = string.IsNullOrEmpty(item.Status?.PrivacyStatus) ? 0 : 1, }; result.Add(playlist); @@ -96,10 +101,15 @@ public async Task> GetPlaylists(string playlistId) return result; } - public async Task CreatePlaylist(PlaylistModel playlist, bool publicPlaylist = true) + public async Task CreatePlaylist(YoutubePlaylist playlist, bool publicPlaylist = true) { var youtubeService = await GetService().ConfigureAwait(false); + if (youtubeService is null) + { + return; + } + var newPlaylist = new Playlist() { Snippet = new PlaylistSnippet() @@ -116,7 +126,7 @@ public async Task CreatePlaylist(PlaylistModel playlist, bool publicPlaylist = t .ExecuteAsync() .ConfigureAwait(false); - foreach (var item in playlist.MediaItems) + foreach (var item in playlist.Items) { // Add a video to the newly created playlist. var newVideo = new PlaylistItem() @@ -135,9 +145,14 @@ public async Task CreatePlaylist(PlaylistModel playlist, bool publicPlaylist = t } } - public async Task DeletePlaylist(PlaylistModel playlist) + public async Task DeletePlaylist(YoutubePlaylist playlist) { var youtubeService = await GetService().ConfigureAwait(false); + if (youtubeService is null) + { + return; + } + var id = GetPlaylistId(playlist); await youtubeService.Playlists.Delete(id) @@ -145,7 +160,7 @@ await youtubeService.Playlists.Delete(id) .ConfigureAwait(false); } - public static string GetVideoId(MediaItemModel item) + private static string GetVideoId(YoutubeVideo item) { var url = new Uri(item.Location); var result = HttpUtility.ParseQueryString(url.Query) @@ -154,7 +169,7 @@ public static string GetVideoId(MediaItemModel item) return result; } - public static string GetPlaylistId(PlaylistModel list) + private static string GetPlaylistId(YoutubePlaylist list) { var url = new Uri(list.Location); var result = HttpUtility.ParseQueryString(url.Query) @@ -165,8 +180,13 @@ public static string GetPlaylistId(PlaylistModel list) public async Task> GetPlaylistItems(string playlistId) { - var result = new List(); var youtubeService = await GetService().ConfigureAwait(false); + if (youtubeService is null) + { + return Enumerable.Empty().ToList(); + } + + var result = new List(); var request = youtubeService.PlaylistItems.List("snippet,contentDetails"); request.PlaylistId = playlistId; @@ -174,13 +194,11 @@ public async Task> GetPlaylistItems(string playlistId) var response = await request.ExecuteAsync() .ConfigureAwait(false); - foreach (var item in response.Items) { var nextPageToken = ""; while (nextPageToken != null) { - result.Add(item); nextPageToken = response.NextPageToken; @@ -192,6 +210,10 @@ public async Task> GetPlaylistItems(string playlistId) public async Task DeletePlaylistItems(ICollection playlistItems) { var youtubeService = await GetService().ConfigureAwait(false); + if (youtubeService is null) + { + return; + } foreach (var item in playlistItems) await youtubeService.PlaylistItems.Delete(item.Id) @@ -199,11 +221,9 @@ await youtubeService.PlaylistItems.Delete(item.Id) .ConfigureAwait(false); } - //TODO writing a async sync method for what i get from youtube vs that i generate myself as playlist - - public async Task> GetVideo(string videoId) + public async Task> GetVideo(string videoId) { - var result = new List(); + var result = new List(); var youtubeService = await GetService().ConfigureAwait(false); var request = youtubeService.Videos.List("snippet,contentDetails"); @@ -217,12 +237,12 @@ public async Task> GetVideo(string videoId) var nextPageToken = ""; while (nextPageToken != null) { - var video = new Domain.MediaItemModel + var video = new YoutubeVideo { Title = item.Snippet.Title, Location = $"{_videoBaseUrl}{videoId}", Duration = XmlConvert.ToTimeSpan(item.ContentDetails.Duration).Ticks, - PrivacyStatus = (item.ContentDetails.CountryRestriction?.Allowed ?? true) ? (int)PrivacyStatus.None : (int)PrivacyStatus.Restricted, + PrivacyStatus = (item.ContentDetails.CountryRestriction?.Allowed ?? true) ? 0 : 1, }; result.Add(video); diff --git a/src/Maple.Youtube/YoutubeService.cs b/src/Maple.Youtube/YoutubeService.cs new file mode 100644 index 0000000..153be3d --- /dev/null +++ b/src/Maple.Youtube/YoutubeService.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Web; + +namespace Maple.Youtube +{ + public class YoutubeService : IYoutubeService + { + private const string YoutubeUrlPattern = @"(?:http|https|)(?::\/\/|)(?:www.|m.|)(?:youtu\.be\/|youtube\.com(?:\/embed\/|\/v\/|\/watch\?v=|\|\/feeds\/api\/videos\/|\/user\S*[^\w\-\s]|\S*[^\w\-\s]))([\w\-]*)[a-z0-9;:@?&%=+\/\$_.-]*"; + private const string YoutubeDomain = "www.youtube.com"; + private const string YoutuDomain = "youtu.be"; + + private readonly YoutubeApi _api; + private readonly Regex _urlPattern; + + public YoutubeService() + { + _urlPattern = new Regex(YoutubeUrlPattern, RegexOptions.Compiled); + _api = new YoutubeApi(); + } + + public IEnumerable GetMrls(string url) + { + return Enumerable.Empty(); + } + + public async Task> Parse(string data) + { + if (string.IsNullOrEmpty(data)) + return Enumerable.Empty(); + + if (Uri.TryCreate(data.Trim(), UriKind.RelativeOrAbsolute, out var url)) + { + switch (url.DnsSafeHost) + { + case YoutuDomain: + url = new Uri(url.AbsoluteUri.Replace(@"youtu.be/", @"youtube.com/watch?v=")); + return await Parse(url).ConfigureAwait(false); + + case YoutubeDomain: + return await Parse(url).ConfigureAwait(false); + } + } + + return Enumerable.Empty(); + } + + private async Task> Parse(Uri url) + { + var result = new List(); + var match = _urlPattern.Match(url.AbsoluteUri); + + while (match.Success) + { + var collection = HttpUtility.ParseQueryString(url.Query); + var keys = collection.AllKeys; + + foreach (var key in keys) + { + var id = collection.Get(key).ToLowerInvariant(); + + switch (key) + { + case "v": + var videos = await _api.GetVideo(id).ConfigureAwait(false); + result.AddRange(videos); + + break; + + case "list": + var playlists = await _api.GetPlaylists(id).ConfigureAwait(false); + result.AddRange(playlists); + + break; + } + } + + match = match.NextMatch(); + } + + return result; + } + } +} diff --git a/src/Maple.Youtube/YoutubeUrlParser.cs b/src/Maple.Youtube/YoutubeUrlParser.cs deleted file mode 100644 index b98c95a..0000000 --- a/src/Maple.Youtube/YoutubeUrlParser.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System; -using System.Collections.Specialized; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using System.Web; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple.Youtube -{ - public class YoutubeUrlParser : IYoutubeUrlParser - { - private const string YoutubeUrlPattern = @"(?:http|https|)(?::\/\/|)(?:www.|m.|)(?:youtu\.be\/|youtube\.com(?:\/embed\/|\/v\/|\/watch\?v=|\|\/feeds\/api\/videos\/|\/user\S*[^\w\-\s]|\S*[^\w\-\s]))([\w\-]*)[a-z0-9;:@?&%=+\/\$_.-]*"; - private const string YoutubeDomain = "www.youtube.com"; - private const string YoutuDomain = "youtu.be"; - - private readonly ILoggingService _log; - private readonly IYoutubeApi _api; - private readonly Regex _urlPattern; - - public YoutubeUrlParser(ILoggingService log) - { - _log = log ?? throw new ArgumentNullException(nameof(log), $"{nameof(log)} {Resources.IsRequired}"); - - _urlPattern = new Regex(YoutubeUrlPattern, RegexOptions.Compiled); - _api = new YoutubeApi(_log); - } - - public async Task Parse(string data, ParseResultType type) - { - var failure = new UrlParseResult(_log, ParseResultType.None); - - if (type == ParseResultType.None) - return failure; - - if (string.IsNullOrEmpty(data)) - return failure; - - if (Uri.TryCreate(data.Trim(), UriKind.RelativeOrAbsolute, out var url)) - { - try - { - switch (url.DnsSafeHost) - { - case YoutuDomain: - url = new Uri(url.AbsoluteUri.Replace(@"youtu.be/", @"youtube.com/watch?v=")); - return await Parse(url, type).ConfigureAwait(false); - - case YoutubeDomain: - return await Parse(url, type).ConfigureAwait(false); - } - } - catch (Exception ex) - { - _log.Error(this, ex); - } - } - - return failure; - } - - private async Task Parse(Uri url, ParseResultType type) - { - var result = new UrlParseResult(_log, type); - var match = _urlPattern.Match(url.AbsoluteUri); - var collection = default(NameValueCollection); - - while (match.Success) - { - collection = HttpUtility.ParseQueryString(url.Query); - var keys = collection.AllKeys; - - foreach (var key in keys) - { - var id = collection.Get(key).ToLowerInvariant(); - - switch (key) - { - case "v": - var videos = await _api.GetVideo(id).ConfigureAwait(false); - - foreach (var video in videos) - result.MediaItems.Add(video); - - break; - - case "list": - var playlists = await _api.GetPlaylists(id).ConfigureAwait(false); - - foreach (var playlist in playlists) - result.Playlists.Add(playlist); - - break; - - default: - return new UrlParseResult(_log, ParseResultType.None); - } - } - - match = match.NextMatch(); - } - - return result; - } - } -} diff --git a/src/Maple.Youtube/app.config b/src/Maple.Youtube/app.config index f6dddd5..5775c63 100644 --- a/src/Maple.Youtube/app.config +++ b/src/Maple.Youtube/app.config @@ -3,41 +3,44 @@ - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + + + + diff --git a/src/Maple/App.config b/src/Maple/App.config deleted file mode 100644 index 67ca9a7..0000000 --- a/src/Maple/App.config +++ /dev/null @@ -1,127 +0,0 @@ - - - -
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - - - 0,0 - - - 0,0 - - - Normal - - - - - - - - - False - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Maple/App.xaml b/src/Maple/App.xaml index 2cc3369..5630ac1 100644 --- a/src/Maple/App.xaml +++ b/src/Maple/App.xaml @@ -1,61 +1,13 @@ + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - + - \ No newline at end of file + diff --git a/src/Maple/App.xaml.cs b/src/Maple/App.xaml.cs index 2854ef7..09bd7f6 100644 --- a/src/Maple/App.xaml.cs +++ b/src/Maple/App.xaml.cs @@ -1,193 +1,101 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Net; +using System; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Threading; using DryIoc; -using Maple.Core; -using Maple.Domain; -using Squirrel; +using Jot; +using Microsoft.Extensions.Logging; +using MvvmScarletToolkit; namespace Maple { public partial class App : Application { - private IContainer _container; - private Task _backgroundUpdate; + private readonly Tracker _tracker; + + private readonly IContainer _container; + private readonly ILogger _log; + + public App() + { + _container = CompositionRoot.Get(); + _tracker = _container.Resolve(); + _log = _container.Resolve().CreateLogger(); + + _log.LogInformation(Maple.Properties.Resources.AppStart); + } protected override async void OnStartup(StartupEventArgs e) { + _log.LogInformation(Maple.Properties.Resources.AppStartLoadUI); + base.OnStartup(e); + DispatcherUnhandledException += App_DispatcherUnhandledException; - _container = await DependencyInjectionFactory.Get().ConfigureAwait(true); + var styles = _container.Resolve(); - var localizationService = _container.Resolve(); - var log = _container.Resolve(); + Resources.MergedDictionaries.Add(styles); - InitializeUpdater(log); - InitializeResources(localizationService); - InitializeLocalization(); + _log.LogInformation(Maple.Properties.Resources.AppStartLoadData); + var shell = await GetShell(); - var shell = await GetShell(localizationService, log).ConfigureAwait(true); shell.Show(); - - base.OnStartup(e); + _log.LogInformation(Maple.Properties.Resources.AppStartComplete); } - private async void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) + private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) { - var log = _container?.Resolve(); - var dialog = _container?.Resolve(); - - log.Info(Localization.Properties.Resources.ExceptionMessageUnhandled); - - if (e.Exception.InnerException != null) - log.Error(e.Exception.InnerException); - - log.Error(e.Exception); - - await dialog.ShowExceptionDialog(e.Exception).ConfigureAwait(true); + _log.LogInformation(Maple.Properties.Resources.ExceptionMessageUnhandled); + _log.LogError(e.Exception, e.Exception.Message); } protected override void OnExit(ExitEventArgs e) { - SaveState(); - DisposeResources(); - - _backgroundUpdate.Wait(); - + _log.LogInformation(Maple.Properties.Resources.AppExit); ExitInternal(e); } - /// - /// Gets the shell control. - /// - /// The service. - /// /// /// order matters alot here, so be careful when modifying this /// - private async Task GetShell(ILocalizationService service, ILoggingService log) + private async Task GetShell() { - using (var vm = _container.Resolve()) + using (var vm = _container.Resolve()) { var shell = _container.Resolve(); var screen = _container.Resolve(); + var shellViewModel = _container.Resolve(); + var loading = shellViewModel.Load(CancellationToken.None); - shell.Loaded += (o, args) => screen.Close(); - screen.Show(); - - await Task.WhenAll(LoadApplicationData()).ConfigureAwait(true); - - log.Info(Localization.Properties.Resources.AppStart); - await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(true); - - return shell; - } - } - - /// - /// Initializes the resources. - /// - /// The service. - /// - /// injecting the translation manager into a SharedResourcedictionary, - /// so that hopefully all usages of the translation extension can be resolved inside of ResourceDictionaries - /// - private void InitializeResources(ILocalizationService service) - { - var url = new Uri("/Maple;component/Resources/Style.xaml", UriKind.RelativeOrAbsolute); - var styles = new IoCResourceDictionary(service, url); - - Resources.MergedDictionaries.Add(styles); - } - - private void InitializeLocalization() - { - Thread.CurrentThread.CurrentCulture = Core.Properties.Settings.Default.StartUpCulture; - } - - private void InitializeUpdater(ILoggingService log) - { - Splat.Locator.CurrentMutable.Register(() => log, typeof(Splat.ILogger)); - - _backgroundUpdate = LoadUpdates(log); - } - - private async Task LoadUpdates(ILoggingService log) - { - var manager = default(UpdateManager); - - try - { - using (manager = await UpdateManager.GitHubUpdateManager("https://www.github.com/Insire/Maple", prerelease: true).ConfigureAwait(true)) + shell.DataContext = shellViewModel; + shell.Loaded += async (o, args) => { - await manager.UpdateApp().ConfigureAwait(true); + await loading; + screen.Close(); + }; - //Debug.WriteLine("CheckForUpdate"); - //var updateInfo = await manager.CheckForUpdate(ignoreDeltaUpdates: true).ConfigureAwait(true); - //Debug.WriteLine("CheckForUpdate completed"); - //if (updateInfo.ReleasesToApply.Any()) - //{ - // Debug.WriteLine("Update found"); - // var releaseEntry = await manager.UpdateApp().ConfigureAwait(true); - // Debug.WriteLine($"Update complete {releaseEntry.Version}"); + screen.Show(); + await Task.WhenAll(loading, Task.Delay(TimeSpan.FromSeconds(1))); - //} - } - } - catch (WebException ex) - { - Debug.WriteLine(ex.Status); - log.Error(ex); - } - catch (Exception ex) - { - Debug.WriteLine(ex); - log.Error(ex); - } - finally - { - manager?.Dispose(); + return shell; } } - private IList LoadApplicationData() - { - var tasks = new List(); - - foreach (var item in _container.Resolve>()) - tasks.Add(item.LoadAsync()); - - return tasks; - } - - private void SaveState() + private async void ExitInternal(ExitEventArgs e) { - var log = _container.Resolve(); - log.Info(Localization.Properties.Resources.SavingState); + DispatcherUnhandledException -= App_DispatcherUnhandledException; - foreach (var item in _container.Resolve>()) - item.Save(); + _log.LogInformation(Maple.Properties.Resources.AppExitSaving); + _tracker.PersistAll(); - log.Info(Localization.Properties.Resources.SavedState); - } + base.OnExit(e); - private void DisposeResources() - { - // TODO get and dispose claimed resources - } - - private void ExitInternal(ExitEventArgs e) - { - DispatcherUnhandledException -= App_DispatcherUnhandledException; + await ScarletExitService.Default.ShutDown(); + _log.LogInformation(Maple.Properties.Resources.AppExitComplete); _container.Dispose(); - base.OnExit(e); } } } diff --git a/src/Maple/CompositionRoot.cs b/src/Maple/CompositionRoot.cs new file mode 100644 index 0000000..808bb0f --- /dev/null +++ b/src/Maple/CompositionRoot.cs @@ -0,0 +1,197 @@ +using DryIoc; +using FluentValidation; +using Jot; +using Jot.Storage; +using LiteDB; +using Maple.Domain; +using Maple.Youtube; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Abstractions; +using MvvmScarletToolkit.Observables; +using MvvmScarletToolkit.Wpf.Features.FileSystemBrowser; +using MvvmScarletToolkit.Wpf.FileSystemBrowser; +using Serilog; +using Serilog.Events; +using Serilog.Exceptions; +using Serilog.Extensions.Logging; +using Serilog.Formatting.Display; +using SoftThorn.MonstercatNet; +using System; +using System.ComponentModel; +using System.IO; +using System.Net.Http; +using System.Windows; + +namespace Maple +{ + public static class CompositionRoot + { + public static DryIoc.IContainer Get() + { + var assemblyName = typeof(CompositionRoot).Assembly.GetName(); + var version = assemblyName.Version; + + var settingsDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SoftThorn", "Maple"); + var logDirectory = Path.Combine(settingsDirectory, "logs"); + + Directory.CreateDirectory(settingsDirectory); + Directory.CreateDirectory(logDirectory); + + var c = new DryIoc.Container(); + + RegisterLogging(); + RegisterViewModels(); + RegisterServices(); + RegisterValidation(); + RegisterGui(); + RegisterDataAccess(); + RegisterFileSystemAccess(); + RegisterMonstercat(); + RegisterStartup(); + + void RegisterLogging() + { + var formatter = new MessageTemplateTextFormatter("{Timestamp:o} {RequestId,13} [{Level:u3}] ({SourceContext}) ({ThreadId}) ({EventId:x8}) {Message}{NewLine}{Exception}", null); + var logConfiguration = new LoggerConfiguration() + .MinimumLevel.Is(LogEventLevel.Verbose) + .Enrich.FromLogContext() + .Enrich.With() + .Enrich.With() + .Enrich.WithExceptionDetails() + .WriteTo.Console() + .WriteTo.Async(p => p.File( + formatter, + Environment.ExpandEnvironmentVariables(Path.Combine(logDirectory, $"{version}_maple.log")), + fileSizeLimitBytes: 1073741824, + retainedFileCountLimit: 1, + shared: true, + flushToDiskInterval: TimeSpan.FromSeconds(3))); + + Log.Logger = logConfiguration.CreateLogger(); + + var loggerFactory = new LoggerFactory(); + + loggerFactory + .AddSerilog(); + + c.Register(serviceType: typeof(ILoggerProvider), implementationType: typeof(SerilogLoggerProvider), reuse: Reuse.Singleton); + c.Register(serviceType: typeof(ILogger<>), implementationType: typeof(Logger<>)); + + c.UseInstance(loggerFactory); + c.UseInstance(Log.Logger); + } + + void RegisterGui() + { + var tracker = new Tracker(new JsonFileStore(perUser: true)); + tracker.Configure() + .Id(w => $"[Width={SystemParameters.VirtualScreenWidth},Height{SystemParameters.VirtualScreenHeight}]") + .Properties(w => new { w.Height, w.Width, w.Left, w.Top, w.WindowState }) + .PersistOn(nameof(Window.Closing)) + .StopTrackingOn(nameof(Window.Closing)); + + c.UseInstance(new Uri("/Maple;component/Resources/Style.xaml", UriKind.RelativeOrAbsolute)); + c.UseInstance(tracker); + + c.Register(Reuse.Singleton); + c.Register(); + c.Register(Reuse.Singleton, Made.Of(() => new IoCResourceDictionary(Arg.Of(), Arg.Of>(), Arg.Of()))); + } + + void RegisterViewModels() + { + c.RegisterMany(new[] { typeof(Playlists) }, typeof(Playlists), Reuse.Singleton); + c.RegisterMany(new[] { typeof(MediaPlayers) }, typeof(MediaPlayers), Reuse.Singleton, setup: Setup.With(allowDisposableTransient: true)); + c.RegisterMany(new[] { typeof(Cultures) }, typeof(Cultures), Reuse.Singleton); + c.RegisterMany(new[] { typeof(ILocalizationService), typeof(LocalizationsViewModel) }, typeof(LocalizationsViewModel), Reuse.Singleton); + + c.Register(Reuse.Singleton, setup: Setup.With(allowDisposableTransient: true)); + c.Register(Reuse.Singleton, setup: Setup.With(allowDisposableTransient: true)); + + c.Register(Reuse.Singleton); + + c.Register(Reuse.Singleton, setup: Setup.With(allowDisposableTransient: true)); + + c.Register(setup: Setup.With(allowDisposableTransient: true)); + }; + + void RegisterServices() + { + c.Register(Reuse.Singleton); + c.Register(Reuse.Singleton); + c.Register(); + c.Register(Reuse.Singleton); + c.Register(Reuse.Singleton); + c.Register(Reuse.Transient, setup: Setup.With(allowDisposableTransient: true)); + c.Register(Reuse.Singleton); + c.Register(Reuse.Singleton); + + c.Register(); + + c.UseInstance(ScarletCommandBuilder.Default); + c.UseInstance(ScarletDispatcher.Default); + c.UseInstance(ScarletMessenger.Default); + c.UseInstance(ScarletCommandManager.Default); + c.UseInstance(ScarletMessageProxy.Default); + c.UseInstance(ScarletWeakEventManager.Default); + c.UseInstance(ScarletExitService.Default); + } + + void RegisterValidation() + { + c.Register, PlaylistValidator>(Reuse.Singleton); + c.Register, PlaylistsValidator>(Reuse.Singleton); + c.Register, MediaPlayerValidator>(Reuse.Singleton); + c.Register, MediaPlayersValidator>(Reuse.Singleton); + c.Register, MediaItemValidator>(Reuse.Singleton); + } + + void RegisterDataAccess() + { + var dbPath = Path.Combine(settingsDirectory, "maple.db"); + var builder = new DbContextOptionsBuilder() + .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking) + .UseSqlite($"Data Source={dbPath};"); + + c.UseInstance(builder.Options); + c.Register(Reuse.Transient, setup: Setup.With(allowDisposableTransient: true)); + + var fileDbPath = Path.Combine(settingsDirectory, "file.db"); + c.UseInstance(new LiteDatabaseOptions(fileDbPath)); + c.Register(Reuse.Transient, setup: Setup.With(allowDisposableTransient: true), made: Made.Of(() => LiteDatabaseFactory.Create(Arg.Of()))); + + c.Register(Reuse.Singleton); + c.Register(Reuse.Singleton); + } + + void RegisterFileSystemAccess() + { + c.UseInstance(FileSystemOptionsViewModel.Default); + c.Register(Reuse.Transient, setup: Setup.With(allowDisposableTransient: true)); + c.Register(); + } + + void RegisterMonstercat() + { + c.Register(Reuse.Singleton, Made.Of(() => MonstercatApi.Create(Arg.Of()))); + c.Register(Reuse.Singleton); + c.Register(Reuse.Singleton); + c.UseInstance(new HttpClient().UseMonstercatApiV2()); + } + + void RegisterStartup() + { + c.Register(Reuse.Singleton); + c.Register(Reuse.Singleton); + c.Register(Reuse.Singleton, setup: Setup.With(allowDisposableTransient: true)); + c.Register(Reuse.Singleton); + c.Register(Reuse.Singleton); + c.Register(Reuse.Singleton, setup: Setup.With(allowDisposableTransient: true)); + } + + return c; + } + } +} diff --git a/src/Maple/Features/About/AboutViewModel.cs b/src/Maple/Features/About/AboutViewModel.cs new file mode 100644 index 0000000..6becf50 --- /dev/null +++ b/src/Maple/Features/About/AboutViewModel.cs @@ -0,0 +1,8 @@ +using MvvmScarletToolkit.Observables; + +namespace Maple +{ + public sealed class AboutViewModel : ObservableObject + { + } +} diff --git a/src/Maple/Features/Dashboard/DashboardViewModel.cs b/src/Maple/Features/Dashboard/DashboardViewModel.cs new file mode 100644 index 0000000..a8d0501 --- /dev/null +++ b/src/Maple/Features/Dashboard/DashboardViewModel.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; +using MvvmScarletToolkit.Observables; + +namespace Maple +{ + public sealed class DashboardViewModel : ObservableObject + { + } +} diff --git a/src/Maple/Features/DataAccess/ApplicationDbContext.cs b/src/Maple/Features/DataAccess/ApplicationDbContext.cs new file mode 100644 index 0000000..13dde7d --- /dev/null +++ b/src/Maple/Features/DataAccess/ApplicationDbContext.cs @@ -0,0 +1,31 @@ +using Maple.Domain; +using Microsoft.EntityFrameworkCore; + +namespace Maple +{ + public sealed class ApplicationDbContext : DbContext + { + public DbSet Playlists { get; set; } + public DbSet MediaItems { get; set; } + public DbSet MediaPlayers { get; set; } + + public DbSet AudioDevices { get; set; } + public DbSet AudioDeviceTypes { get; set; } + + public ApplicationDbContext(DbContextOptions options) + : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.ApplyConfiguration(new MediaPlayerConfiguration()); + modelBuilder.ApplyConfiguration(new MediaItemConfiguration()); + modelBuilder.ApplyConfiguration(new PlaylistConfiguration()); + modelBuilder.ApplyConfiguration(new AudioDeviceTypeConfiguration()); + modelBuilder.ApplyConfiguration(new AudioDeviceConfiguration()); + } + } +} diff --git a/src/Maple/Features/DataAccess/Configuration/AudioDeviceConfiguration.cs b/src/Maple/Features/DataAccess/Configuration/AudioDeviceConfiguration.cs new file mode 100644 index 0000000..76d488d --- /dev/null +++ b/src/Maple/Features/DataAccess/Configuration/AudioDeviceConfiguration.cs @@ -0,0 +1,22 @@ +using Maple.Domain; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Maple +{ + public sealed class AudioDeviceConfiguration : BaseConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + base.Configure(builder); + + builder.Property(c => c.OsId) + .IsRequired(); + + builder.HasOne(t => t.AudioDeviceType) + .WithMany(t => t.AudioDevices) + .IsRequired() + .OnDelete(DeleteBehavior.Cascade); + } + } +} diff --git a/src/Maple/Features/DataAccess/Configuration/AudioDeviceTypeConfiguration.cs b/src/Maple/Features/DataAccess/Configuration/AudioDeviceTypeConfiguration.cs new file mode 100644 index 0000000..962a357 --- /dev/null +++ b/src/Maple/Features/DataAccess/Configuration/AudioDeviceTypeConfiguration.cs @@ -0,0 +1,49 @@ +using Maple.Domain; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Maple +{ + public sealed class AudioDeviceTypeConfiguration : BaseConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + base.Configure(builder); + + builder.Property(c => c.DeviceType) + .HasConversion() + .IsRequired(); + + builder.HasData(new AudioDeviceTypeModel + { + Id = (int)Domain.DeviceType.WaveOut, + Sequence = (int)Domain.DeviceType.WaveOut, + DeviceType = Domain.DeviceType.WaveOut, + Name = nameof(Domain.DeviceType.WaveOut), + }); + + builder.HasData(new AudioDeviceTypeModel + { + Id = (int)Domain.DeviceType.DirectSound, + Sequence = (int)Domain.DeviceType.DirectSound, + DeviceType = Domain.DeviceType.DirectSound, + Name = nameof(Domain.DeviceType.DirectSound), + }); + + builder.HasData(new AudioDeviceTypeModel + { + Id = (int)Domain.DeviceType.WASAPI, + Sequence = (int)Domain.DeviceType.WASAPI, + DeviceType = Domain.DeviceType.WASAPI, + Name = nameof(Domain.DeviceType.WASAPI), + }); + + builder.HasData(new AudioDeviceTypeModel + { + Id = (int)Domain.DeviceType.ASIO, + Sequence = (int)Domain.DeviceType.ASIO, + DeviceType = Domain.DeviceType.ASIO, + Name = nameof(Domain.DeviceType.ASIO), + }); + } + } +} diff --git a/src/Maple/Features/DataAccess/Configuration/BaseConfiguration.cs b/src/Maple/Features/DataAccess/Configuration/BaseConfiguration.cs new file mode 100644 index 0000000..cc410ea --- /dev/null +++ b/src/Maple/Features/DataAccess/Configuration/BaseConfiguration.cs @@ -0,0 +1,43 @@ +using Maple.Domain; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Maple +{ + public abstract class BaseConfiguration : IEntityTypeConfiguration + where T : Entity + { + public virtual void Configure(EntityTypeBuilder builder) + { + builder.HasKey(t => t.Id); + + builder.Property(t => t.Name) + .IsRequired() + .HasMaxLength(50); + + builder.Property(t => t.Id) + .HasColumnName("Id"); + + builder.Property(t => t.Sequence) + .HasDefaultValue(0) + .HasColumnName("Sequence") + .IsRequired(); + + builder.Property(t => t.CreatedBy) + .HasDefaultValue("SYSTEM"); + + builder.Property(t => t.UpdatedBy) + .HasDefaultValue("SYSTEM"); + + builder.Property(t => t.CreatedOn) + .ValueGeneratedOnAdd() + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + builder.Property(t => t.UpdatedOn) + .ValueGeneratedOnAddOrUpdate() + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + builder.Ignore(c => c.IsDeleted); + } + } +} diff --git a/src/Maple/Features/DataAccess/Configuration/MediaItemConfiguration.cs b/src/Maple/Features/DataAccess/Configuration/MediaItemConfiguration.cs new file mode 100644 index 0000000..769c535 --- /dev/null +++ b/src/Maple/Features/DataAccess/Configuration/MediaItemConfiguration.cs @@ -0,0 +1,19 @@ +using Maple.Domain; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Maple +{ + public sealed class MediaItemConfiguration : BaseConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + base.Configure(builder); + + builder.HasOne(t => t.Playlist) + .WithMany(t => t.MediaItems) + .IsRequired() + .OnDelete(DeleteBehavior.SetNull); + } + } +} diff --git a/src/Maple/Features/DataAccess/Configuration/MediaPlayerConfiguration.cs b/src/Maple/Features/DataAccess/Configuration/MediaPlayerConfiguration.cs new file mode 100644 index 0000000..eece3b3 --- /dev/null +++ b/src/Maple/Features/DataAccess/Configuration/MediaPlayerConfiguration.cs @@ -0,0 +1,17 @@ +using Maple.Domain; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Maple +{ + public sealed class MediaPlayerConfiguration : BaseConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + base.Configure(builder); + + builder.HasOne(t => t.Playlist) + .WithMany(t => t.MediaPlayers) + .IsRequired(false); + } + } +} diff --git a/src/Maple/Features/DataAccess/Configuration/PlaylistConfiguration.cs b/src/Maple/Features/DataAccess/Configuration/PlaylistConfiguration.cs new file mode 100644 index 0000000..0ea69bf --- /dev/null +++ b/src/Maple/Features/DataAccess/Configuration/PlaylistConfiguration.cs @@ -0,0 +1,24 @@ +using Maple.Domain; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Maple +{ + public sealed class PlaylistConfiguration : BaseConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + base.Configure(builder); + + builder.Property(t => t.IsShuffeling) + .IsRequired(); + + builder.Property(c => c.PrivacyStatus) + .HasConversion() + .IsRequired(); + + builder.Property(c => c.RepeatMode) + .HasConversion() + .IsRequired(); + } + } +} diff --git a/src/Maple/Features/DataAccess/DesignTime/DesignTimeApplicationDbContextFactory.cs b/src/Maple/Features/DataAccess/DesignTime/DesignTimeApplicationDbContextFactory.cs new file mode 100644 index 0000000..ff480f5 --- /dev/null +++ b/src/Maple/Features/DataAccess/DesignTime/DesignTimeApplicationDbContextFactory.cs @@ -0,0 +1,16 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; + +namespace Maple +{ + public class DesignTimeApplicationDbContextFactory : IDesignTimeDbContextFactory + { + public ApplicationDbContext CreateDbContext(string[] args) + { + var optionsBuilder = new DbContextOptionsBuilder(); + optionsBuilder.UseSqlite("Data Source=maple.db"); + + return new ApplicationDbContext(optionsBuilder.Options); + } + } +} diff --git a/src/Maple/Features/DataAccess/FileStorage/IMediaItemCache.cs b/src/Maple/Features/DataAccess/FileStorage/IMediaItemCache.cs new file mode 100644 index 0000000..d70e40a --- /dev/null +++ b/src/Maple/Features/DataAccess/FileStorage/IMediaItemCache.cs @@ -0,0 +1,10 @@ +using System.IO; + +namespace Maple +{ + public interface IMediaItemCache + { + void Add(Stream stream, int id); + Stream Get(int id); + } +} \ No newline at end of file diff --git a/src/Maple/Features/DataAccess/FileStorage/IThumbnailCache.cs b/src/Maple/Features/DataAccess/FileStorage/IThumbnailCache.cs new file mode 100644 index 0000000..01ef8ea --- /dev/null +++ b/src/Maple/Features/DataAccess/FileStorage/IThumbnailCache.cs @@ -0,0 +1,11 @@ +using System.IO; +using System.Windows; + +namespace Maple +{ + public interface IThumbnailCache + { + void Add(Stream stream, int id, Size size); + Stream Get(int id, Size? size); + } +} \ No newline at end of file diff --git a/src/Maple/Features/DataAccess/FileStorage/LiteDatabaseFactory.cs b/src/Maple/Features/DataAccess/FileStorage/LiteDatabaseFactory.cs new file mode 100644 index 0000000..a526700 --- /dev/null +++ b/src/Maple/Features/DataAccess/FileStorage/LiteDatabaseFactory.cs @@ -0,0 +1,12 @@ +using LiteDB; + +namespace Maple +{ + public static class LiteDatabaseFactory + { + public static LiteDatabase Create(LiteDatabaseOptions options) + { + return new LiteDatabase(options.ConnectionString, options.BsonMapper); + } + } +} diff --git a/src/Maple/Features/DataAccess/FileStorage/LiteDatabaseOptions.cs b/src/Maple/Features/DataAccess/FileStorage/LiteDatabaseOptions.cs new file mode 100644 index 0000000..3df6e69 --- /dev/null +++ b/src/Maple/Features/DataAccess/FileStorage/LiteDatabaseOptions.cs @@ -0,0 +1,16 @@ +using LiteDB; +using System; + +namespace Maple +{ + public sealed class LiteDatabaseOptions + { + public string ConnectionString { get; } + public BsonMapper BsonMapper { get; set; } + + public LiteDatabaseOptions(string connectionString) + { + ConnectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString)); + } + } +} diff --git a/src/Maple/Features/DataAccess/FileStorage/LiteMediaItemCache.cs b/src/Maple/Features/DataAccess/FileStorage/LiteMediaItemCache.cs new file mode 100644 index 0000000..5a7c16d --- /dev/null +++ b/src/Maple/Features/DataAccess/FileStorage/LiteMediaItemCache.cs @@ -0,0 +1,49 @@ +using LiteDB; +using System; +using System.IO; + +namespace Maple +{ + public sealed class LiteMediaItemCache : IMediaItemCache + { + private readonly Func _databaseFactory; + private readonly string StorageName; + + public LiteMediaItemCache(Func databaseFactory) + { + _databaseFactory = databaseFactory ?? throw new ArgumentNullException(nameof(databaseFactory)); + StorageName = "MediaItemCache"; + } + + public void Add(Stream stream, int id) + { + var type = nameof(T); + using (var db = _databaseFactory()) + { + // Gets a FileStorage with custom collection name + var fs = db.GetStorage(StorageName); + + // Upload a file from a Stream + fs.Upload(GetCacheKey(type, id), id.ToString(), stream); + } + } + + private static string GetCacheKey(string type, int id) + { + return $"$/{type}/{id}"; + } + + public Stream Get(int id) + { + var type = nameof(T); + using (var db = _databaseFactory()) + { + // Gets a FileStorage with custom collection name + var fs = db.GetStorage(StorageName); + var file = fs.FindById(GetCacheKey(type, id)); + + return file.OpenRead(); + } + } + } +} diff --git a/src/Maple/Features/DataAccess/FileStorage/LiteThumbnailCache.cs b/src/Maple/Features/DataAccess/FileStorage/LiteThumbnailCache.cs new file mode 100644 index 0000000..87d8021 --- /dev/null +++ b/src/Maple/Features/DataAccess/FileStorage/LiteThumbnailCache.cs @@ -0,0 +1,65 @@ +using LiteDB; +using System; +using System.IO; +using System.Linq; +using System.Windows; + +namespace Maple +{ + // https://www.litedb.org/docs/filestorage/ + // https://www.litedb.org/docs/getting-started/ + public sealed class LiteThumbnailCache : IThumbnailCache + { + private readonly Func _databaseFactory; + private readonly string StorageName; + + public LiteThumbnailCache(Func databaseFactory) + { + _databaseFactory = databaseFactory ?? throw new ArgumentNullException(nameof(databaseFactory)); + StorageName = "ThumbnailCache"; + } + + public void Add(Stream stream, int id, Size size) + { + var type = nameof(T); + using (var db = _databaseFactory()) + { + // Gets a FileStorage with custom collection name + var fs = db.GetStorage(StorageName); + + // Upload a file from a Stream + fs.Upload(GetCacheKey(type, id, size), ToString(size), stream); + } + } + + private static string GetCacheKey(string type, int id, Size? size) + { + if (size.HasValue) + { + return $"$/{type}/{id}/{ToString(size.Value)}"; + } + else + { + return $"$/{type}/{id}/"; + } + } + + private static string ToString(Size size) + { + return $"{size.Width}x{size.Height}"; + } + + public Stream Get(int id, Size? size) + { + var type = nameof(T); + using (var db = _databaseFactory()) + { + // Gets a FileStorage with custom collection name + var fs = db.GetStorage(StorageName); + var file = fs.Find(GetCacheKey(type, id, size)).FirstOrDefault(); + + return file.OpenRead(); + } + } + } +} diff --git a/src/Maple/Features/Import/FileSystem/FileSystemInfoChangedMessage.cs b/src/Maple/Features/Import/FileSystem/FileSystemInfoChangedMessage.cs new file mode 100644 index 0000000..63b6e73 --- /dev/null +++ b/src/Maple/Features/Import/FileSystem/FileSystemInfoChangedMessage.cs @@ -0,0 +1,12 @@ +using MvvmScarletToolkit; + +namespace Maple +{ + public class FileSystemInfoChangedMessage : GenericScarletMessage + { + public FileSystemInfoChangedMessage(object sender, IFileSystemInfo info) + : base(sender, info) + { + } + } +} diff --git a/src/Maple/Features/Import/Monstercat/Entities/IMonstercatViewModel.cs b/src/Maple/Features/Import/Monstercat/Entities/IMonstercatViewModel.cs new file mode 100644 index 0000000..1e168cd --- /dev/null +++ b/src/Maple/Features/Import/Monstercat/Entities/IMonstercatViewModel.cs @@ -0,0 +1,11 @@ +using System; +using System.ComponentModel; + +namespace Maple +{ + public interface IMonstercatViewModel : INotifyPropertyChanged + { + Guid Id { get; } + string Title { get; } + } +} diff --git a/src/Maple/Features/Import/Monstercat/Entities/MonstercatPlaylistViewModel.cs b/src/Maple/Features/Import/Monstercat/Entities/MonstercatPlaylistViewModel.cs new file mode 100644 index 0000000..96a81c4 --- /dev/null +++ b/src/Maple/Features/Import/Monstercat/Entities/MonstercatPlaylistViewModel.cs @@ -0,0 +1,37 @@ +using MvvmScarletToolkit; +using MvvmScarletToolkit.Observables; +using SoftThorn.MonstercatNet; +using System; + +namespace Maple +{ + public sealed class MonstercatPlaylistViewModel : ViewModelListBase, IMonstercatViewModel + { + private readonly IMonstercatApi _monstercatApi; + + public Guid Id { get; } + public string Title { get; } + + public int NumRecords { get; } + public bool Public { get; } + public bool MyLibrary { get; } + + public MonstercatPlaylistViewModel(IMonstercatApi monstercatApi, IScarletCommandBuilder commandBuilder, SoftThorn.MonstercatNet.Playlist model) + : base(commandBuilder) + { + if (model is null) + { + throw new ArgumentNullException(nameof(model)); + } + + _monstercatApi = monstercatApi ?? throw new ArgumentNullException(nameof(monstercatApi)); + + Id = model.Id; + Title = model.Name ?? throw new ArgumentNullException(nameof(model.Name)); + + NumRecords = model.NumRecords; + Public = model.Public; + MyLibrary = model.MyLibrary; + } + } +} diff --git a/src/Maple/Features/Import/Monstercat/Entities/MonstercatReleaseViewModel.cs b/src/Maple/Features/Import/Monstercat/Entities/MonstercatReleaseViewModel.cs new file mode 100644 index 0000000..57ef6e7 --- /dev/null +++ b/src/Maple/Features/Import/Monstercat/Entities/MonstercatReleaseViewModel.cs @@ -0,0 +1,38 @@ +using MvvmScarletToolkit; +using MvvmScarletToolkit.Observables; +using SoftThorn.MonstercatNet; +using System; + +namespace Maple +{ + public sealed class MonstercatReleaseViewModel : ViewModelBase, IMonstercatViewModel + { + private readonly IMonstercatApi _monstercatApi; + + public Guid Id { get; } + public string Title { get; } + + public string ArtistsTitle { get; } + public string GenrePrimary { get; } + + public string GenreSecondary { get; } + + public MonstercatReleaseViewModel(IMonstercatApi monstercatApi, IScarletCommandBuilder commandBuilder, Release model) + : base(commandBuilder) + { + if (model is null) + { + throw new ArgumentNullException(nameof(model)); + } + + _monstercatApi = monstercatApi ?? throw new ArgumentNullException(nameof(monstercatApi)); + + Id = model.Id; + Title = model.Title ?? throw new ArgumentNullException(nameof(model.Title)); + + ArtistsTitle = model.ArtistsTitle; + GenrePrimary = model.GenrePrimary; + GenreSecondary = model.GenreSecondary; + } + } +} diff --git a/src/Maple/Features/Import/Monstercat/Entities/MonstercatTrackViewModel.cs b/src/Maple/Features/Import/Monstercat/Entities/MonstercatTrackViewModel.cs new file mode 100644 index 0000000..4e0c28a --- /dev/null +++ b/src/Maple/Features/Import/Monstercat/Entities/MonstercatTrackViewModel.cs @@ -0,0 +1,37 @@ +using MvvmScarletToolkit; +using MvvmScarletToolkit.Observables; +using SoftThorn.MonstercatNet; +using System; + +namespace Maple +{ + public sealed class MonstercatTrackViewModel : ViewModelBase + { + private readonly IMonstercatApi _monstercatApi; + + public Guid Id { get; } + public string Title { get; } + public string ArtistsTitle { get; } + public string GenrePrimary { get; } + + public string GenreSecondary { get; } + + public MonstercatTrackViewModel(IMonstercatApi monstercatApi, IScarletCommandBuilder commandBuilder, Track model) + : base(commandBuilder) + { + if (model is null) + { + throw new ArgumentNullException(nameof(model)); + } + + _monstercatApi = monstercatApi ?? throw new ArgumentNullException(nameof(monstercatApi)); + + Id = model.Id; + Title = model.Title ?? throw new ArgumentNullException(nameof(model.Title)); + + ArtistsTitle = model.ArtistsTitle; + GenrePrimary = model.GenrePrimary; + GenreSecondary = model.GenreSecondary; + } + } +} diff --git a/src/Maple/Features/Import/Monstercat/IMonstercatViewModelFactory.cs b/src/Maple/Features/Import/Monstercat/IMonstercatViewModelFactory.cs new file mode 100644 index 0000000..d06ed50 --- /dev/null +++ b/src/Maple/Features/Import/Monstercat/IMonstercatViewModelFactory.cs @@ -0,0 +1,10 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Maple +{ + public interface IMonstercatViewModelFactory + { + Task Create(string input, CancellationToken token); + } +} diff --git a/src/Maple/Features/Import/Monstercat/MonstercatImportDialog.xaml b/src/Maple/Features/Import/Monstercat/MonstercatImportDialog.xaml new file mode 100644 index 0000000..0ea466f --- /dev/null +++ b/src/Maple/Features/Import/Monstercat/MonstercatImportDialog.xaml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Maple/Features/Import/Monstercat/MonstercatImportDialog.xaml.cs b/src/Maple/Features/Import/Monstercat/MonstercatImportDialog.xaml.cs new file mode 100644 index 0000000..d026e90 --- /dev/null +++ b/src/Maple/Features/Import/Monstercat/MonstercatImportDialog.xaml.cs @@ -0,0 +1,44 @@ +using MvvmScarletToolkit; +using MvvmScarletToolkit.Abstractions; +using System; +using System.Threading; +using System.Windows; + +namespace Maple +{ + public partial class MonstercatImportDialog + { + private readonly MonstercatImportViewModel _monstercatImportViewModel; + + public MonstercatImportDialog() + { + InitializeComponent(); + } + + public MonstercatImportDialog(IScarletCommandBuilder commandBuilder, ILocalizationService localizationService, Window owner, CancellationToken abort, MonstercatImportViewModel monstercatImportViewModel) + : base(commandBuilder, localizationService, owner, abort) + { + _monstercatImportViewModel = monstercatImportViewModel ?? throw new ArgumentNullException(nameof(monstercatImportViewModel)); + + if (owner is null) + { + throw new ArgumentNullException(nameof(owner)); + } + + InitializeComponent(); + + Owner = owner; + DataContext = monstercatImportViewModel; + } + + public MonstercatImportDialog(DialogWindow owner, CancellationToken abort, MonstercatImportViewModel monstercatImportViewModel) + : this(owner.CommandBuilder, owner.LocalizationService, owner, abort, monstercatImportViewModel) + { + } + + protected override bool CanAccept() + { + return true; // TODO ? + } + } +} diff --git a/src/Maple/Features/Import/Monstercat/MonstercatImportViewModel.cs b/src/Maple/Features/Import/Monstercat/MonstercatImportViewModel.cs new file mode 100644 index 0000000..3832b25 --- /dev/null +++ b/src/Maple/Features/Import/Monstercat/MonstercatImportViewModel.cs @@ -0,0 +1,83 @@ +using FluentValidation.Results; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Observables; +using System; +using System.Collections.ObjectModel; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace Maple +{ + public sealed class MonstercatImportViewModel : ViewModelListBase + { + private readonly ObservableCollection _errors; + private readonly ObservableCollection _releases; + private readonly ObservableCollection _playlists; + + private readonly IMonstercatViewModelFactory _monstercatApi; + + private string _source; + public string Source + { + get { return _source; } + set { SetValue(ref _source, value); } + } + + private ValidationFailure _error; + public ValidationFailure Error + { + get { return _error; } + set { SetValue(ref _error, value); } + } + + public ICommand ParseCommand { get; } + + public ICommand AddToResultsCommand { get; } + + public ICommand RemoveFromResultsCommand { get; } + + public ReadOnlyObservableCollection Errors { get; } + public ReadOnlyObservableCollection Releases { get; } + public ReadOnlyObservableCollection Playlists { get; } + + public MonstercatImportViewModel(in IScarletCommandBuilder commandBuilder, IMonstercatViewModelFactory monstercatApi) + : base(commandBuilder) + { + _monstercatApi = monstercatApi ?? throw new ArgumentNullException(nameof(monstercatApi)); + + _errors = new ObservableCollection(); + _releases = new ObservableCollection(); + _playlists = new ObservableCollection(); + + Errors = new ReadOnlyObservableCollection(_errors); + Releases = new ReadOnlyObservableCollection(_releases); + Playlists = new ReadOnlyObservableCollection(_playlists); + + ParseCommand = commandBuilder + .Create(Parse, CanParse) + .WithSingleExecution() + .Build(); + } + + private async Task Parse(CancellationToken token) + { + using (BusyStack.GetToken()) + { + var result = await _monstercatApi.Create(Source, token); + + if (result is null) + { + return; + } + + await Add(result); + } + } + + private bool CanParse() + { + return !IsBusy && !string.IsNullOrWhiteSpace(Source); + } + } +} diff --git a/src/Maple/Features/Import/Monstercat/MonstercatViewModelFactory.cs b/src/Maple/Features/Import/Monstercat/MonstercatViewModelFactory.cs new file mode 100644 index 0000000..d36fc8a --- /dev/null +++ b/src/Maple/Features/Import/Monstercat/MonstercatViewModelFactory.cs @@ -0,0 +1,70 @@ +using MvvmScarletToolkit; +using SoftThorn.MonstercatNet; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Maple +{ + public sealed class MonstercatViewModelFactory : IMonstercatViewModelFactory + { + private readonly IMonstercatApi _monstercatApi; + private readonly IScarletCommandBuilder _commandBuilder; + + public MonstercatViewModelFactory(IMonstercatApi monstercatApi, IScarletCommandBuilder commandBuilder) + { + _monstercatApi = monstercatApi ?? throw new ArgumentNullException(nameof(monstercatApi)); + _commandBuilder = commandBuilder ?? throw new ArgumentNullException(nameof(commandBuilder)); + } + + public async Task Create(string input, CancellationToken token) + { + if (!input.Contains("monstercat.com", StringComparison.InvariantCultureIgnoreCase)) + { + return null; + } + + if (Uri.TryCreate(input.Trim(), UriKind.RelativeOrAbsolute, out var url)) + { + if (url.Segments.Length != 3) + { + return null; + } + + switch (url.Segments[1].Trim('/').ToLowerInvariant()) + { + case "release": + { + var id = url.Segments[2]; + var result = await _monstercatApi.GetRelease(id); + if (result?.Release is null) + { + return null; + } + + return new MonstercatReleaseViewModel(_monstercatApi, _commandBuilder, result.Release); + } + + case "playlist": + { + var id = url.Segments[2]; + if (!Guid.TryParse(id, out var guid)) + { + return null; + } + + return new MonstercatPlaylistViewModel(_monstercatApi, _commandBuilder, new SoftThorn.MonstercatNet.Playlist() + { + // TODO fetch and add playlist information + // also fetch all track meta data + Id = guid, + Name = "Test", + }); + } + } + } + + return null; + } + } +} diff --git a/src/Maple/Features/Import/Youtube/YoutubeImportViewModel.cs b/src/Maple/Features/Import/Youtube/YoutubeImportViewModel.cs new file mode 100644 index 0000000..2618b75 --- /dev/null +++ b/src/Maple/Features/Import/Youtube/YoutubeImportViewModel.cs @@ -0,0 +1,64 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using Maple.Youtube; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Observables; + +namespace Maple +{ + public sealed class YoutubeImportViewModel : ViewModelListBase + { + private readonly IYoutubeService _youtubeService; + + private string _source; + public string Source + { + get { return _source; } + set { SetValue(ref _source, value); } + } + + public ICommand ParseCommand { get; } + + public YoutubeImportViewModel(IScarletCommandBuilder commandBuilder, IYoutubeService youtubeService) + : base(commandBuilder) + { + _youtubeService = youtubeService ?? throw new ArgumentNullException(nameof(youtubeService)); + + ParseCommand = commandBuilder + .Create(Parse, CanParse) + .WithSingleExecution() + .Build(); + } + + private async Task Parse(CancellationToken token) + { + using (BusyStack.GetToken()) + { + var results = await _youtubeService + .Parse(Source) + .ConfigureAwait(true); + + foreach (var model in results) + { + switch (model) + { + case YoutubePlaylist playlist: + await Add(new YoutubePlaylistViewModel(playlist)).ConfigureAwait(false); + break; + + case YoutubeVideo video: + await Add(new YoutubeVideoViewModel(video)).ConfigureAwait(false); + break; + } + } + } + } + + private bool CanParse() + { + return !IsBusy && !string.IsNullOrWhiteSpace(Source); + } + } +} diff --git a/src/Maple/Features/Import/Youtube/YoutubePlaylistViewModel.cs b/src/Maple/Features/Import/Youtube/YoutubePlaylistViewModel.cs new file mode 100644 index 0000000..59f8582 --- /dev/null +++ b/src/Maple/Features/Import/Youtube/YoutubePlaylistViewModel.cs @@ -0,0 +1,17 @@ +using System.Collections.ObjectModel; +using System.Linq; +using Maple.Youtube; + +namespace Maple +{ + public sealed class YoutubePlaylistViewModel : YoutubeRessourceViewModel + { + public ReadOnlyCollection Items { get; } + + public YoutubePlaylistViewModel(YoutubePlaylist model) + : base(model) + { + Items = model.Items.Select(p => new YoutubeVideoViewModel(p)).ToList().AsReadOnly(); + } + } +} diff --git a/src/Maple/Features/Import/Youtube/YoutubeRessourceViewModel.cs b/src/Maple/Features/Import/Youtube/YoutubeRessourceViewModel.cs new file mode 100644 index 0000000..c51a91c --- /dev/null +++ b/src/Maple/Features/Import/Youtube/YoutubeRessourceViewModel.cs @@ -0,0 +1,25 @@ +using Maple.Domain; +using Maple.Youtube; +using MvvmScarletToolkit.Observables; + +namespace Maple +{ + public abstract class YoutubeRessourceViewModel : ObservableObject + { + public string Title { get; } + + public string Description { get; } + + public string Location { get; } + + public PrivacyStatus PrivacyStatus { get; } + + public YoutubeRessourceViewModel(YoutubeRessource model) + { + Title = model.Title; + Description = model.Description; + Location = model.Location; + PrivacyStatus = (PrivacyStatus)model.PrivacyStatus; + } + } +} diff --git a/src/Maple/Features/Import/Youtube/YoutubeVideoViewModel.cs b/src/Maple/Features/Import/Youtube/YoutubeVideoViewModel.cs new file mode 100644 index 0000000..03ca525 --- /dev/null +++ b/src/Maple/Features/Import/Youtube/YoutubeVideoViewModel.cs @@ -0,0 +1,15 @@ +using Maple.Youtube; + +namespace Maple +{ + public sealed class YoutubeVideoViewModel : YoutubeRessourceViewModel + { + public long Duration { get; } + + public YoutubeVideoViewModel(YoutubeVideo model) + : base(model) + { + Duration = model.Duration; + } + } +} diff --git a/src/Maple/Features/Localization/Providers/ResxTranslationProvider.cs b/src/Maple/Features/Localization/Providers/ResxTranslationProvider.cs new file mode 100644 index 0000000..f4c5dea --- /dev/null +++ b/src/Maple/Features/Localization/Providers/ResxTranslationProvider.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Resources; +using MvvmScarletToolkit.Abstractions; + +namespace Maple +{ + public class ResxTranslationProvider : ILocalizationProvider + { + private readonly ResourceManager _resourceManager; + + public IEnumerable Languages { get; } + + /// + /// Initializes a new instance of the class. + /// + /// Name of the base. + /// The assembly that provides localized strings + public ResxTranslationProvider() + { + _resourceManager = new ResourceManager(typeof(Properties.Resources)); + Languages = new CultureInfo[] + { + new CultureInfo("de"), + new CultureInfo("en") + }; + } + + public string Translate(string key, CultureInfo culture) + { + return _resourceManager.GetString(key, culture); + } + } +} diff --git a/src/Maple/UI/MarkupExtensions/TranslationExtension.cs b/src/Maple/Features/Localization/TranslationExtension.cs similarity index 60% rename from src/Maple/UI/MarkupExtensions/TranslationExtension.cs rename to src/Maple/Features/Localization/TranslationExtension.cs index ff79a2e..3127113 100644 --- a/src/Maple/UI/MarkupExtensions/TranslationExtension.cs +++ b/src/Maple/Features/Localization/TranslationExtension.cs @@ -1,10 +1,12 @@ -using System; +using System; +using System.ComponentModel; using System.Diagnostics; using System.Windows; using System.Windows.Data; using System.Windows.Markup; using System.Xaml; -using Maple.Core; +using MvvmScarletToolkit.Abstractions; +using MvvmScarletToolkit.Observables; namespace Maple { @@ -32,47 +34,45 @@ public TranslationExtension(string key) public override object ProvideValue(IServiceProvider serviceProvider) { if (TryGetIoCFrameWorkElement(serviceProvider, out var element)) - return ProvideValue(serviceProvider, element.TranslationManager); + return ProvideBinding(serviceProvider, element.WeakEventManager, element.LocalizationService); - if (TryGetTranslationManagerFromResources(serviceProvider, out var manager)) - return ProvideValue(serviceProvider, manager); + if (TryGetServiceFromResources>(serviceProvider, out var manager) && TryGetServiceFromResources(serviceProvider, out var service)) + return ProvideBinding(serviceProvider, manager, service); - Debug.WriteLine($"{nameof(TranslationExtension)} ProvideValue {Key} failed"); + Debug.WriteLine($"{nameof(TranslationExtension)} ProvideValue for {Key} failed"); - if (Debugger.IsAttached) - Debug.Fail($"{nameof(TranslationExtension)} ProvideValue {Key} failed"); - - return null; + return $"!{Key}!"; } - private bool TryGetIoCFrameWorkElement(IServiceProvider serviceProvider, out IIocFrameworkElement element) + private static bool TryGetIoCFrameWorkElement(IServiceProvider serviceProvider, out IIocFrameworkElement element) { var provider = serviceProvider.GetService(typeof(IRootObjectProvider)) as IRootObjectProvider; element = provider?.RootObject as IIocFrameworkElement; return element != null; } - private bool TryGetTranslationManagerFromResources(IServiceProvider serviceProvider, out ILocalizationService manager) + private static bool TryGetServiceFromResources(IServiceProvider serviceProvider, out T service) + where T : class { var provider = serviceProvider.GetService(typeof(IRootObjectProvider)) as IRootObjectProvider; var dictionary = provider?.RootObject as ResourceDictionary; - var key = typeof(ILocalizationService).Name; + var key = typeof(T).Name; if (dictionary?.Contains(key) == true) { - manager = dictionary[key] as ILocalizationService; + service = dictionary[key] as T; return true; } - manager = null; + service = null; return false; } - private object ProvideValue(IServiceProvider serviceProvider, ILocalizationService manager) + private object ProvideBinding(IServiceProvider serviceProvider, IScarletEventManager weakEventManager, ILocalizationService service) { var binding = new Binding("Value") { - Source = new LocalizationDTO(manager, Key, ToUpper) + Source = new LocalizationViewModel(weakEventManager, service, Key, ToUpper) }; return binding.ProvideValue(serviceProvider); diff --git a/src/Maple/Features/Logging/EventIdEnricher.cs b/src/Maple/Features/Logging/EventIdEnricher.cs new file mode 100644 index 0000000..c3e0b7c --- /dev/null +++ b/src/Maple/Features/Logging/EventIdEnricher.cs @@ -0,0 +1,14 @@ +using Serilog.Core; +using Serilog.Events; +using Serilog.Formatting.Compact; + +namespace Maple +{ + internal sealed class EventIdEnricher : ILogEventEnricher + { + public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) + { + logEvent.AddOrUpdateProperty(new LogEventProperty("EventId", new ScalarValue(EventIdHash.Compute(logEvent.MessageTemplate.Text)))); + } + } +} diff --git a/src/Maple/Features/Logging/LoggingFileConfiguration.cs b/src/Maple/Features/Logging/LoggingFileConfiguration.cs new file mode 100644 index 0000000..21f770a --- /dev/null +++ b/src/Maple/Features/Logging/LoggingFileConfiguration.cs @@ -0,0 +1,29 @@ +namespace Maple +{ + public sealed class LoggingFileConfiguration + { + internal const long DefaultFileSizeLimitBytes = 1024 * 1024 * 1024; + internal const int DefaultRetainedFileCountLimit = 28; + + /// + /// Filname to write. The filename may include {Date} to specify + /// how the date portion of the filename is calculated. May include + /// environment variables. + /// + public string PathFormat { get; set; } + + /// + /// The maximum size, in bytes, to which any single log file will be + /// allowed to grow. For unrestricted growth, pass null. The + /// default is 1 GiB. + /// + public long? FileSizeLimitBytes { get; set; } + + /// + /// The maximum number of log files that will be retained, including + /// the current log file. For unlimited retention, pass null. + /// The default is 31. + /// + public int? RetainedFileCountLimit { get; set; } + } +} diff --git a/src/Maple/Features/Logging/ThreadIdEnricher.cs b/src/Maple/Features/Logging/ThreadIdEnricher.cs new file mode 100644 index 0000000..a230688 --- /dev/null +++ b/src/Maple/Features/Logging/ThreadIdEnricher.cs @@ -0,0 +1,14 @@ +using Serilog.Core; +using Serilog.Events; +using System.Threading; + +namespace Maple +{ + internal sealed class ThreadIdEnricher : ILogEventEnricher + { + public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) + { + logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ThreadId", Thread.CurrentThread.ManagedThreadId)); + } + } +} diff --git a/src/Maple/Features/Navigation/NavigationViewModel.cs b/src/Maple/Features/Navigation/NavigationViewModel.cs new file mode 100644 index 0000000..844c9bb --- /dev/null +++ b/src/Maple/Features/Navigation/NavigationViewModel.cs @@ -0,0 +1,58 @@ +using System.Linq; +using System.Windows.Input; +using Maple.Properties; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Commands; +using MvvmScarletToolkit.Observables; + +namespace Maple +{ + public sealed class NavigationViewModel : Scenes + { + public ICommand OpenMediaPlayerCommand { get; } + public ICommand OpenOptionsCommand { get; } + + public NavigationViewModel(IScarletCommandBuilder commandBuilder, + PlaybackViewModel playback, + LocalizationsViewModel localizations, + MediaPlayers mediaPlayers, + Playlists playlists, + OptionsViewModel options, + DashboardViewModel dashboard, + AboutViewModel about) + : base(commandBuilder, localizations) + { + Add(nameof(Resources.Dashboard), dashboard); + Add(nameof(Resources.Playback), playback); + Add(nameof(Resources.MediaLibrary), playlists); + Add(nameof(Resources.MediaPlayers), mediaPlayers); + Add(nameof(Resources.Options), options); + Add(nameof(Resources.About), about); + + SelectedItem = this[0]; + + OpenMediaPlayerCommand = new RelayCommand(CommandManager, OpenMediaPlayerView, CanOpenMediaPlayerView); + OpenOptionsCommand = new RelayCommand(CommandManager, OpenOptionsView, CanOpenOptionsView); + } + + private void OpenOptionsView() + { + SelectedItem = Items.First(p => p.Content is OptionsViewModel); + } + + private bool CanOpenOptionsView() + { + return Items?.Any(p => p.Content is OptionsViewModel) == true; + } + + private void OpenMediaPlayerView() + { + SelectedItem = Items.First(p => p.Content is MediaPlayers); + } + + private bool CanOpenMediaPlayerView() + { + return Items?.Any(p => p.Content is MediaPlayers) == true; + } + } +} diff --git a/src/Maple/Features/Playback/AudioDeviceTypes/AudioDeviceType.cs b/src/Maple/Features/Playback/AudioDeviceTypes/AudioDeviceType.cs new file mode 100644 index 0000000..2044c20 --- /dev/null +++ b/src/Maple/Features/Playback/AudioDeviceTypes/AudioDeviceType.cs @@ -0,0 +1,91 @@ +using Maple.Domain; +using MvvmScarletToolkit.Observables; +using System; + +namespace Maple +{ + public sealed class AudioDeviceType : ObservableObject, IAudioDeviceTypeModel + { + private int _id; + public int Id + { + get { return _id; } + private set { SetValue(ref _id, value); } + } + + private int _sequence; + public int Sequence + { + get { return _sequence; } + set { SetValue(ref _sequence, value); } + } + + private string _name; + public string Name + { + get { return _name; } + set { SetValue(ref _name, value); } + } + + private string _createdBy; + public string CreatedBy + { + get { return _createdBy; } + private set { SetValue(ref _createdBy, value); } + } + + private string _updatedBy; + public string UpdatedBy + { + get { return _updatedBy; } + private set { SetValue(ref _updatedBy, value); } + } + + private DateTime _updatedOn; + public DateTime UpdatedOn + { + get { return _updatedOn; } + private set { SetValue(ref _updatedOn, value); } + } + + private DateTime _createdOn; + public DateTime CreatedOn + { + get { return _createdOn; } + private set { SetValue(ref _createdOn, value); } + } + + private bool _isDeleted; + public bool IsDeleted + { + get { return _isDeleted; } + private set { SetValue(ref _isDeleted, value); } + } + + private DeviceType _deviceType; + public DeviceType DeviceType + { + get { return _deviceType; } + private set { SetValue(ref _deviceType, value); } + } + + public AudioDeviceType(AudioDeviceTypeModel model) + { + Update(model); + } + + public void Update(AudioDeviceTypeModel model) + { + Id = model.Id; + Name = model.Name; + Sequence = model.Sequence; + + DeviceType = model.DeviceType; + + CreatedBy = model.CreatedBy; + CreatedOn = model.CreatedOn; + UpdatedBy = model.UpdatedBy; + UpdatedOn = model.UpdatedOn; + } + } +} diff --git a/src/Maple/Features/Playback/AudioDeviceTypes/AudioDeviceTypes.cs b/src/Maple/Features/Playback/AudioDeviceTypes/AudioDeviceTypes.cs new file mode 100644 index 0000000..3eba0d4 --- /dev/null +++ b/src/Maple/Features/Playback/AudioDeviceTypes/AudioDeviceTypes.cs @@ -0,0 +1,26 @@ +using MvvmScarletToolkit; +using MvvmScarletToolkit.Observables; + +namespace Maple +{ + public sealed class AudioDeviceTypes : ViewModelListBase + { + public AudioDeviceTypes(in IScarletCommandBuilder commandBuilder) + : base(commandBuilder) + { + } + + public AudioDeviceType GetById(int id) + { + for (var i = 0; i < Count; i++) + { + if (this[i].Id == id) + { + return this[i]; + } + } + + return null; + } + } +} diff --git a/src/Maple/Features/Playback/AudioDevices/AsioDevice.cs b/src/Maple/Features/Playback/AudioDevices/AsioDevice.cs new file mode 100644 index 0000000..2bbeea4 --- /dev/null +++ b/src/Maple/Features/Playback/AudioDevices/AsioDevice.cs @@ -0,0 +1,27 @@ +using System; +using System.Diagnostics; +using Maple.Domain; +using NAudio.Wave; + +namespace Maple +{ + [DebuggerDisplay("{" + nameof(GetDebuggerDisplay) + "(),nq}")] + internal sealed class AsioDevice : AudioDevice + { + public AsioOut Device { get; } + + public AsioDevice(AsioOut device) + : base(device?.DriverName) + { + Device = device ?? throw new ArgumentNullException(nameof(device)); + Name = device.DriverName; + + AudioDeviceTypeId = (int)Domain.DeviceType.ASIO; + } + + private string GetDebuggerDisplay() + { + return $"{this.GetKey()} {Name} {nameof(AsioDevice)}"; + } + } +} diff --git a/src/Maple/Features/Playback/AudioDevices/AudioDevice.cs b/src/Maple/Features/Playback/AudioDevices/AudioDevice.cs new file mode 100644 index 0000000..3e6f6cf --- /dev/null +++ b/src/Maple/Features/Playback/AudioDevices/AudioDevice.cs @@ -0,0 +1,131 @@ +using Maple.Domain; +using MvvmScarletToolkit.Observables; +using System; + +namespace Maple +{ + public abstract class AudioDevice : ObservableObject, IAudioDevice + { + private string _osId; + public string OsId + { + get { return _osId; } + private set { SetValue(ref _osId, value); } + } + + private int _id; + public int Id + { + get { return _id; } + private set { SetValue(ref _id, value); } + } + + private int _sequence; + public int Sequence + { + get { return _sequence; } + set { SetValue(ref _sequence, value); } + } + + private string _name; + public string Name + { + get { return _name; } + set { SetValue(ref _name, value); } + } + + private bool _isSelected; + public bool IsSelected + { + get { return _isSelected; } + set { SetValue(ref _isSelected, value); } + } + + private int _audioDeviceTypeId; + public int AudioDeviceTypeId + { + get { return _audioDeviceTypeId; } + protected set { SetValue(ref _audioDeviceTypeId, value); } + } + + private AudioDeviceType _audioDeviceType; + public AudioDeviceType AudioDeviceType + { + get { return _audioDeviceType; } + private set { SetValue(ref _audioDeviceType, value); } + } + + private string _createdBy; + public string CreatedBy + { + get { return _createdBy; } + private set { SetValue(ref _createdBy, value); } + } + + private string _updatedBy; + public string UpdatedBy + { + get { return _updatedBy; } + private set { SetValue(ref _updatedBy, value); } + } + + private DateTime _updatedOn; + public DateTime UpdatedOn + { + get { return _updatedOn; } + private set { SetValue(ref _updatedOn, value); } + } + + private DateTime _createdOn; + public DateTime CreatedOn + { + get { return _createdOn; } + private set { SetValue(ref _createdOn, value); } + } + + private bool _isDeleted; + public bool IsDeleted + { + get { return _isDeleted; } + private set { SetValue(ref _isDeleted, value); } + } + + protected AudioDevice(string osIdentifier) + { + if (string.IsNullOrWhiteSpace(osIdentifier)) + { + throw new ArgumentException("Can't be Null or WhiteSpace", nameof(osIdentifier)); + } + + OsId = osIdentifier; + + var now = DateTime.Now; + + CreatedBy = Environment.UserName; + CreatedOn = now; + UpdatedBy = Environment.UserName; + UpdatedOn = now; + } + + public void UpdateFromModel(AudioDeviceModel model, AudioDeviceType audioDeviceType) + { + Update(model); + + AudioDeviceType = audioDeviceType; + } + + public void Update(IAudioDevice model) + { + Id = model.Id; + Name = model.Name; + Sequence = model.Sequence; + + AudioDeviceTypeId = model.AudioDeviceTypeId; + + CreatedBy = model.CreatedBy; + CreatedOn = model.CreatedOn; + UpdatedBy = model.UpdatedBy; + UpdatedOn = model.UpdatedOn; + } + } +} diff --git a/src/Maple/Features/Playback/AudioDevices/AudioDeviceProvider.cs b/src/Maple/Features/Playback/AudioDevices/AudioDeviceProvider.cs new file mode 100644 index 0000000..6f55669 --- /dev/null +++ b/src/Maple/Features/Playback/AudioDevices/AudioDeviceProvider.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Maple.Domain; +using MvvmScarletToolkit; +using NAudio.CoreAudioApi; +using NAudio.Wave; + +namespace Maple +{ + internal sealed class AudioDeviceProvider : IAudioDeviceProvider + { + private readonly IScarletDispatcher _dispatcher; + + public AudioDeviceProvider(IScarletDispatcher dispatcher) + { + _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher)); + } + + public Task> Get(Domain.DeviceType type, CancellationToken token) + { + return Task.Run(() => (type switch + { + Domain.DeviceType.WaveOut => new ReadOnlyCollection(GetWave(token).ToList()), + Domain.DeviceType.DirectSound => new ReadOnlyCollection(GetDirectSound(token).ToList()), + Domain.DeviceType.WASAPI => new ReadOnlyCollection(GetWasapi(token).ToList()), + Domain.DeviceType.ASIO => new ReadOnlyCollection(GetAsio(token).ToList()), + Domain.DeviceType.None => new ReadOnlyCollection(Enumerable.Empty().ToList()), + _ => throw new NotImplementedException(), + }), token); + } + + private IEnumerable GetWave(CancellationToken token) + { + if (token.IsCancellationRequested) + { + yield break; + } + + for (var n = -1; n < WaveOut.DeviceCount; n++) + { + if (token.IsCancellationRequested) + { + yield break; + } + + var caps = WaveOut.GetCapabilities(n); + yield return new WaveOutDevice(caps); + } + } + + private IEnumerable GetDirectSound(CancellationToken token) + { + if (token.IsCancellationRequested) + { + yield break; + } + + foreach (var dev in DirectSoundOut.Devices) + { + if (token.IsCancellationRequested) + { + yield break; + } + + yield return new DirectSoundDevice(dev); + } + } + + private IEnumerable GetWasapi(CancellationToken token) + { + if (token.IsCancellationRequested) + { + yield break; + } + + var enumerator = new MMDeviceEnumerator(); + foreach (var wasapi in enumerator.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active)) + { + if (token.IsCancellationRequested) + { + yield break; + } + + yield return new WasapiDevice(wasapi); + } + } + + private IEnumerable GetAsio(CancellationToken token) + { + if (token.IsCancellationRequested) + { + yield break; + } + + foreach (var asio in AsioOut.GetDriverNames()) + { + if (token.IsCancellationRequested) + { + yield break; + } + + var device = default(AsioDevice); + + _dispatcher.Invoke(() => device = new AsioDevice(new AsioOut(asio))); + + if (device is null) + { + continue; + } + + yield return device; + } + } + } +} diff --git a/src/Maple/Features/Playback/AudioDevices/AudioDeviceProviderExtensions.cs b/src/Maple/Features/Playback/AudioDevices/AudioDeviceProviderExtensions.cs new file mode 100644 index 0000000..c32779b --- /dev/null +++ b/src/Maple/Features/Playback/AudioDevices/AudioDeviceProviderExtensions.cs @@ -0,0 +1,29 @@ +using Maple.Domain; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Maple +{ + public static class AudioDeviceProviderExtensions + { + public async static Task> Get(this IAudioDeviceProvider deviceProvider, CancellationToken token) + { + var results = new List(); + + var devices = await deviceProvider.Get(DeviceType.ASIO, token); + results.AddRange(devices); + + devices = await deviceProvider.Get(DeviceType.DirectSound, token); + results.AddRange(devices); + + devices = await deviceProvider.Get(DeviceType.WASAPI, token); + results.AddRange(devices); + + devices = await deviceProvider.Get(DeviceType.WaveOut, token); + results.AddRange(devices); + + return results; + } + } +} diff --git a/src/Maple/Features/Playback/AudioDevices/AudioDevices.cs b/src/Maple/Features/Playback/AudioDevices/AudioDevices.cs new file mode 100644 index 0000000..3f86e3c --- /dev/null +++ b/src/Maple/Features/Playback/AudioDevices/AudioDevices.cs @@ -0,0 +1,26 @@ +using MvvmScarletToolkit; +using MvvmScarletToolkit.Observables; + +namespace Maple +{ + public sealed class AudioDevices : ViewModelListBase + { + public AudioDevices(IScarletCommandBuilder commandBuilder) + : base(commandBuilder) + { + } + + public AudioDevice GetById(int? id) + { + for (var i = 0; i < Count; i++) + { + if (this[i].Id == id) + { + return this[i]; + } + } + + return null; + } + } +} diff --git a/src/Maple/Features/Playback/AudioDevices/CreateAudioDeviceViewModel.cs b/src/Maple/Features/Playback/AudioDevices/CreateAudioDeviceViewModel.cs new file mode 100644 index 0000000..06ca846 --- /dev/null +++ b/src/Maple/Features/Playback/AudioDevices/CreateAudioDeviceViewModel.cs @@ -0,0 +1,60 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using Maple.Domain; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Observables; + +namespace Maple +{ + public sealed class CreateAudioDeviceViewModel : ViewModelListBase + { + private readonly IAudioDeviceProvider _deviceProvider; + + private Domain.DeviceType _deviceType; + public Domain.DeviceType DeviceType + { + get { return _deviceType; } + set { SetValue(ref _deviceType, value); } + } + + public AudioDevice AudioDevice { get; } + + public ICommand LoadCommand { get; } + + public CreateAudioDeviceViewModel(IScarletCommandBuilder commandBuilder, IAudioDeviceProvider deviceProvider, AudioDevice audioDevice) + : base(commandBuilder) + { + _deviceProvider = deviceProvider ?? throw new ArgumentNullException(nameof(deviceProvider)); + + AudioDevice = audioDevice ?? throw new ArgumentNullException(nameof(audioDevice)); + + LoadCommand = CommandBuilder + .Create(Load, CanLoad) + .WithBusyNotification(BusyStack) + .WithSingleExecution() + .Build(); + } + + private async Task Load(CancellationToken token) + { + var asio = _deviceProvider.Get(Domain.DeviceType.ASIO, token); + var directSound = _deviceProvider.Get(Domain.DeviceType.DirectSound, token); + var wasapi = _deviceProvider.Get(Domain.DeviceType.WASAPI, token); + var waveout = _deviceProvider.Get(Domain.DeviceType.WaveOut, token); + + await Task.WhenAll(asio, directSound, wasapi, waveout); + + await AddRange(asio.Result); + await AddRange(directSound.Result); + await AddRange(wasapi.Result); + await AddRange(waveout.Result); + } + + private bool CanLoad() + { + return true; + } + } +} diff --git a/src/Maple/Features/Playback/AudioDevices/DirectSoundDevice.cs b/src/Maple/Features/Playback/AudioDevices/DirectSoundDevice.cs new file mode 100644 index 0000000..8f63ad8 --- /dev/null +++ b/src/Maple/Features/Playback/AudioDevices/DirectSoundDevice.cs @@ -0,0 +1,27 @@ +using System; +using System.Diagnostics; +using Maple.Domain; +using NAudio.Wave; + +namespace Maple +{ + [DebuggerDisplay("{" + nameof(GetDebuggerDisplay) + "(),nq}")] + internal sealed class DirectSoundDevice : AudioDevice + { + public DirectSoundDeviceInfo Device { get; } + + public DirectSoundDevice(DirectSoundDeviceInfo device) + : base(device?.Description) + { + Device = device ?? throw new ArgumentNullException(nameof(device)); + Name = device.Description; + + AudioDeviceTypeId = (int)Domain.DeviceType.DirectSound; + } + + private string GetDebuggerDisplay() + { + return $"{this.GetKey()} {Name} {nameof(DirectSoundDevice)}"; + } + } +} diff --git a/src/Maple/Features/Playback/AudioDevices/IAudioDeviceProvider.cs b/src/Maple/Features/Playback/AudioDevices/IAudioDeviceProvider.cs new file mode 100644 index 0000000..c88d863 --- /dev/null +++ b/src/Maple/Features/Playback/AudioDevices/IAudioDeviceProvider.cs @@ -0,0 +1,12 @@ +using Maple.Domain; +using System.Collections.ObjectModel; +using System.Threading; +using System.Threading.Tasks; + +namespace Maple +{ + public interface IAudioDeviceProvider + { + Task> Get(DeviceType type, CancellationToken token); + } +} diff --git a/src/Maple/Features/Playback/AudioDevices/WasapiDevice.cs b/src/Maple/Features/Playback/AudioDevices/WasapiDevice.cs new file mode 100644 index 0000000..a01a4e3 --- /dev/null +++ b/src/Maple/Features/Playback/AudioDevices/WasapiDevice.cs @@ -0,0 +1,27 @@ +using System; +using System.Diagnostics; +using Maple.Domain; +using NAudio.CoreAudioApi; + +namespace Maple +{ + [DebuggerDisplay("{" + nameof(GetDebuggerDisplay) + "(),nq}")] + internal sealed class WasapiDevice : AudioDevice + { + public MMDevice Device { get; } + + public WasapiDevice(MMDevice device) + : base(device?.FriendlyName) + { + Device = device ?? throw new ArgumentNullException(nameof(device)); + Name = device.FriendlyName; + + AudioDeviceTypeId = (int)Domain.DeviceType.WASAPI; + } + + private string GetDebuggerDisplay() + { + return $"{this.GetKey()} {Name} {nameof(WasapiDevice)}"; + } + } +} diff --git a/src/Maple/Features/Playback/AudioDevices/WaveOutDevice.cs b/src/Maple/Features/Playback/AudioDevices/WaveOutDevice.cs new file mode 100644 index 0000000..1512121 --- /dev/null +++ b/src/Maple/Features/Playback/AudioDevices/WaveOutDevice.cs @@ -0,0 +1,26 @@ +using Maple.Domain; +using NAudio.Wave; +using System.Diagnostics; + +namespace Maple +{ + [DebuggerDisplay("{" + nameof(GetDebuggerDisplay) + "(),nq}")] + internal sealed class WaveOutDevice : AudioDevice + { + public WaveOutCapabilities Device { get; } + + public WaveOutDevice(WaveOutCapabilities device) + : base(device.ProductName) + { + Name = device.ProductName; + Device = device; + + AudioDeviceTypeId = (int)Domain.DeviceType.WaveOut; + } + + private string GetDebuggerDisplay() + { + return $"{this.GetKey()} {Name} {nameof(WaveOutDevice)}"; + } + } +} diff --git a/src/Maple/Features/Playback/CompletedMediaItemMessage.cs b/src/Maple/Features/Playback/CompletedMediaItemMessage.cs new file mode 100644 index 0000000..5493d5b --- /dev/null +++ b/src/Maple/Features/Playback/CompletedMediaItemMessage.cs @@ -0,0 +1,13 @@ +using Maple.Domain; +using MvvmScarletToolkit; + +namespace Maple +{ + public class CompletedMediaItemMessage : GenericScarletMessage + { + public CompletedMediaItemMessage(object sender, IMediaItem mediaItem) + : base(sender, mediaItem) + { + } + } +} diff --git a/src/Maple/Features/Playback/MediaItems/MediaItem.cs b/src/Maple/Features/Playback/MediaItems/MediaItem.cs new file mode 100644 index 0000000..72550d7 --- /dev/null +++ b/src/Maple/Features/Playback/MediaItems/MediaItem.cs @@ -0,0 +1,154 @@ +using System; +using System.Diagnostics; +using Maple.Domain; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Observables; + +namespace Maple +{ + [DebuggerDisplay("MediaItem: {Sequence}, {Name}, {Location}")] + public sealed class MediaItem : ViewModelBase, IMediaItem + { + private int _id; + public int Id + { + get { return _id; } + private set { SetValue(ref _id, value); } + } + + private int _sequence; + public int Sequence + { + get { return _sequence; } + set { SetValue(ref _sequence, value); } + } + + private string _name; + public string Name + { + get { return _name; } + set { SetValue(ref _name, value); } + } + + private string _thumbnail; + public string Thumbnail + { + get { return _thumbnail; } + set { SetValue(ref _thumbnail, value); } + } + + private string _location; + public string Location + { + get { return _location; } + set { SetValue(ref _location, value); } + } + + private Playlist _playlist; + public Playlist Playlist + { + get { return _playlist; } + set { SetValue(ref _playlist, value); } + } + + private TimeSpan _duration; + public TimeSpan Duration + { + get { return _duration; } + set { SetValue(ref _duration, value); } + } + + private PrivacyStatus _privacyStatus; + public PrivacyStatus PrivacyStatus + { + get { return _privacyStatus; } + set { SetValue(ref _privacyStatus, value); } + } + + private MediaItemType _mediaItemType; + public MediaItemType MediaItemType + { + get { return _mediaItemType; } + set { SetValue(ref _mediaItemType, value); } + } + + private bool _isSelected; + public bool IsSelected + { + get { return _isSelected; } + set { SetValue(ref _isSelected, value); } + } + + private string _createdBy; + public string CreatedBy + { + get { return _createdBy; } + set { SetValue(ref _createdBy, value); } + } + + private string _updatedBy; + public string UpdatedBy + { + get { return _updatedBy; } + set { SetValue(ref _updatedBy, value); } + } + + private DateTime _updatedOn; + public DateTime UpdatedOn + { + get { return _updatedOn; } + set { SetValue(ref _updatedOn, value); } + } + + private DateTime _createdOn; + public DateTime CreatedOn + { + get { return _createdOn; } + set { SetValue(ref _createdOn, value); } + } + + private bool _isDeleted; + public bool IsDeleted + { + get { return _isDeleted; } + private set { SetValue(ref _isDeleted, value); } + } + + public MediaItem(IScarletCommandBuilder commandBuilder) + : base(commandBuilder) + { + } + + public MediaItem(MediaItem mediaItem) + : this(mediaItem.CommandBuilder) + { + Update(mediaItem); + + Playlist = mediaItem.Playlist; + } + + public MediaItem(IScarletCommandBuilder commandBuilder, MediaItemModel model, Playlist playlist) + : this(commandBuilder) + { + Update(model); + + Playlist = playlist; + } + + public void Update(IMediaItem model) + { + Id = model.Id; + Name = model.Name; + Sequence = model.Sequence; + + Duration = model.Duration; + MediaItemType = model.MediaItemType; + PrivacyStatus = model.PrivacyStatus; + + CreatedBy = model.CreatedBy; + CreatedOn = model.CreatedOn; + UpdatedBy = model.UpdatedBy; + UpdatedOn = model.UpdatedOn; + } + } +} diff --git a/src/Maple/Features/Playback/MediaItems/MediaItemValidator.cs b/src/Maple/Features/Playback/MediaItems/MediaItemValidator.cs new file mode 100644 index 0000000..d3baa98 --- /dev/null +++ b/src/Maple/Features/Playback/MediaItems/MediaItemValidator.cs @@ -0,0 +1,16 @@ +using FluentValidation; +using MvvmScarletToolkit.Abstractions; + +namespace Maple +{ + internal sealed class MediaItemValidator : BaseValidator, IValidator + { + public MediaItemValidator(ILocalizationService translationService) + : base(translationService) + { + RuleFor(mediaItem => mediaItem.Name).NotEmpty(); // TODO finalize Validator configuration + RuleFor(mediaItem => mediaItem.Thumbnail).NotEmpty().Length(0, 260); // max windows path length https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file + RuleFor(mediaItem => mediaItem.Location).NotEmpty().Length(0, 260); // max windows path length https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file + } + } +} diff --git a/src/Maple/Features/Playback/MediaPlayers/CreateMediaPlayerDialog.xaml b/src/Maple/Features/Playback/MediaPlayers/CreateMediaPlayerDialog.xaml new file mode 100644 index 0000000..2c37149 --- /dev/null +++ b/src/Maple/Features/Playback/MediaPlayers/CreateMediaPlayerDialog.xaml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Maple/Features/Playback/MediaPlayers/MediaPlayerPlaybackControl.xaml.cs b/src/Maple/Features/Playback/MediaPlayers/MediaPlayerPlaybackControl.xaml.cs new file mode 100644 index 0000000..1b45c3b --- /dev/null +++ b/src/Maple/Features/Playback/MediaPlayers/MediaPlayerPlaybackControl.xaml.cs @@ -0,0 +1,10 @@ +namespace Maple +{ + public partial class MediaPlayerPlaybackControl + { + public MediaPlayerPlaybackControl() + { + InitializeComponent(); + } + } +} diff --git a/src/Maple/Features/Playback/MediaPlayers/MediaPlayerValidator.cs b/src/Maple/Features/Playback/MediaPlayers/MediaPlayerValidator.cs new file mode 100644 index 0000000..386284f --- /dev/null +++ b/src/Maple/Features/Playback/MediaPlayers/MediaPlayerValidator.cs @@ -0,0 +1,14 @@ +using FluentValidation; +using MvvmScarletToolkit.Abstractions; + +namespace Maple +{ + internal sealed class MediaPlayerValidator : BaseValidator, IValidator + { + public MediaPlayerValidator(ILocalizationService translationService) + : base(translationService) + { + RuleFor(mediaPlayer => mediaPlayer.Name).NotEmpty(); // TODO finalize Validator configuration + } + } +} diff --git a/src/Maple/Features/Playback/MediaPlayers/MediaPlayers.cs b/src/Maple/Features/Playback/MediaPlayers/MediaPlayers.cs new file mode 100644 index 0000000..06fa28b --- /dev/null +++ b/src/Maple/Features/Playback/MediaPlayers/MediaPlayers.cs @@ -0,0 +1,34 @@ +using System; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Observables; + +namespace Maple +{ + public sealed class MediaPlayers : ViewModelListBase + { + private readonly MediaPlayerFactory _mediaPlayerFactory; + + private MediaPlayer _main; + public MediaPlayer Main + { + get { return _main; } + private set { SetValue(ref _main, value); } + } + + public MediaPlayers(IScarletCommandBuilder commandBuilder, MediaPlayerFactory mediaPlayerFactory) + : base(commandBuilder) + { + _mediaPlayerFactory = mediaPlayerFactory ?? throw new ArgumentNullException(nameof(mediaPlayerFactory)); + } + + internal CreateMediaPlayerViewModel Create() + { + return _mediaPlayerFactory.Create(); + } + + internal CreateMediaPlayerViewModel Create(MediaPlayer mediaPlayer) + { + return _mediaPlayerFactory.Create(mediaPlayer); + } + } +} diff --git a/src/Maple/Features/Playback/MediaPlayers/MediaPlayersValidator.cs b/src/Maple/Features/Playback/MediaPlayers/MediaPlayersValidator.cs new file mode 100644 index 0000000..b6f04e1 --- /dev/null +++ b/src/Maple/Features/Playback/MediaPlayers/MediaPlayersValidator.cs @@ -0,0 +1,13 @@ +using FluentValidation; +using MvvmScarletToolkit.Abstractions; + +namespace Maple +{ + internal sealed class MediaPlayersValidator : BaseValidator, IValidator + { + public MediaPlayersValidator(ILocalizationService translationService) + : base(translationService) + { + } + } +} diff --git a/src/Maple/Features/Playback/MediaPlayers/MediaPlayersView.xaml b/src/Maple/Features/Playback/MediaPlayers/MediaPlayersView.xaml new file mode 100644 index 0000000..046b77f --- /dev/null +++ b/src/Maple/Features/Playback/MediaPlayers/MediaPlayersView.xaml @@ -0,0 +1,275 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Maple/Features/Playback/MediaPlayers/MediaPlayersView.xaml.cs b/src/Maple/Features/Playback/MediaPlayers/MediaPlayersView.xaml.cs new file mode 100644 index 0000000..82cb14a --- /dev/null +++ b/src/Maple/Features/Playback/MediaPlayers/MediaPlayersView.xaml.cs @@ -0,0 +1,154 @@ +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Input; +using MvvmScarletToolkit; + +namespace Maple +{ + public partial class MediaPlayersView + { + public ICommand CreateCommand + { + get { return (ICommand)GetValue(CreateCommandProperty); } + set { SetValue(CreateCommandProperty, value); } + } + + public static readonly DependencyProperty CreateCommandProperty = DependencyProperty.Register( + nameof(CreateCommand), + typeof(ICommand), + typeof(MediaPlayersView), + new PropertyMetadata(default(ICommand))); + + public ICommand UpdateCommand + { + get { return (ICommand)GetValue(UpdateCommandProperty); } + set { SetValue(UpdateCommandProperty, value); } + } + + public static readonly DependencyProperty UpdateCommandProperty = DependencyProperty.Register( + nameof(UpdateCommand), + typeof(ICommand), + typeof(MediaPlayersView), + new PropertyMetadata(default(ICommand))); + + public ICommand AddFromFileCommand + { + get { return (ICommand)GetValue(AddFromFileCommandProperty); } + set { SetValue(AddFromFileCommandProperty, value); } + } + + public static readonly DependencyProperty AddFromFileCommandProperty = DependencyProperty.Register( + nameof(AddFromFileCommand), + typeof(ICommand), + typeof(MediaPlayersView), + new PropertyMetadata(default(ICommand))); + + public ICommand AddFromUrlCommand + { + get { return (ICommand)GetValue(AddFromUrlCommandProperty); } + set { SetValue(AddFromUrlCommandProperty, value); } + } + + public static readonly DependencyProperty AddFromUrlCommandProperty = DependencyProperty.Register( + nameof(AddFromUrlCommand), + typeof(ICommand), + typeof(MediaPlayersView), + new PropertyMetadata(default(ICommand))); + + public ICommand AddFromFolderCommand + { + get { return (ICommand)GetValue(AddFromFolderCommandProperty); } + set { SetValue(AddFromFolderCommandProperty, value); } + } + + public static readonly DependencyProperty AddFromFolderCommandProperty = DependencyProperty.Register( + nameof(AddFromFolderCommand), + typeof(ICommand), + typeof(MediaPlayersView), + new PropertyMetadata(default(ICommand))); + + private Shell _shell; + + public MediaPlayersView() + { + InitializeComponent(); + } + + private void MediaPlayersView_Loaded(object sender, RoutedEventArgs e) + { + _shell = this.FindParent(); + + CreateCommand = _shell.CommandBuilder.Create(Create, CanCreate) + .WithAsyncCancellation() + .WithSingleExecution() + .Build(); + + UpdateCommand = _shell.CommandBuilder.Create(Update, CanUpdate) + .WithAsyncCancellation() + .WithSingleExecution() + .Build(); + } + + private async Task Create(CancellationToken token) + { + if (!(DataContext is MediaPlayers itemsViewModel)) + { + return; + } + + if (_shell is null) + { + return; + } + + var viewModel = itemsViewModel.Create(); + + var dlg = new CreateMediaPlayerDialog(viewModel, _shell, token); + + var result = dlg.ShowDialog(); + if (result.HasValue && result.Value) + { + await itemsViewModel.Add(viewModel.MediaPlayer); + } + } + + private bool CanCreate() + { + return _shell != null && DataContext is MediaPlayers; + } + + private async Task Update(CancellationToken token) + { + if (!(DataContext is MediaPlayers itemsViewModel)) + { + return; + } + + if (_shell is null) + { + return; + } + + var oldInstance = itemsViewModel.SelectedItem; + var newInstance = new MediaPlayer(itemsViewModel.SelectedItem); + + var dialogViewModel = itemsViewModel.Create(newInstance); + var dlg = new CreateMediaPlayerDialog(dialogViewModel, _shell, token); + + var result = dlg.ShowDialog(); + if (result.HasValue && result.Value) + { + await itemsViewModel.Add(newInstance); + await itemsViewModel.Remove(oldInstance); + + itemsViewModel.SelectedItem = newInstance; + } + } + + private bool CanUpdate() + { + return _shell != null && DataContext is MediaPlayers itemsViewModel && itemsViewModel.SelectedItem != null; + } + } +} diff --git a/src/Maple/Features/Playback/PlaybackView.xaml b/src/Maple/Features/Playback/PlaybackView.xaml new file mode 100644 index 0000000..3bed948 --- /dev/null +++ b/src/Maple/Features/Playback/PlaybackView.xaml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Maple/Features/Playback/PlaybackView.xaml.cs b/src/Maple/Features/Playback/PlaybackView.xaml.cs new file mode 100644 index 0000000..83ec4d1 --- /dev/null +++ b/src/Maple/Features/Playback/PlaybackView.xaml.cs @@ -0,0 +1,10 @@ +namespace Maple +{ + public partial class PlaybackView + { + public PlaybackView() + { + InitializeComponent(); + } + } +} diff --git a/src/Maple/Features/Playback/PlaybackViewModel.cs b/src/Maple/Features/Playback/PlaybackViewModel.cs new file mode 100644 index 0000000..7cb04bf --- /dev/null +++ b/src/Maple/Features/Playback/PlaybackViewModel.cs @@ -0,0 +1,22 @@ +using System; +using MvvmScarletToolkit.Observables; + +namespace Maple +{ + public sealed class PlaybackViewModel : ObservableObject + { + public MediaPlayers MediaPlayers { get; } + + private MediaPlayer _selectedMediaPlayer; + public MediaPlayer SelectedMediaPlayer + { + get { return _selectedMediaPlayer; } + set { SetValue(ref _selectedMediaPlayer, value); } + } + + public PlaybackViewModel(MediaPlayers mediaPlayers) + { + MediaPlayers = mediaPlayers ?? throw new ArgumentNullException(nameof(mediaPlayers)); + } + } +} diff --git a/src/Maple.Core/Messages/PlayingMediaItemMessage.cs b/src/Maple/Features/Playback/PlayingMediaItemMessage.cs similarity index 63% rename from src/Maple.Core/Messages/PlayingMediaItemMessage.cs rename to src/Maple/Features/Playback/PlayingMediaItemMessage.cs index 08f17bd..3c6475a 100644 --- a/src/Maple.Core/Messages/PlayingMediaItemMessage.cs +++ b/src/Maple/Features/Playback/PlayingMediaItemMessage.cs @@ -1,10 +1,12 @@ -using Maple.Domain; +using Maple.Domain; +using MvvmScarletToolkit; -namespace Maple.Core +namespace Maple { - public class PlayingMediaItemMessage : GenericMapleMessage + public class PlayingMediaItemMessage : GenericScarletMessage { public int PlaylistId { get; } + public PlayingMediaItemMessage(object sender, IMediaItem mediaItem, int playlistId) : base(sender, mediaItem) { diff --git a/src/Maple/Features/Playback/Playlists/CreatePlaylistDialog.xaml b/src/Maple/Features/Playback/Playlists/CreatePlaylistDialog.xaml new file mode 100644 index 0000000..5477ef0 --- /dev/null +++ b/src/Maple/Features/Playback/Playlists/CreatePlaylistDialog.xaml @@ -0,0 +1,210 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Maple/Features/Playback/Playlists/CreatePlaylistDialog.xaml.cs b/src/Maple/Features/Playback/Playlists/CreatePlaylistDialog.xaml.cs new file mode 100644 index 0000000..02bc66f --- /dev/null +++ b/src/Maple/Features/Playback/Playlists/CreatePlaylistDialog.xaml.cs @@ -0,0 +1,102 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Input; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Abstractions; + +namespace Maple +{ + public partial class CreatePlaylistDialog : DialogWindow + { + private readonly CreatePlaylistViewModel _viewModel; + + public ICommand SelectThumbnailCommand + { + get { return (ICommand)GetValue(SelectThumbnailCommandProperty); } + set { SetValue(SelectThumbnailCommandProperty, value); } + } + + public static readonly DependencyProperty SelectThumbnailCommandProperty = DependencyProperty.Register( + nameof(SelectThumbnailCommand), + typeof(ICommand), + typeof(CreatePlaylistDialog), + new PropertyMetadata(default(ICommand))); + + public ICommand MonstercatImportCommand + { + get { return (ICommand)GetValue(MonstercatImportCommandProperty); } + set { SetValue(MonstercatImportCommandProperty, value); } + } + + public static readonly DependencyProperty MonstercatImportCommandProperty = DependencyProperty.Register( + nameof(MonstercatImportCommand), + typeof(ICommand), + typeof(CreatePlaylistDialog), + new PropertyMetadata(default(ICommand))); + + public CreatePlaylistDialog() + { + InitializeComponent(); + } + + public CreatePlaylistDialog(IScarletCommandBuilder commandBuilder, ILocalizationService localizationService, CreatePlaylistViewModel viewModel, Window owner, CancellationToken abort) + : base(commandBuilder, localizationService, owner, abort) + { + _viewModel = viewModel ?? throw new ArgumentNullException(nameof(viewModel)); + + InitializeComponent(); + + DataContext = viewModel; + + SelectThumbnailCommand = commandBuilder + .Create(SelectThumbnail, CanSelectThumbnail) + .WithAsyncCancellation() + .WithSingleExecution() + .Build(); + + MonstercatImportCommand = commandBuilder + .Create(MonstercatImport, CanMonstercatImport) + .WithAsyncCancellation() + .WithSingleExecution() + .Build(); + } + + public CreatePlaylistDialog(CreatePlaylistViewModel dataContext, IoCWindow owner, CancellationToken abort) + : this(owner.CommandBuilder, owner.LocalizationService, dataContext, owner, abort) + { + } + + protected override bool CanAccept() + { + return _viewModel.CanSave() && base.CanAccept(); + } + + private Task SelectThumbnail(CancellationToken token) + { + var dlg = new FileSystemBrowserDialog(this, token, _viewModel.FileSystemViewModel); + dlg.ShowDialog(); + + return Task.CompletedTask; + } + + private bool CanSelectThumbnail() + { + return true; // TODO ? + } + + private Task MonstercatImport(CancellationToken token) + { + var dlg = new MonstercatImportDialog(this, token, _viewModel.Monstercat); + dlg.ShowDialog(); + + return Task.CompletedTask; + } + + private bool CanMonstercatImport() // TODO ? + { + return true; + } + } +} diff --git a/src/Maple/Features/Playback/Playlists/CreatePlaylistViewModel.cs b/src/Maple/Features/Playback/Playlists/CreatePlaylistViewModel.cs new file mode 100644 index 0000000..e210507 --- /dev/null +++ b/src/Maple/Features/Playback/Playlists/CreatePlaylistViewModel.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.ObjectModel; +using FluentValidation; +using FluentValidation.Results; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Observables; +using MvvmScarletToolkit.Wpf.FileSystemBrowser; + +namespace Maple +{ + public sealed class CreatePlaylistViewModel : ObservableObject + { + private readonly ObservableCollection _errors; + public Playlists Playlists { get; } + public Playlist Playlist { get; } + + public IValidator PlaylistValidator { get; } + public FileSystemViewModel FileSystemViewModel { get; } + public MonstercatImportViewModel Monstercat { get; } + public ReadOnlyObservableCollection Errors { get; } + + private ValidationFailure _error; + public ValidationFailure Error + { + get { return _error; } + set { SetValue(ref _error, value); } + } + + public CreatePlaylistViewModel(Playlists playlists, Playlist playlist, IValidator playlistValidator, Func fileSystemViewModelFactory, MonstercatImportViewModel monstercat) + { + Playlists = playlists ?? throw new ArgumentNullException(nameof(playlists)); + Playlist = playlist ?? throw new ArgumentNullException(nameof(playlist)); + PlaylistValidator = playlistValidator ?? throw new ArgumentNullException(nameof(playlistValidator)); + Monstercat = monstercat ?? throw new ArgumentNullException(nameof(monstercat)); + FileSystemViewModel = fileSystemViewModelFactory(); + + _errors = new ObservableCollection(); + Errors = new ReadOnlyObservableCollection(_errors); + } + + public bool CanSave() + { + var result = PlaylistValidator.Validate(Playlist); + + _errors.UpdateItems(result.Errors, Comparer, Mapper); + + if (!result.IsValid) + { + Error = _errors[0]; + } + else + { + Error = null; + } + + return result.IsValid; + } + + private bool Comparer(ValidationFailure @old, ValidationFailure @new) + { + return old.PropertyName == @new.PropertyName + && old.ErrorMessage == @new.ErrorMessage; + } + + private ValidationFailure Mapper(ValidationFailure list) + { + return list; + } + } +} diff --git a/src/Maple/Features/Playback/Playlists/ManagePlaylistView.xaml b/src/Maple/Features/Playback/Playlists/ManagePlaylistView.xaml new file mode 100644 index 0000000..f566809 --- /dev/null +++ b/src/Maple/Features/Playback/Playlists/ManagePlaylistView.xaml @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Maple/Features/Playback/Playlists/ManagePlaylistView.xaml.cs b/src/Maple/Features/Playback/Playlists/ManagePlaylistView.xaml.cs new file mode 100644 index 0000000..a5b4eb2 --- /dev/null +++ b/src/Maple/Features/Playback/Playlists/ManagePlaylistView.xaml.cs @@ -0,0 +1,12 @@ +using System.Windows.Controls; + +namespace Maple +{ + public partial class ManagePlaylistView : UserControl + { + public ManagePlaylistView() + { + InitializeComponent(); + } + } +} diff --git a/src/Maple/Features/Playback/Playlists/Playlist.cs b/src/Maple/Features/Playback/Playlists/Playlist.cs new file mode 100644 index 0000000..76978c8 --- /dev/null +++ b/src/Maple/Features/Playback/Playlists/Playlist.cs @@ -0,0 +1,320 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using FluentValidation; +using Maple.Domain; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Observables; + +namespace Maple +{ + [DebuggerDisplay("{Name}, {Sequence}")] + public sealed class Playlist : ViewModelListBase, IPlaylist + { + private readonly Stack _history; + + private int _id; + public int Id + { + get { return _id; } + private set { SetValue(ref _id, value); } + } + + private int _sequence; + public int Sequence + { + get { return _sequence; } + set { SetValue(ref _sequence, value); } + } + + private string _name; + public string Name + { + get { return _name; } + set { SetValue(ref _name, value); } + } + + private bool _isSelected; + public bool IsSelected + { + get { return _isSelected; } + set { SetValue(ref _isSelected, value); } + } + + private bool _isShuffeling; + public bool IsShuffeling + { + get { return _isShuffeling; } + set { SetValue(ref _isShuffeling, value); } + } + + private PrivacyStatus _privacyStatus; + public PrivacyStatus PrivacyStatus + { + get { return _privacyStatus; } + set { SetValue(ref _privacyStatus, value); } + } + + private RepeatMode _repeatMode; + public RepeatMode RepeatMode + { + get { return _repeatMode; } + set { SetValue(ref _repeatMode, value); } + } + + private string _createdBy; + public string CreatedBy + { + get { return _createdBy; } + private set { SetValue(ref _createdBy, value); } + } + + private string _updatedBy; + public string UpdatedBy + { + get { return _updatedBy; } + private set { SetValue(ref _updatedBy, value); } + } + + private DateTime _updatedOn; + public DateTime UpdatedOn + { + get { return _updatedOn; } + private set { SetValue(ref _updatedOn, value); } + } + + private DateTime _createdOn; + public DateTime CreatedOn + { + get { return _createdOn; } + private set { SetValue(ref _createdOn, value); } + } + + private bool _isDeleted; + public bool IsDeleted + { + get { return _isDeleted; } + private set { SetValue(ref _isDeleted, value); } + } + + /// + /// default + /// + public Playlist(IScarletCommandBuilder commandBuilder) + : base(commandBuilder) + { + _history = new Stack(); + } + + /// + /// copy constructor + /// + public Playlist(Playlist playlist) + : this(playlist.CommandBuilder) + { + Update(playlist); + + for (var i = 0; i < playlist.Count; i++) + { + var item = playlist[i]; + + AddUnchecked(item); + item.Playlist = this; + } + } + + /// + /// ctor for turning a model into a VM + /// + public Playlist(IScarletCommandBuilder commandBuilder, PlaylistModel model) + : this(commandBuilder) + { + Update(model); + + for (var i = 0; i < model.MediaItems.Count; i++) + { + var item = model.MediaItems[i]; + AddUnchecked(new MediaItem(commandBuilder, item, this)); + } + } + + public void Update(IPlaylist model) + { + Id = model.Id; + Name = model.Name; + Sequence = model.Sequence; + + PrivacyStatus = model.PrivacyStatus; + RepeatMode = model.RepeatMode; + IsShuffeling = model.IsShuffeling; + + CreatedBy = model.CreatedBy; + CreatedOn = model.CreatedOn; + UpdatedBy = model.UpdatedBy; + UpdatedOn = model.UpdatedOn; + } + + /// + /// Returns the next MediaItem from the Items collection according to their respective sequence and the current RepeatMode + /// + /// + public MediaItem Next() + { + using (BusyStack.GetToken()) + { + if (Items != null && Items.Any()) + { + return RepeatMode switch + { + RepeatMode.All => IsShuffeling ? NextShuffle() : NextRepeatAll(), + + RepeatMode.None => IsShuffeling ? NextShuffle() : NextRepeatNone(), + + RepeatMode.Single => NextRepeatSingle(), + + _ => throw new NotImplementedException(nameof(RepeatMode)), + }; + } + + return null; + } + } + + private MediaItem NextRepeatNone() + { + var currentIndex = 0; + if (SelectedItem?.Sequence != null) + { + currentIndex = SelectedItem?.Sequence ?? 0; + } + + if (Items.Count > 1) + { + var nextPossibleItems = Items.Where(p => p.Sequence > currentIndex); + + if (nextPossibleItems?.Any() == true) // try to find items after the current one + { + Items.ToList().ForEach(p => p.IsSelected = false); + var foundItem = nextPossibleItems.Where(q => q.Sequence == nextPossibleItems.Select(p => p.Sequence).Min()).First(); + foundItem.IsSelected = true; + return foundItem; + } + + return null; + // we dont repeat, so there is nothing to do here + } + else + { + return NextRepeatSingle(); + } + } + + private MediaItem NextRepeatSingle() + { + if (RepeatMode != RepeatMode.None) + { + return SelectedItem; + } + else + { + return null; + } + } + + private MediaItem NextRepeatAll() + { + var currentIndex = 0; + if (SelectedItem?.Sequence != null) + { + currentIndex = SelectedItem?.Sequence ?? 0; + } + + if (Items.Count > 1) + { + var nextPossibleItems = Items.Where(p => p.Sequence > currentIndex); + + if (nextPossibleItems.Any()) // try to find items after the current one + { + Items.ToList().ForEach(p => p.IsSelected = false); + var foundItem = nextPossibleItems.Where(q => q.Sequence == nextPossibleItems.Select(p => p.Sequence).Min()).First(); + foundItem.IsSelected = true; + + return foundItem; + } + else // if there are none, use the first item in the list + { + Items.ToList().ForEach(p => p.IsSelected = false); + var foundItem = Items.First(); + foundItem.IsSelected = true; + + return foundItem; + } + } + else + { + return NextRepeatSingle(); + } + } + + private MediaItem NextShuffle() + { + if (Items.Count > 1) + { + var nextItems = Items.Where(p => p.Sequence != SelectedItem?.Sequence); // get all items besides the current one + Items.ToList().ForEach(p => p.IsSelected = false); + var foundItem = nextItems.Random(); + foundItem.IsSelected = true; + + return foundItem; + } + else + { + return NextRepeatSingle(); + } + } + + public MediaItem Previous() + { + using (BusyStack.GetToken()) + { + Items.ToList().ForEach(p => p.IsSelected = false); // deselect all items in the list + + if (_history?.Any() == true) + { + while (_history.Any()) + { + var previous = _history.Pop(); + + //if (previous == SelectedItem?.Sequence) // the most recent item in the history, is the just played item, so we wanna skip that + // continue; + + if (previous > -1) + { + var previousItems = Items.Where(p => p.Sequence == previous); // try to get the last played item + if (previousItems.Any()) + { + var foundItem = previousItems.First(); + foundItem.IsSelected = true; + + return foundItem; + } + } + } + } + + return null; + } + } + + public bool CanNext() + { + return Items != null && Items.Any(); + } + + public bool CanPrevious() + { + return _history != null && _history.Any(); + } + } +} diff --git a/src/Maple/Features/Playback/Playlists/PlaylistFactory.cs b/src/Maple/Features/Playback/Playlists/PlaylistFactory.cs new file mode 100644 index 0000000..7ffa296 --- /dev/null +++ b/src/Maple/Features/Playback/Playlists/PlaylistFactory.cs @@ -0,0 +1,41 @@ +using FluentValidation; +using Maple.Domain; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Wpf.FileSystemBrowser; +using System; + +namespace Maple +{ + public sealed class PlaylistFactory + { + private readonly IScarletCommandBuilder _commandBuilder; + private readonly IValidator _validator; + private readonly Func _fileSystemViewModelFactory; + private readonly MonstercatImportViewModel _monstercatImport; + + public PlaylistFactory(IScarletCommandBuilder commandBuilder, IValidator validator, Func fileSystemViewModelFactory, MonstercatImportViewModel monstercatImport) + { + _commandBuilder = commandBuilder ?? throw new ArgumentNullException(nameof(commandBuilder)); + _validator = validator ?? throw new ArgumentNullException(nameof(validator)); + _fileSystemViewModelFactory = fileSystemViewModelFactory ?? throw new ArgumentNullException(nameof(fileSystemViewModelFactory)); + _monstercatImport = monstercatImport ?? throw new ArgumentNullException(nameof(monstercatImport)); + } + + public Playlist Create(PlaylistModel model) + { + return new Playlist(_commandBuilder, model); + } + + public CreatePlaylistViewModel Create(Playlists playlists) + { + var playerViewModel = new Playlist(new Playlist(_commandBuilder)); + + return Create(playlists, playerViewModel); + } + + public CreatePlaylistViewModel Create(Playlists playlists, Playlist playlist) + { + return new CreatePlaylistViewModel(playlists, playlist, _validator, _fileSystemViewModelFactory, _monstercatImport); + } + } +} diff --git a/src/Maple/Features/Playback/Playlists/PlaylistValidator.cs b/src/Maple/Features/Playback/Playlists/PlaylistValidator.cs new file mode 100644 index 0000000..831976c --- /dev/null +++ b/src/Maple/Features/Playback/Playlists/PlaylistValidator.cs @@ -0,0 +1,22 @@ +using FluentValidation; +using MvvmScarletToolkit.Abstractions; + +namespace Maple +{ + internal sealed class PlaylistValidator : BaseValidator, IValidator + { + public PlaylistValidator(ILocalizationService translationService, IValidator mediaItemValidator) + : base(translationService) + { + RuleFor(playlist => playlist.Name).NotEmpty(); + RuleFor(playlist => playlist.Name).Length(1, 64); + + RuleFor(playlist => playlist.PrivacyStatus).NotNull(); + + RuleFor(playlist => playlist.RepeatMode).NotNull(); + + RuleFor(playlist => playlist.Items).NotNull(); + RuleForEach(playlist => playlist.Items).SetValidator(mediaItemValidator); + } + } +} diff --git a/src/Maple/Features/Playback/Playlists/Playlists.cs b/src/Maple/Features/Playback/Playlists/Playlists.cs new file mode 100644 index 0000000..c7a983e --- /dev/null +++ b/src/Maple/Features/Playback/Playlists/Playlists.cs @@ -0,0 +1,100 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Observables; + +namespace Maple +{ + public sealed class Playlists : ViewModelListBase + { + private readonly PlaylistFactory _playlistFactory; + + public ICommand CreateCommand { get; } + public ICommand UpdateCommand { get; } + + public Func CanCreateCallback { get; set; } + public Func CreateCallback { get; set; } + + public Func CanUpdateCallback { get; set; } + public Func UpdateCallback { get; set; } + + public Playlists(IScarletCommandBuilder commandBuilder, PlaylistFactory playlistFactory) + : base(commandBuilder) + { + _playlistFactory = playlistFactory; + + CreateCommand = CommandBuilder.Create(CreatePlaylist, CanCreatePlaylist) + .WithAsyncCancellation() + .WithSingleExecution() + .Build(); + + UpdateCommand = CommandBuilder.Create(Update, CanUpdate) + .WithAsyncCancellation() + .WithSingleExecution() + .Build(); + } + + internal CreatePlaylistViewModel Create() + { + return _playlistFactory.Create(this); + } + + internal CreatePlaylistViewModel Create(Playlist playlist) + { + return _playlistFactory.Create(this, playlist); + } + + private async Task CreatePlaylist(CancellationToken token) + { + var dialogViewModel = Create(); + + var result = CreateCallback?.Invoke(dialogViewModel, token); + if (result.HasValue && result.Value) + { + await Add(dialogViewModel.Playlist); + } + } + + private bool CanCreatePlaylist() + { + return !IsBusy && CanCreateCallback?.Invoke() == true; + } + + private async Task Update(CancellationToken token) + { + var oldInstance = SelectedItem; + var newInstance = new Playlist(SelectedItem); + + var dialogViewModel = Create(newInstance); + + var result = UpdateCallback?.Invoke(dialogViewModel, token); + if (result.HasValue && result.Value) + { + await Add(newInstance); + await Remove(oldInstance); + + SelectedItem = newInstance; + } + } + + private bool CanUpdate() + { + return !IsBusy && SelectedItem != null && CanUpdateCallback?.Invoke() == true; + } + + public Playlist GetById(int? id) + { + for (var i = 0; i < Count; i++) + { + if (this[i].Id == id) + { + return this[i]; + } + } + + return null; + } + } +} diff --git a/src/Maple/Features/Playback/Playlists/PlaylistsValidator.cs b/src/Maple/Features/Playback/Playlists/PlaylistsValidator.cs new file mode 100644 index 0000000..c98d8d7 --- /dev/null +++ b/src/Maple/Features/Playback/Playlists/PlaylistsValidator.cs @@ -0,0 +1,15 @@ +using FluentValidation; +using MvvmScarletToolkit.Abstractions; + +namespace Maple +{ + internal sealed class PlaylistsValidator : BaseValidator + { + public PlaylistsValidator(ILocalizationService translationService, IValidator playlistValidator) + : base(translationService) + { + RuleFor(playlists => playlists.Items).NotNull(); + RuleForEach(playlists => playlists.Items).SetValidator(playlistValidator); + } + } +} diff --git a/src/Maple/Features/Playback/Playlists/PlaylistsView.xaml b/src/Maple/Features/Playback/Playlists/PlaylistsView.xaml new file mode 100644 index 0000000..7e56e46 --- /dev/null +++ b/src/Maple/Features/Playback/Playlists/PlaylistsView.xaml @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Maple/Features/Playback/Playlists/PlaylistsView.xaml.cs b/src/Maple/Features/Playback/Playlists/PlaylistsView.xaml.cs new file mode 100644 index 0000000..cba51a4 --- /dev/null +++ b/src/Maple/Features/Playback/Playlists/PlaylistsView.xaml.cs @@ -0,0 +1,78 @@ +using System.Threading; +using System.Windows; +using MvvmScarletToolkit; + +namespace Maple +{ + public partial class PlaylistsView + { + private Shell _shell; + private Playlists _playlists; + + public PlaylistsView() + { + InitializeComponent(); + } + + private void PlaylistsView_Loaded(object sender, RoutedEventArgs e) + { + _shell = this.FindParent(); + + if (_shell is null) + { + return; + } + + if (!(DataContext is Playlists playlists)) + { + return; + } + + _playlists = playlists; + + _playlists.CanCreateCallback += CanCreate; + _playlists.CreateCallback += Create; + + _playlists.CanUpdateCallback += CanUpdate; + _playlists.UpdateCallback += Update; + } + + private void PlaylistsView_Unloaded(object sender, RoutedEventArgs e) + { + if (_playlists is null) + { + return; + } + + _playlists.CreateCallback -= Create; + _playlists.CanCreateCallback -= CanCreate; + + _playlists.UpdateCallback -= Update; + _playlists.CanUpdateCallback -= CanUpdate; + } + + private bool? Create(CreatePlaylistViewModel viewModel, CancellationToken token) + { + var dlg = new CreatePlaylistDialog(viewModel, _shell, token); + + return dlg.ShowDialog(); + } + + private bool CanCreate() + { + return _shell != null; + } + + private bool? Update(CreatePlaylistViewModel viewModel, CancellationToken token) + { + var dlg = new CreatePlaylistDialog(viewModel, _shell, token); + + return dlg.ShowDialog(); + } + + private bool CanUpdate() + { + return _shell != null; + } + } +} diff --git a/src/Maple/Features/Playback/RepeatModeChangedMessage.cs b/src/Maple/Features/Playback/RepeatModeChangedMessage.cs new file mode 100644 index 0000000..2e29038 --- /dev/null +++ b/src/Maple/Features/Playback/RepeatModeChangedMessage.cs @@ -0,0 +1,13 @@ +using Maple.Domain; +using MvvmScarletToolkit; + +namespace Maple +{ + public class RepeatModeChangedMessage : GenericScarletMessage + { + public RepeatModeChangedMessage(object sender, RepeatMode content) + : base(sender, content) + { + } + } +} diff --git a/src/Maple/Features/Playback/RepeatModeControl.xaml b/src/Maple/Features/Playback/RepeatModeControl.xaml new file mode 100644 index 0000000..f06c7e0 --- /dev/null +++ b/src/Maple/Features/Playback/RepeatModeControl.xaml @@ -0,0 +1,66 @@ + + + + diff --git a/src/Maple/Features/Playback/RepeatModeControl.xaml.cs b/src/Maple/Features/Playback/RepeatModeControl.xaml.cs new file mode 100644 index 0000000..ea542bd --- /dev/null +++ b/src/Maple/Features/Playback/RepeatModeControl.xaml.cs @@ -0,0 +1,62 @@ +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using Maple.Domain; +using MvvmScarletToolkit; + +namespace Maple +{ + public partial class RepeatModeControl : UserControl + { + public ICommand ToggleCommand + { + get { return (ICommand)GetValue(ToggleCommandProperty); } + set { SetValue(ToggleCommandProperty, value); } + } + + public static readonly DependencyProperty ToggleCommandProperty = DependencyProperty.Register( + nameof(ToggleCommand), + typeof(ICommand), + typeof(RepeatModeControl), + new PropertyMetadata(default(ICommand))); + + private Shell _shell; + + public RepeatModeControl() + { + InitializeComponent(); + } + + private void RepeatModeControl_Loaded(object sender, RoutedEventArgs e) + { + _shell = this.FindParent(); + + ToggleCommand = _shell.CommandBuilder.Create(Toggle, CanToggle) + .WithSingleExecution() + .Build(); + } + + private Task Toggle(CancellationToken token) + { + if (!(DataContext is RepeatMode mode)) + { + return Task.CompletedTask; + } + + return mode switch + { + RepeatMode.None => _shell.Invoke(() => DataContext = RepeatMode.Single, token), + RepeatMode.Single => _shell.Invoke(() => DataContext = RepeatMode.All, token), + RepeatMode.All => _shell.Invoke(() => DataContext = RepeatMode.None, token), + _ => Task.CompletedTask, + }; + } + + private bool CanToggle() + { + return DataContext is RepeatMode; + } + } +} diff --git a/src/Maple.Core/Services/SequenceService.cs b/src/Maple/Features/Playback/SequenceService.cs similarity index 55% rename from src/Maple.Core/Services/SequenceService.cs rename to src/Maple/Features/Playback/SequenceService.cs index ea6998e..aa1c127 100644 --- a/src/Maple.Core/Services/SequenceService.cs +++ b/src/Maple/Features/Playback/SequenceService.cs @@ -1,18 +1,19 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Maple.Domain; -using Maple.Localization.Properties; +using Maple.Properties; +using Microsoft.Extensions.Logging; -namespace Maple.Core +namespace Maple { - public class SequenceService : ISequenceService + public sealed class SequenceService : ISequenceService { - private readonly ILoggingService _log; + private readonly ILogger _log; - public SequenceService(ILoggingService log) + public SequenceService(ILoggerFactory factory) { - _log = log ?? throw new ArgumentNullException(nameof(log), $"{nameof(log)} {Resources.IsRequired}"); + _log = factory.CreateLogger() ?? throw new ArgumentNullException(nameof(factory)); } public int Get(IList items) @@ -25,7 +26,7 @@ public int Get(IList items) { if (result == int.MaxValue) { - _log.Error(Resources.MaxPlaylistCountReachedException); + _log.LogError(Resources.MaxPlaylistCountReachedException); break; } diff --git a/src/Maple/Features/Playback/ShuffleModeChangedMessage.cs b/src/Maple/Features/Playback/ShuffleModeChangedMessage.cs new file mode 100644 index 0000000..e73754d --- /dev/null +++ b/src/Maple/Features/Playback/ShuffleModeChangedMessage.cs @@ -0,0 +1,12 @@ +using MvvmScarletToolkit; + +namespace Maple +{ + public class ShuffleModeChangedMessage : GenericScarletMessage + { + public ShuffleModeChangedMessage(object sender, bool content) + : base(sender, content) + { + } + } +} diff --git a/src/Maple/Features/Settings/Culture.cs b/src/Maple/Features/Settings/Culture.cs new file mode 100644 index 0000000..0b395c3 --- /dev/null +++ b/src/Maple/Features/Settings/Culture.cs @@ -0,0 +1,16 @@ +using System.Globalization; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Observables; + +namespace Maple +{ + public sealed class Culture : ViewModelBase + { + public string DisplayName => Model.DisplayName; + + public Culture(IScarletCommandBuilder commandBuilder, CultureInfo culture) + : base(commandBuilder, culture) + { + } + } +} diff --git a/src/Maple/Features/Settings/Cultures.cs b/src/Maple/Features/Settings/Cultures.cs new file mode 100644 index 0000000..33ae9ce --- /dev/null +++ b/src/Maple/Features/Settings/Cultures.cs @@ -0,0 +1,27 @@ +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Abstractions; +using MvvmScarletToolkit.Observables; + +namespace Maple +{ + public sealed class Cultures : BusinessViewModelListBase + { + private readonly ILocalizationService _localizationService; + + public Cultures(IScarletCommandBuilder commandBuilder, ILocalizationService localizationService) + : base(commandBuilder) + { + Messenger.Subscribe>((p) => _localizationService.CurrentLanguage = p.Content.Model); + _localizationService = localizationService; + } + + protected override async Task RefreshInternal(CancellationToken token) + { + await Task.WhenAll(_localizationService.Languages.ForEachAsync(p => Add(new Culture(CommandBuilder, p)))); + await Dispatcher.Invoke(() => SelectedItem = Items.FirstOrDefault(p => p.Model == _localizationService.CurrentLanguage)); + } + } +} diff --git a/src/Maple/Features/Settings/OptionsViewModel.cs b/src/Maple/Features/Settings/OptionsViewModel.cs new file mode 100644 index 0000000..4534567 --- /dev/null +++ b/src/Maple/Features/Settings/OptionsViewModel.cs @@ -0,0 +1,19 @@ +using System; +using MvvmScarletToolkit.Observables; + +namespace Maple +{ + public sealed class OptionsViewModel : ObservableObject + { + public Cultures Cultures { get; } + public AudioDevices AudioDevices { get; } + public AudioDeviceTypes AudioDeviceTypes { get; } + + public OptionsViewModel(Cultures cultures, AudioDevices audioDevices, AudioDeviceTypes audioDeviceTypes) + { + Cultures = cultures ?? throw new ArgumentNullException(nameof(cultures)); + AudioDevices = audioDevices ?? throw new ArgumentNullException(nameof(audioDevices)); + AudioDeviceTypes = audioDeviceTypes ?? throw new ArgumentNullException(nameof(audioDeviceTypes)); + } + } +} diff --git a/src/Maple/Features/Startup/LogMessageReceivedMessage.cs b/src/Maple/Features/Startup/LogMessageReceivedMessage.cs new file mode 100644 index 0000000..855b7da --- /dev/null +++ b/src/Maple/Features/Startup/LogMessageReceivedMessage.cs @@ -0,0 +1,12 @@ +using MvvmScarletToolkit; + +namespace Maple +{ + public class LogMessageReceivedMessage : GenericScarletMessage + { + public LogMessageReceivedMessage(object sender, string content) + : base(sender, content) + { + } + } +} diff --git a/src/Maple/Features/Startup/MetaDataViewModel.cs b/src/Maple/Features/Startup/MetaDataViewModel.cs new file mode 100644 index 0000000..70cb5b9 --- /dev/null +++ b/src/Maple/Features/Startup/MetaDataViewModel.cs @@ -0,0 +1,83 @@ +using System; +using Maple.Domain; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Observables; + +namespace Maple +{ + public sealed class MetaDataViewModel : ViewModelBase + { + private readonly IVersionService _versionService; + + private IDisposable _token; + private bool _disposed; + + private string _version; + /// + /// Gets the version. + /// + /// + /// The version. + /// + public string Version + { + get { return _version; } + private set { SetValue(ref _version, value); } + } + + private string _language; + /// + /// Gets the language. + /// + /// + /// The language. + /// + public string Language + { + get { return _language; } + private set { SetValue(ref _language, value); } + } + + /// + /// Initializes a new instance of the class. + /// + /// The manager. + /// The media players. + public MetaDataViewModel(IScarletCommandBuilder commandBuilder, IVersionService versionService) + : base(commandBuilder) + { + _versionService = versionService ?? throw new ArgumentNullException(nameof(versionService)); + + _token = Messenger.Subscribe>(UpdateLanguage); + Version = _versionService.Get(); + } + + private void UpdateLanguage(ViewModelListBaseSelectionChanged message) + { + Language = $"({message.Content.Model.TwoLetterISOLanguageName})"; + } + + protected override void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + _disposed = true; + + if (disposing) + { + if (_token != null) + { + _token?.Dispose(); + _token = null; + } + } + + base.Dispose(disposing); + } + + // TODO add message queue and notify user about important notifications + } +} diff --git a/src/Maple/SplashScreen.xaml b/src/Maple/Features/Startup/SplashScreen.xaml similarity index 73% rename from src/Maple/SplashScreen.xaml rename to src/Maple/Features/Startup/SplashScreen.xaml index e7c774b..5e338a5 100644 --- a/src/Maple/SplashScreen.xaml +++ b/src/Maple/Features/Startup/SplashScreen.xaml @@ -1,18 +1,13 @@  + WindowStartupLocation="CenterScreen"> + @@ -29,11 +24,12 @@ + + Text="Copyright © 2020 by Insire" /> - - + Source="pack://application:,,,/Maple;component/Resources/logo_withoutbackground.png" /> diff --git a/src/Maple/Features/Startup/SplashScreen.xaml.cs b/src/Maple/Features/Startup/SplashScreen.xaml.cs new file mode 100644 index 0000000..f96e572 --- /dev/null +++ b/src/Maple/Features/Startup/SplashScreen.xaml.cs @@ -0,0 +1,17 @@ +using System; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Abstractions; + +namespace Maple +{ + public partial class SplashScreen : IoCWindow + { + public SplashScreen(ILocalizationService localizationService, IScarletCommandBuilder commandBuilder, SplashScreenViewModel datacontext) + : base(commandBuilder, localizationService) + { + DataContext = datacontext ?? throw new ArgumentNullException(nameof(datacontext)); + + InitializeComponent(); + } + } +} diff --git a/src/Maple/ViewModels/SplashScreenViewModel.cs b/src/Maple/Features/Startup/SplashScreenViewModel.cs similarity index 63% rename from src/Maple/ViewModels/SplashScreenViewModel.cs rename to src/Maple/Features/Startup/SplashScreenViewModel.cs index 5609d0a..f13f33d 100644 --- a/src/Maple/ViewModels/SplashScreenViewModel.cs +++ b/src/Maple/Features/Startup/SplashScreenViewModel.cs @@ -1,19 +1,21 @@ -using System; +using System; using System.Collections.Generic; using System.Windows.Input; -using Maple.Core; using Maple.Domain; -using Maple.Localization.Properties; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Abstractions; +using MvvmScarletToolkit.Commands; +using MvvmScarletToolkit.Observables; namespace Maple { - public class SplashScreenViewModel : ObservableObject, ISplashScreenViewModel + public class SplashScreenViewModel : ViewModelBase, IDisposable { - private readonly IMessenger _messenger; + private readonly IScarletMessenger _messenger; private readonly Queue _queue; - private System.Timers.Timer _timer; - protected bool IsDisposed { get; private set; } + private bool _disposed; + private System.Timers.Timer _timer; private string _version; public string Version @@ -43,26 +45,29 @@ public ICommand DisposeCommand private set { SetValue(ref _disposeCommand, value); } } - private SplashScreenViewModel() + private SplashScreenViewModel(IScarletCommandBuilder commandBuilder) + : base(commandBuilder) { _queue = new Queue(); _timer = new System.Timers.Timer(150); - _timer.Elapsed += _timer_Elapsed; + _timer.Elapsed += Timer_Elapsed; } - private SplashScreenViewModel(IMessenger messenger) : this() + private SplashScreenViewModel(IScarletMessenger messenger, IScarletCommandBuilder commandBuilder) + : this(commandBuilder) { - _messenger = messenger ?? throw new ArgumentNullException(nameof(messenger), $"{nameof(messenger)} {Resources.IsRequired}"); + _messenger = messenger ?? throw new ArgumentNullException(nameof(messenger)); _messenger.Subscribe(LogMessageReceived); } - public SplashScreenViewModel(IMessenger messenger, IVersionService version) : this(messenger) + public SplashScreenViewModel(IScarletMessenger messenger, IVersionService version, IScarletCommandBuilder commandBuilder) + : this(messenger, commandBuilder) { Version = version.Get(); InitializeCommands(); } - private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { if (_queue.Count == 0) return; @@ -73,8 +78,8 @@ private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) private void InitializeCommands() { - LoadCommand = new RelayCommand(Load, CanLoad); - DisposeCommand = new RelayCommand(Dispose, CanDispose); + LoadCommand = new RelayCommand(CommandManager, Load, CanLoad); + DisposeCommand = new RelayCommand(CommandManager, Dispose, CanDispose); } public void Load() @@ -92,31 +97,26 @@ private void LogMessageReceived(LogMessageReceivedMessage e) _queue.Enqueue(e.Content); } - public void Dispose() + protected override void Dispose(bool disposing) { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (IsDisposed) + if (_disposed) + { return; + } + _disposed = true; if (disposing) { if (_timer != null) { _timer.Stop(); - _timer.Elapsed -= _timer_Elapsed; + _timer.Elapsed -= Timer_Elapsed; _timer.Dispose(); _timer = null; } - // Free any other managed objects here. } - // Free any unmanaged objects here. - IsDisposed = true; + base.Dispose(disposing); } public bool CanDispose() diff --git a/src/Maple/Services/VersionService.cs b/src/Maple/Features/Startup/VersionService.cs similarity index 88% rename from src/Maple/Services/VersionService.cs rename to src/Maple/Features/Startup/VersionService.cs index 00c284d..67de055 100644 --- a/src/Maple/Services/VersionService.cs +++ b/src/Maple/Features/Startup/VersionService.cs @@ -3,7 +3,7 @@ namespace Maple { - public class VersionService : IVersionService + public sealed class VersionService : IVersionService { private readonly AssemblyName _assemblyName; diff --git a/src/Maple/FodyWeavers.xml b/src/Maple/FodyWeavers.xml deleted file mode 100644 index 1f93c9a..0000000 --- a/src/Maple/FodyWeavers.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/Maple/Interfaces/IBaseMapper.cs b/src/Maple/Interfaces/IBaseMapper.cs deleted file mode 100644 index 6288c78..0000000 --- a/src/Maple/Interfaces/IBaseMapper.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Maple.Core; -using Maple.Domain; - -namespace Maple -{ - public interface IBaseMapper - where TVieModel : BaseDataViewModel - where TDataModel : class, IBaseObject - { - TVieModel Get(TDataModel model); - - TDataModel GetData(TVieModel viewModel); - } -} diff --git a/src/Maple/Interfaces/IMediaItemMapper.cs b/src/Maple/Interfaces/IMediaItemMapper.cs deleted file mode 100644 index f987723..0000000 --- a/src/Maple/Interfaces/IMediaItemMapper.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Maple.Domain; - -namespace Maple -{ - public interface IMediaItemMapper : IBaseMapper - { - MediaItem GetNewMediaItem(int sequence, Playlist playlist); - MediaItemModel GetDataNewMediaItem(PlaylistModel playlist); - } -} diff --git a/src/Maple/Interfaces/IMediaPlayerMapper.cs b/src/Maple/Interfaces/IMediaPlayerMapper.cs deleted file mode 100644 index ed7f9cb..0000000 --- a/src/Maple/Interfaces/IMediaPlayerMapper.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Maple.Domain; - -namespace Maple -{ - public interface IMediaPlayerMapper : IBaseMapper - { - MainMediaPlayer GetMain(MediaPlayerModel player, Playlist playlist); - - MediaPlayer Get(MediaPlayerModel player, Playlist playlist); - MediaPlayer GetNewMediaPlayer(int sequence, Playlist playlist = null); - } -} \ No newline at end of file diff --git a/src/Maple/Interfaces/IMediaRepository.cs b/src/Maple/Interfaces/IMediaRepository.cs deleted file mode 100644 index 5eb7ffa..0000000 --- a/src/Maple/Interfaces/IMediaRepository.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Maple -{ - public interface IMediaRepository : IDisposable - { - bool IsBusy { get; } - - void Save(MediaItem viewModel); - void Save(MediaItems viewModel); - Task GetMediaItemByIdAsync(int id); - Task> GetMediaItemsAsync(); - Task GetMediaItemByPlaylistIdAsync(int id); - - - void Save(Playlist viewModel); - void Save(Playlists viewModel); - Task GetPlaylistByIdAsync(int id); - Task> GetPlaylistsAsync(); - - void Save(MediaPlayer viewModel); - void Save(MediaPlayers viewModel); - Task GetMainMediaPlayerAsync(); - Task GetMediaPlayerByIdAsync(int id); - Task> GetAllOptionalMediaPlayersAsync(); - } -} \ No newline at end of file diff --git a/src/Maple/Interfaces/IPlaylistMapper.cs b/src/Maple/Interfaces/IPlaylistMapper.cs deleted file mode 100644 index 014b807..0000000 --- a/src/Maple/Interfaces/IPlaylistMapper.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Maple.Domain; - -namespace Maple -{ - public interface IPlaylistMapper : IBaseMapper - { - Playlist GetNewPlaylist(); - } -} diff --git a/src/Maple/Maple.csproj b/src/Maple/Maple.csproj index c6b270b..7f9d6c8 100644 --- a/src/Maple/Maple.csproj +++ b/src/Maple/Maple.csproj @@ -1,364 +1,81 @@ - - - Debug - AnyCPU - {FBD5595B-6859-4E8E-BDFA-C3169EF34985} - WinExe - Properties - Maple - Maple - v4.7.1 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - true - - false - - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - true - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - false - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - Maple.App - - - ..\Resources\Images\logo.ico - - - - - - 2.12.5 - - - - - - - 2.2.0 - - - 2.2.0 - - - - - - - - - - 1.7.8 - - - - - - - - - - - - - - - - - - - - - - - 4.0 - - - - - - - - MSBuild:Compile - Designer - - - Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - - - - MediaPlayersPage.xaml - - - OptionsPage.xaml - - - PlaylistsPage.xaml - - - - - - - - - SplashScreen.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MediaPlayerPage.xaml - - - NewPlaylistOptionsPage.xaml - - - NewPlaylistPage.xaml - - - ColorOptionsPage.xaml - - - - - - - - - - - - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - App.xaml - Code - - - Shell.xaml - Code - - - Designer - MSBuild:Compile - - - - - Code - - - True - True - Resources.resx - - - True - Settings.settings - True - - - ResXFileCodeGenerator - Resources.Designer.cs - - - Resources\client_secret.json - PreserveNewest - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - - Designer - - - - - False - .NET Framework 3.5 SP1 - false - - - - - Resources\logo.ico - - - - - Resources\logo_withoutbackground.png - - - - - - - - {21FA5854-0692-42E2-924E-A38CF3C7FF71} - Maple.Core - - - {b3cd46be-3c08-4bae-ae60-a6d84a62400c} - Maple.Data - - - {9d7d05a6-8271-4836-a7bb-5b2abeccbd81} - Maple.Domain - - - {A073FC92-90E3-4541-8B52-6F7293187871} - Maple.Localization - - - {B5BE546F-8D9F-4FB9-B235-AF05FD553F9E} - Maple.Youtube - - - - - Resources\Art_Of_Escapism_-_Universe_Words.mp3 - PreserveNewest - - - - - - - - \ No newline at end of file + + + WinExe + netcoreapp3.1 + true + False + false + false + false + win10-x64 + False + logo.ico + 8.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + + + + + Resources.resx + True + True + + + + + Resources.Designer.cs + PublicResXFileCodeGenerator + + + diff --git a/src/Maple/Migrations/20201105104602_Initial.Designer.cs b/src/Maple/Migrations/20201105104602_Initial.Designer.cs new file mode 100644 index 0000000..087ad19 --- /dev/null +++ b/src/Maple/Migrations/20201105104602_Initial.Designer.cs @@ -0,0 +1,353 @@ +// +using System; +using Maple; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Maple.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20201105104602_Initial")] + partial class Initial + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.9"); + + modelBuilder.Entity("Maple.Domain.AudioDeviceModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnName("Id") + .HasColumnType("INTEGER"); + + b.Property("AudioDeviceTypeId") + .HasColumnType("INTEGER"); + + b.Property("CreatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(50); + + b.Property("OsId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Sequence") + .ValueGeneratedOnAdd() + .HasColumnName("Sequence") + .HasColumnType("INTEGER") + .HasDefaultValue(0); + + b.Property("UpdatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id"); + + b.HasIndex("AudioDeviceTypeId"); + + b.ToTable("AudioDevices"); + }); + + modelBuilder.Entity("Maple.Domain.AudioDeviceTypeModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnName("Id") + .HasColumnType("INTEGER"); + + b.Property("CreatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("DeviceType") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(50); + + b.Property("Sequence") + .ValueGeneratedOnAdd() + .HasColumnName("Sequence") + .HasColumnType("INTEGER") + .HasDefaultValue(0); + + b.Property("UpdatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id"); + + b.ToTable("AudioDeviceTypes"); + + b.HasData( + new + { + Id = 1, + CreatedOn = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), + DeviceType = 1, + Name = "WaveOut", + Sequence = 1, + UpdatedOn = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) + }, + new + { + Id = 2, + CreatedOn = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), + DeviceType = 2, + Name = "DirectSound", + Sequence = 2, + UpdatedOn = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) + }, + new + { + Id = 3, + CreatedOn = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), + DeviceType = 3, + Name = "WASAPI", + Sequence = 3, + UpdatedOn = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) + }, + new + { + Id = 4, + CreatedOn = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), + DeviceType = 4, + Name = "ASIO", + Sequence = 4, + UpdatedOn = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) + }); + }); + + modelBuilder.Entity("Maple.Domain.MediaItemModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnName("Id") + .HasColumnType("INTEGER"); + + b.Property("CreatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Duration") + .HasColumnType("TEXT"); + + b.Property("MediaItemType") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(50); + + b.Property("PlaylistId") + .HasColumnType("INTEGER"); + + b.Property("PrivacyStatus") + .HasColumnType("INTEGER"); + + b.Property("Sequence") + .ValueGeneratedOnAdd() + .HasColumnName("Sequence") + .HasColumnType("INTEGER") + .HasDefaultValue(0); + + b.Property("UpdatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id"); + + b.HasIndex("PlaylistId"); + + b.ToTable("MediaItems"); + }); + + modelBuilder.Entity("Maple.Domain.MediaPlayerModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnName("Id") + .HasColumnType("INTEGER"); + + b.Property("AudioDeviceId") + .HasColumnType("INTEGER"); + + b.Property("CreatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("IsPrimary") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(50); + + b.Property("PlaylistId") + .HasColumnType("INTEGER"); + + b.Property("Sequence") + .ValueGeneratedOnAdd() + .HasColumnName("Sequence") + .HasColumnType("INTEGER") + .HasDefaultValue(0); + + b.Property("UpdatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id"); + + b.HasIndex("AudioDeviceId"); + + b.HasIndex("PlaylistId"); + + b.ToTable("MediaPlayers"); + }); + + modelBuilder.Entity("Maple.Domain.PlaylistModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnName("Id") + .HasColumnType("INTEGER"); + + b.Property("CreatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("IsShuffeling") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(50); + + b.Property("PrivacyStatus") + .HasColumnType("INTEGER"); + + b.Property("RepeatMode") + .HasColumnType("INTEGER"); + + b.Property("Sequence") + .ValueGeneratedOnAdd() + .HasColumnName("Sequence") + .HasColumnType("INTEGER") + .HasDefaultValue(0); + + b.Property("UpdatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id"); + + b.ToTable("Playlists"); + }); + + modelBuilder.Entity("Maple.Domain.AudioDeviceModel", b => + { + b.HasOne("Maple.Domain.AudioDeviceTypeModel", "AudioDeviceType") + .WithMany("AudioDevices") + .HasForeignKey("AudioDeviceTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Maple.Domain.MediaItemModel", b => + { + b.HasOne("Maple.Domain.PlaylistModel", "Playlist") + .WithMany("MediaItems") + .HasForeignKey("PlaylistId") + .OnDelete(DeleteBehavior.SetNull) + .IsRequired(); + }); + + modelBuilder.Entity("Maple.Domain.MediaPlayerModel", b => + { + b.HasOne("Maple.Domain.AudioDeviceModel", "AudioDevice") + .WithMany() + .HasForeignKey("AudioDeviceId"); + + b.HasOne("Maple.Domain.PlaylistModel", "Playlist") + .WithMany("MediaPlayers") + .HasForeignKey("PlaylistId"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Maple/Migrations/20201105104602_Initial.cs b/src/Maple/Migrations/20201105104602_Initial.cs new file mode 100644 index 0000000..cf5aaee --- /dev/null +++ b/src/Maple/Migrations/20201105104602_Initial.cs @@ -0,0 +1,201 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Maple.Migrations +{ + public partial class Initial : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AudioDeviceTypes", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Sequence = table.Column(nullable: false, defaultValue: 0) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(maxLength: 50, nullable: false), + CreatedOn = table.Column(nullable: false, defaultValueSql: "CURRENT_TIMESTAMP"), + CreatedBy = table.Column(nullable: true, defaultValue: "SYSTEM"), + UpdatedOn = table.Column(nullable: false, defaultValueSql: "CURRENT_TIMESTAMP"), + UpdatedBy = table.Column(nullable: true, defaultValue: "SYSTEM"), + DeviceType = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AudioDeviceTypes", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Playlists", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Sequence = table.Column(nullable: false, defaultValue: 0) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(maxLength: 50, nullable: false), + CreatedOn = table.Column(nullable: false, defaultValueSql: "CURRENT_TIMESTAMP"), + CreatedBy = table.Column(nullable: true, defaultValue: "SYSTEM"), + UpdatedOn = table.Column(nullable: false, defaultValueSql: "CURRENT_TIMESTAMP"), + UpdatedBy = table.Column(nullable: true, defaultValue: "SYSTEM"), + IsShuffeling = table.Column(nullable: false), + PrivacyStatus = table.Column(nullable: false), + RepeatMode = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Playlists", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AudioDevices", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Sequence = table.Column(nullable: false, defaultValue: 0) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(maxLength: 50, nullable: false), + CreatedOn = table.Column(nullable: false, defaultValueSql: "CURRENT_TIMESTAMP"), + CreatedBy = table.Column(nullable: true, defaultValue: "SYSTEM"), + UpdatedOn = table.Column(nullable: false, defaultValueSql: "CURRENT_TIMESTAMP"), + UpdatedBy = table.Column(nullable: true, defaultValue: "SYSTEM"), + OsId = table.Column(nullable: false), + AudioDeviceTypeId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AudioDevices", x => x.Id); + table.ForeignKey( + name: "FK_AudioDevices_AudioDeviceTypes_AudioDeviceTypeId", + column: x => x.AudioDeviceTypeId, + principalTable: "AudioDeviceTypes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "MediaItems", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Sequence = table.Column(nullable: false, defaultValue: 0) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(maxLength: 50, nullable: false), + CreatedOn = table.Column(nullable: false, defaultValueSql: "CURRENT_TIMESTAMP"), + CreatedBy = table.Column(nullable: true, defaultValue: "SYSTEM"), + UpdatedOn = table.Column(nullable: false, defaultValueSql: "CURRENT_TIMESTAMP"), + UpdatedBy = table.Column(nullable: true, defaultValue: "SYSTEM"), + Duration = table.Column(nullable: false), + PrivacyStatus = table.Column(nullable: false), + MediaItemType = table.Column(nullable: false), + PlaylistId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_MediaItems", x => x.Id); + table.ForeignKey( + name: "FK_MediaItems_Playlists_PlaylistId", + column: x => x.PlaylistId, + principalTable: "Playlists", + principalColumn: "Id", + onDelete: ReferentialAction.SetNull); + }); + + migrationBuilder.CreateTable( + name: "MediaPlayers", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Sequence = table.Column(nullable: false, defaultValue: 0) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(maxLength: 50, nullable: false), + CreatedOn = table.Column(nullable: false, defaultValueSql: "CURRENT_TIMESTAMP"), + CreatedBy = table.Column(nullable: true, defaultValue: "SYSTEM"), + UpdatedOn = table.Column(nullable: false, defaultValueSql: "CURRENT_TIMESTAMP"), + UpdatedBy = table.Column(nullable: true, defaultValue: "SYSTEM"), + IsPrimary = table.Column(nullable: false), + PlaylistId = table.Column(nullable: true), + AudioDeviceId = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_MediaPlayers", x => x.Id); + table.ForeignKey( + name: "FK_MediaPlayers_AudioDevices_AudioDeviceId", + column: x => x.AudioDeviceId, + principalTable: "AudioDevices", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_MediaPlayers_Playlists_PlaylistId", + column: x => x.PlaylistId, + principalTable: "Playlists", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.InsertData( + table: "AudioDeviceTypes", + columns: new[] { "Id", "DeviceType", "Name", "Sequence" }, + values: new object[] { 1, 1, "WaveOut", 1 }); + + migrationBuilder.InsertData( + table: "AudioDeviceTypes", + columns: new[] { "Id", "DeviceType", "Name", "Sequence" }, + values: new object[] { 2, 2, "DirectSound", 2 }); + + migrationBuilder.InsertData( + table: "AudioDeviceTypes", + columns: new[] { "Id", "DeviceType", "Name", "Sequence" }, + values: new object[] { 3, 3, "WASAPI", 3 }); + + migrationBuilder.InsertData( + table: "AudioDeviceTypes", + columns: new[] { "Id", "DeviceType", "Name", "Sequence" }, + values: new object[] { 4, 4, "ASIO", 4 }); + + migrationBuilder.CreateIndex( + name: "IX_AudioDevices_AudioDeviceTypeId", + table: "AudioDevices", + column: "AudioDeviceTypeId"); + + migrationBuilder.CreateIndex( + name: "IX_MediaItems_PlaylistId", + table: "MediaItems", + column: "PlaylistId"); + + migrationBuilder.CreateIndex( + name: "IX_MediaPlayers_AudioDeviceId", + table: "MediaPlayers", + column: "AudioDeviceId"); + + migrationBuilder.CreateIndex( + name: "IX_MediaPlayers_PlaylistId", + table: "MediaPlayers", + column: "PlaylistId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "MediaItems"); + + migrationBuilder.DropTable( + name: "MediaPlayers"); + + migrationBuilder.DropTable( + name: "AudioDevices"); + + migrationBuilder.DropTable( + name: "Playlists"); + + migrationBuilder.DropTable( + name: "AudioDeviceTypes"); + } + } +} diff --git a/src/Maple/Migrations/ApplicationDbContextModelSnapshot.cs b/src/Maple/Migrations/ApplicationDbContextModelSnapshot.cs new file mode 100644 index 0000000..b3fa446 --- /dev/null +++ b/src/Maple/Migrations/ApplicationDbContextModelSnapshot.cs @@ -0,0 +1,358 @@ +// +using System; +using Maple; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Maple.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + partial class ApplicationDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { + var now = DateTime.Now; + +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.9"); + + modelBuilder.Entity("Maple.Domain.AudioDeviceModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnName("Id") + .HasColumnType("INTEGER"); + + b.Property("AudioDeviceTypeId") + .HasColumnType("INTEGER"); + + b.Property("CreatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(50); + + b.Property("OsId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Sequence") + .ValueGeneratedOnAdd() + .HasColumnName("Sequence") + .HasColumnType("INTEGER") + .HasDefaultValue(0); + + b.Property("UpdatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id"); + + b.HasIndex("AudioDeviceTypeId"); + + b.ToTable("AudioDevices"); + }); + + modelBuilder.Entity("Maple.Domain.AudioDeviceTypeModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnName("Id") + .HasColumnType("INTEGER"); + + b.Property("CreatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("DeviceType") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(50); + + b.Property("Sequence") + .ValueGeneratedOnAdd() + .HasColumnName("Sequence") + .HasColumnType("INTEGER") + .HasDefaultValue(0); + + b.Property("UpdatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id"); + + b.ToTable("AudioDeviceTypes"); + + b.HasData( + new + { + Id = 1, + CreatedOn = now, + DeviceType = 1, + Name = "WaveOut", + Sequence = 1, + UpdatedOn = now + }, + new + { + Id = 2, + CreatedOn = now, + DeviceType = 2, + Name = "DirectSound", + Sequence = 2, + UpdatedOn = now + }, + new + { + Id = 3, + CreatedOn = now, + DeviceType = 3, + Name = "WASAPI", + Sequence = 3, + UpdatedOn = now + }, + new + { + Id = 4, + CreatedOn = now, + DeviceType = 4, + Name = "ASIO", + Sequence = 4, + UpdatedOn = now + }); + }); + + modelBuilder.Entity("Maple.Domain.MediaItemModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnName("Id") + .HasColumnType("INTEGER"); + + b.Property("CreatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Duration") + .HasColumnType("TEXT"); + + b.Property("MediaItemType") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(50); + + b.Property("PlaylistId") + .HasColumnType("INTEGER"); + + b.Property("PrivacyStatus") + .HasColumnType("INTEGER"); + + b.Property("Sequence") + .ValueGeneratedOnAdd() + .HasColumnName("Sequence") + .HasColumnType("INTEGER") + .HasDefaultValue(0); + + b.Property("UpdatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id"); + + b.HasIndex("PlaylistId"); + + b.ToTable("MediaItems"); + }); + + modelBuilder.Entity("Maple.Domain.MediaPlayerModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnName("Id") + .HasColumnType("INTEGER"); + + b.Property("AudioDeviceId") + .HasColumnType("INTEGER"); + + b.Property("CreatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("IsPrimary") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(50); + + b.Property("PlaylistId") + .HasColumnType("INTEGER"); + + b.Property("Sequence") + .ValueGeneratedOnAdd() + .HasColumnName("Sequence") + .HasColumnType("INTEGER") + .HasDefaultValue(0); + + b.Property("UpdatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id"); + + b.HasIndex("AudioDeviceId"); + + b.HasIndex("PlaylistId"); + + b.ToTable("MediaPlayers"); + }); + + modelBuilder.Entity("Maple.Domain.PlaylistModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnName("Id") + .HasColumnType("INTEGER"); + + b.Property("CreatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("IsShuffeling") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(50); + + b.Property("PrivacyStatus") + .HasColumnType("INTEGER"); + + b.Property("RepeatMode") + .HasColumnType("INTEGER"); + + b.Property("Sequence") + .ValueGeneratedOnAdd() + .HasColumnName("Sequence") + .HasColumnType("INTEGER") + .HasDefaultValue(0); + + b.Property("Thumbnail") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(260); + + b.Property("UpdatedBy") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue("SYSTEM"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("TEXT") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id"); + + b.ToTable("Playlists"); + }); + + modelBuilder.Entity("Maple.Domain.AudioDeviceModel", b => + { + b.HasOne("Maple.Domain.AudioDeviceTypeModel", "AudioDeviceType") + .WithMany("AudioDevices") + .HasForeignKey("AudioDeviceTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Maple.Domain.MediaItemModel", b => + { + b.HasOne("Maple.Domain.PlaylistModel", "Playlist") + .WithMany("MediaItems") + .HasForeignKey("PlaylistId") + .OnDelete(DeleteBehavior.SetNull) + .IsRequired(); + }); + + modelBuilder.Entity("Maple.Domain.MediaPlayerModel", b => + { + b.HasOne("Maple.Domain.AudioDeviceModel", "AudioDevice") + .WithMany() + .HasForeignKey("AudioDeviceId"); + + b.HasOne("Maple.Domain.PlaylistModel", "Playlist") + .WithMany("MediaPlayers") + .HasForeignKey("PlaylistId"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Maple/Properties/AssemblyInfo.cs b/src/Maple/Properties/AssemblyInfo.cs index 09980fb..752ada2 100644 --- a/src/Maple/Properties/AssemblyInfo.cs +++ b/src/Maple/Properties/AssemblyInfo.cs @@ -1,12 +1,10 @@ -using System.Runtime.InteropServices; -using System.Reflection; +using System.Reflection; using System.Windows; [assembly: AssemblyTitle("Maple")] [assembly: AssemblyDescription("Maple is a windows desktop application designed to support semi and non professional streamers in playing back local audio files and streaming content from the internet to their favorite playback device")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] - [assembly: ThemeInfo( ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located //(used if a resource is not found in the page, diff --git a/src/Maple/Properties/Resources.Designer.cs b/src/Maple/Properties/Resources.Designer.cs index d6f7b87..74a399a 100644 --- a/src/Maple/Properties/Resources.Designer.cs +++ b/src/Maple/Properties/Resources.Designer.cs @@ -8,10 +8,10 @@ // //------------------------------------------------------------------------------ -namespace Maple.Properties -{ - - +namespace Maple.Properties { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -19,53 +19,837 @@ namespace Maple.Properties // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources - { - + public class Resources { + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { + internal Resources() { } - + /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if (object.ReferenceEquals(resourceMan, null)) - { + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Maple.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { + public static global::System.Globalization.CultureInfo Culture { + get { return resourceCulture; } - set - { + set { resourceCulture = value; } } + + /// + /// Looks up a localized string similar to Über. + /// + public static string About { + get { + return ResourceManager.GetString("About", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to OK. + /// + public static string Accept { + get { + return ResourceManager.GetString("Accept", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Hinzufügen. + /// + public static string Add { + get { + return ResourceManager.GetString("Add", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Anwendung wird geschlossen. + /// + public static string AppExit { + get { + return ResourceManager.GetString("AppExit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Anwendung geschlossen. + /// + public static string AppExitComplete { + get { + return ResourceManager.GetString("AppExitComplete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Daten werden gespeichert. + /// + public static string AppExitSaving { + get { + return ResourceManager.GetString("AppExitSaving", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Anwendung wird gestartet. + /// + public static string AppStart { + get { + return ResourceManager.GetString("AppStart", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Anwendung gestartet. + /// + public static string AppStartComplete { + get { + return ResourceManager.GetString("AppStartComplete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Daten werden geladen. + /// + public static string AppStartLoadData { + get { + return ResourceManager.GetString("AppStartLoadData", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Daten laden fehlgeschlagen. + /// + public static string AppStartLoadDataFailed { + get { + return ResourceManager.GetString("AppStartLoadDataFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Oberfläche wird geladen. + /// + public static string AppStartLoadUI { + get { + return ResourceManager.GetString("AppStartLoadUI", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wiedergabegerät. + /// + public static string AudioDevice { + get { + return ResourceManager.GetString("AudioDevice", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Abbrechen. + /// + public static string Cancel { + get { + return ResourceManager.GetString("Cancel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Leeren. + /// + public static string Clear { + get { + return ResourceManager.GetString("Clear", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Schließen. + /// + public static string Close { + get { + return ResourceManager.GetString("Close", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Zu den Farbprofilen wechseln. + /// + public static string ColorOptionsCommand { + get { + return ResourceManager.GetString("ColorOptionsCommand", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Anzahl. + /// + public static string Count { + get { + return ResourceManager.GetString("Count", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Startseite. + /// + public static string Dashboard { + get { + return ResourceManager.GetString("Dashboard", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Löschen. + /// + public static string Delete { + get { + return ResourceManager.GetString("Delete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Beschreibung. + /// + public static string Description { + get { + return ResourceManager.GetString("Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Es ist bereits ein Dialog geöffnet. Es kann kein Weiterer geöffnet werden. + /// + public static string DialogOpenAlready { + get { + return ResourceManager.GetString("DialogOpenAlready", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dirigent. + /// + public static string Director { + get { + return ResourceManager.GetString("Director", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Speichert geleert. + /// + public static string DisposedState { + get { + return ResourceManager.GetString("DisposedState", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Speicher wird geleert. + /// + public static string DisposingState { + get { + return ResourceManager.GetString("DisposingState", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dauer. + /// + public static string Duration { + get { + return ResourceManager.GetString("Duration", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ändern. + /// + public static string Edit { + get { + return ResourceManager.GetString("Edit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sprache ändern. + /// + public static string EditLanguage { + get { + return ResourceManager.GetString("EditLanguage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Liste darf nicht null oder leer sein.. + /// + public static string ExceptionMessageCollectionNullOrEmpty { + get { + return ResourceManager.GetString("ExceptionMessageCollectionNullOrEmpty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Werte müssen gleich sein.. + /// + public static string ExceptionMessageEqualValues { + get { + return ResourceManager.GetString("ExceptionMessageEqualValues", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Die angegebene Bedingung ist falsch.. + /// + public static string ExceptionMessageFalseCondition { + get { + return ResourceManager.GetString("ExceptionMessageFalseCondition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Folgendes Verzeichnis wurde nicht gefunden:. + /// + public static string ExceptionMessageMissingDirectory { + get { + return ResourceManager.GetString("ExceptionMessageMissingDirectory", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Folgende Datei wurde nicht gefunden:. + /// + public static string ExceptionMessageMissingFile { + get { + return ResourceManager.GetString("ExceptionMessageMissingFile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Werte dürfen nicht gleich sein.. + /// + public static string ExceptionMessageNotEqualValues { + get { + return ResourceManager.GetString("ExceptionMessageNotEqualValues", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to String darf nicht null, leer oder nur Leerraum enthalten.. + /// + public static string ExceptionMessageStringNullEmpyOrWhiteSpace { + get { + return ResourceManager.GetString("ExceptionMessageStringNullEmpyOrWhiteSpace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Die angegebene Bedingung ist wahr.. + /// + public static string ExceptionMessageTrueCondition { + get { + return ResourceManager.GetString("ExceptionMessageTrueCondition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ein unerwarteter Fehler ist aufgetreten.. + /// + public static string ExceptionMessageUnhandled { + get { + return ResourceManager.GetString("ExceptionMessageUnhandled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Eine Wiedergabeliste aus einer Datei importieren. + /// + public static string FilePlaylistImport { + get { + return ResourceManager.GetString("FilePlaylistImport", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filter. + /// + public static string Filter { + get { + return ResourceManager.GetString("Filter", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Eine Wiedergabeliste anhand eines Ordners aus dem Dateisystem generieren und importieren. + /// + public static string FolderPlaylistImport { + get { + return ResourceManager.GetString("FolderPlaylistImport", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Projektseite auf GitHub.com öffnen. + /// + public static string GithubPageCommand { + get { + return ResourceManager.GetString("GithubPageCommand", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to https://github.com/Insire/Maple. + /// + public static string GithubProjectLink { + get { + return ResourceManager.GetString("GithubProjectLink", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Auf der Datenbank befinden sich eine ungültige Anzahl an Einträgen für den Standardmediaplayer. + /// + public static string InvalidMediaplayerCountOnDBException { + get { + return ResourceManager.GetString("InvalidMediaplayerCountOnDBException", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to darf nicht leer sein. + /// + public static string IsRequired { + get { + return ResourceManager.GetString("IsRequired", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sprachen. + /// + public static string Languages { + get { + return ResourceManager.GetString("Languages", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lade. + /// + public static string Loading { + get { + return ResourceManager.GetString("Loading", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ort. + /// + public static string Location { + get { + return ResourceManager.GetString("Location", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Standardmediaplayer. + /// + public static string MainMediaplayer { + get { + return ResourceManager.GetString("MainMediaplayer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Es können keine weiteren Wiedergabelisten angelegt werden, da die maximale Anzahl erreicht wurde. + /// + public static string MaxPlaylistCountReachedException { + get { + return ResourceManager.GetString("MaxPlaylistCountReachedException", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wiedergabetitel. + /// + public static string MediaItem { + get { + return ResourceManager.GetString("MediaItem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wiedergabetitel. + /// + public static string MediaItems { + get { + return ResourceManager.GetString("MediaItems", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Mediathek. + /// + public static string MediaLibrary { + get { + return ResourceManager.GetString("MediaLibrary", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Zur Wiedergabeliste wechseln. + /// + public static string MediaPlayerCommand { + get { + return ResourceManager.GetString("MediaPlayerCommand", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Mediaplayers. + /// + public static string MediaPlayers { + get { + return ResourceManager.GetString("MediaPlayers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Neu. + /// + public static string New { + get { + return ResourceManager.GetString("New", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Weiter. + /// + public static string Next { + get { + return ResourceManager.GetString("Next", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Mediaplayereinstellungen öffnen. + /// + public static string OpenMediaPlayerConfigurationCommand { + get { + return ResourceManager.GetString("OpenMediaPlayerConfigurationCommand", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Einstellungen. + /// + public static string Options { + get { + return ResourceManager.GetString("Options", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Zu den Einstellungen wechseln. + /// + public static string OptionsCommand { + get { + return ResourceManager.GetString("OptionsCommand", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Analysieren. + /// + public static string Parse { + get { + return ResourceManager.GetString("Parse", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wiedergabe. + /// + public static string Playback { + get { + return ResourceManager.GetString("Playback", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wiedergabemodus. + /// + public static string PlaybackMode { + get { + return ResourceManager.GetString("PlaybackMode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Alle Titel wiederholen. + /// + public static string PlaybackModeAll { + get { + return ResourceManager.GetString("PlaybackModeAll", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Keinen Titel wiederholen. + /// + public static string PlaybackModeNone { + get { + return ResourceManager.GetString("PlaybackModeNone", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Einen Titel wiederholen. + /// + public static string PlaybackModeOne { + get { + return ResourceManager.GetString("PlaybackModeOne", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Zufällige Wiedergabe. + /// + public static string PlaybackShuffle { + get { + return ResourceManager.GetString("PlaybackShuffle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wiedergabeliste. + /// + public static string Playlist { + get { + return ResourceManager.GetString("Playlist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wiedergabeliste hinzufügen. + /// + public static string PlaylistAdd { + get { + return ResourceManager.GetString("PlaylistAdd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Aktuelle Wiedergabeliste. + /// + public static string PlaylistCurrent { + get { + return ResourceManager.GetString("PlaylistCurrent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wiedergabelisten. + /// + public static string Playlists { + get { + return ResourceManager.GetString("Playlists", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Zurück. + /// + public static string Previous { + get { + return ResourceManager.GetString("Previous", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Aktualisieren. + /// + public static string Refresh { + get { + return ResourceManager.GetString("Refresh", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Entfernen. + /// + public static string Remove { + get { + return ResourceManager.GetString("Remove", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Keine Beschränkung. + /// + public static string ResctrictionNone { + get { + return ResourceManager.GetString("ResctrictionNone", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Zugriffsbeschränkung. + /// + public static string Restriction { + get { + return ResourceManager.GetString("Restriction", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kein Zugriff. + /// + public static string RestrictionRestricted { + get { + return ResourceManager.GetString("RestrictionRestricted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Änderungen gespeichert. + /// + public static string SavedState { + get { + return ResourceManager.GetString("SavedState", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Speichere. + /// + public static string Saving { + get { + return ResourceManager.GetString("Saving", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Änderungen werden gespeichert. + /// + public static string SavingState { + get { + return ResourceManager.GetString("SavingState", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Auswählen. + /// + public static string Select { + get { + return ResourceManager.GetString("Select", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dateiauswahl. + /// + public static string SelectFiles { + get { + return ResourceManager.GetString("SelectFiles", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ordnerauswahl. + /// + public static string SelectFolder { + get { + return ResourceManager.GetString("SelectFolder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Maple. + /// + public static string ShellTitle { + get { + return ResourceManager.GetString("ShellTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Farbprofile. + /// + public static string Themes { + get { + return ResourceManager.GetString("Themes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Titel. + /// + public static string Title { + get { + return ResourceManager.GetString("Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lautstärke. + /// + public static string Volume { + get { + return ResourceManager.GetString("Volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Youtubeservice wird geladen. + /// + public static string YoutubeLoad { + get { + return ResourceManager.GetString("YoutubeLoad", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Youtubeservice geladen. + /// + public static string YoutubeLoaded { + get { + return ResourceManager.GetString("YoutubeLoaded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Eine Widergabeliste von Youtube importieren. + /// + public static string YoutubePlaylistImport { + get { + return ResourceManager.GetString("YoutubePlaylistImport", resourceCulture); + } + } } } diff --git a/src/Maple.Localization/Properties/Resources.en.resx b/src/Maple/Properties/Resources.en.resx similarity index 99% rename from src/Maple.Localization/Properties/Resources.en.resx rename to src/Maple/Properties/Resources.en.resx index 1a6b263..3c952bc 100644 --- a/src/Maple.Localization/Properties/Resources.en.resx +++ b/src/Maple/Properties/Resources.en.resx @@ -354,4 +354,7 @@ Refresh + + Open Mediaplayer settings + \ No newline at end of file diff --git a/src/Maple/Properties/Resources.resx b/src/Maple/Properties/Resources.resx index af7dbeb..55ae4cc 100644 --- a/src/Maple/Properties/Resources.resx +++ b/src/Maple/Properties/Resources.resx @@ -46,7 +46,7 @@ mimetype: application/x-microsoft.net.object.binary.base64 value : The object must be serialized with - : System.Serialization.Formatters.Binary.BinaryFormatter + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter : and then encoded with base64 encoding. mimetype: application/x-microsoft.net.object.soap.base64 @@ -60,6 +60,7 @@ : and then encoded with base64 encoding. --> + @@ -68,9 +69,10 @@ - + + @@ -85,9 +87,10 @@ - + + @@ -109,9 +112,274 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Wiedergabe + + + Wiedergabelisten + + + Wiedergabeliste hinzufügen + + + Farbprofile + + + https://github.com/Insire/Maple + @Invariant + + + Einstellungen + + + Maple + + + Sprachen + + + darf nicht leer sein + + + Wiedergabeliste + + + Wiedergabegerät + + + Wiedergabemodus + + + Zufällige Wiedergabe + + + Dirigent + + + Standardmediaplayer + + + Auf der Datenbank befinden sich eine ungültige Anzahl an Einträgen für den Standardmediaplayer + + + Hinzufügen + + + Entfernen + + + Leeren + + + Neu + + + Es können keine weiteren Wiedergabelisten angelegt werden, da die maximale Anzahl erreicht wurde + + + Änderungen werden gespeichert + + + Änderungen gespeichert + + + Speicher wird geleert + + + Speichert geleert + + + Titel + + + Beschreibung + + + Eine Widergabeliste von Youtube importieren + + + Eine Wiedergabeliste anhand eines Ordners aus dem Dateisystem generieren und importieren + + + Eine Wiedergabeliste aus einer Datei importieren + + + OK + + + Schließen + + + Abbrechen + + + Dauer + + + Ort + + + Weiter + + + Zurück + + + Lautstärke + + + Keinen Titel wiederholen + + + Einen Titel wiederholen + + + Alle Titel wiederholen + + + Zugriffsbeschränkung + + + Analysieren + + + Keine Beschränkung + + + Kein Zugriff + + + Anzahl + + + Es ist bereits ein Dialog geöffnet. Es kann kein Weiterer geöffnet werden + + + Youtubeservice wird geladen + + + Youtubeservice geladen + + + Aktuelle Wiedergabeliste + + + Lade + + + Speichere + + + Ordnerauswahl + + + Dateiauswahl + + + Anwendung wird gestartet + + + Projektseite auf GitHub.com öffnen + + + Zur Wiedergabeliste wechseln + + + Zu den Farbprofilen wechseln + + + Zu den Einstellungen wechseln + + + Ändern + + + Sprache ändern + + + Filter + + + Mediaplayers + + + Wiedergabetitel + + + Wiedergabetitel + + + Die angegebene Bedingung ist falsch. + + + Die angegebene Bedingung ist wahr. + + + Werte müssen gleich sein. + + + Werte dürfen nicht gleich sein. + + + Liste darf nicht null oder leer sein. + + + String darf nicht null, leer oder nur Leerraum enthalten. + + + Folgendes Verzeichnis wurde nicht gefunden: + + + Folgende Datei wurde nicht gefunden: + + + Ein unerwarteter Fehler ist aufgetreten. + + + Auswählen + + + Löschen + + + Aktualisieren + + + Mediaplayereinstellungen öffnen + + + Mediathek + + + Startseite + + + Über + + + Anwendung wird geschlossen + + + Anwendung geschlossen + + + Daten werden gespeichert + + + Anwendung gestartet + + + Daten werden geladen + + + Oberfläche wird geladen + + + Daten laden fehlgeschlagen + \ No newline at end of file diff --git a/src/Maple/Properties/Settings.Designer.cs b/src/Maple/Properties/Settings.Designer.cs deleted file mode 100644 index 703eb81..0000000 --- a/src/Maple/Properties/Settings.Designer.cs +++ /dev/null @@ -1,135 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Maple.Properties -{ - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.5.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase - { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default - { - get - { - return defaultInstance; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("True")] - public bool IsFirstRun - { - get - { - return ((bool)(this["IsFirstRun"])); - } - set - { - this["IsFirstRun"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("0,0")] - public global::System.Windows.Point ShellWindowLocation - { - get - { - return ((global::System.Windows.Point)(this["ShellWindowLocation"])); - } - set - { - this["ShellWindowLocation"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("0,0")] - public global::System.Windows.Size ShellWindowSize - { - get - { - return ((global::System.Windows.Size)(this["ShellWindowSize"])); - } - set - { - this["ShellWindowSize"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("Normal")] - public global::System.Windows.WindowState ShellWindowState - { - get - { - return ((global::System.Windows.WindowState)(this["ShellWindowState"])); - } - set - { - this["ShellWindowState"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("")] - public string SwatchName - { - get - { - return ((string)(this["SwatchName"])); - } - set - { - this["SwatchName"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("")] - public string AccentName - { - get - { - return ((string)(this["AccentName"])); - } - set - { - this["AccentName"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("False")] - public bool UseDarkTheme - { - get - { - return ((bool)(this["UseDarkTheme"])); - } - set - { - this["UseDarkTheme"] = value; - } - } - } -} diff --git a/src/Maple/Properties/Settings.settings b/src/Maple/Properties/Settings.settings deleted file mode 100644 index a7a38c0..0000000 --- a/src/Maple/Properties/Settings.settings +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - True - - - 0,0 - - - 0,0 - - - Normal - - - - - - - - - False - - - \ No newline at end of file diff --git a/src/Maple/Properties/launchSettings.json b/src/Maple/Properties/launchSettings.json new file mode 100644 index 0000000..9139f3e --- /dev/null +++ b/src/Maple/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "Maple": { + "commandName": "Project", + "commandLineArgs": "Debug" + } + } +} \ No newline at end of file diff --git a/src/Maple/Resources/Style.xaml b/src/Maple/Resources/Style.xaml index 2c2b839..7d818bc 100644 --- a/src/Maple/Resources/Style.xaml +++ b/src/Maple/Resources/Style.xaml @@ -1,1211 +1,544 @@ - + - - 5 - 5 - - - - - - - - + + + - - - - - - - - - - + + + - + + + - - + + + - - - - - - - + + + - - - - - - + + + + + - + - + + + - + + + + + + + - + + + + + + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - - - - - - - - - - - - + + + + + + + + + + + - + - + - + + + + + + + + + ScrollViewer.VerticalScrollBarVisibility="Auto" + VirtualizingStackPanel.IsVirtualizing="True"> + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + diff --git a/src/Maple/Shell.xaml.cs b/src/Maple/Shell.xaml.cs index 5a1e6bc..88eb8dd 100644 --- a/src/Maple/Shell.xaml.cs +++ b/src/Maple/Shell.xaml.cs @@ -1,24 +1,17 @@ -using System; -using System.Windows.Input; -using Maple.Core; +using Jot; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Abstractions; namespace Maple { public partial class Shell : IoCWindow { - private readonly ShellViewModel _datacontext; - - public Shell(ILocalizationService manager, IMessenger messenger, ShellViewModel datacontext) : base(manager, messenger) + public Shell(ILocalizationService localizationService, IScarletCommandBuilder commandBuilder, Tracker tracker) + : base(commandBuilder, localizationService) { - DataContext = datacontext ?? throw new ArgumentNullException(nameof(datacontext), $"{nameof(datacontext)} {Localization.Properties.Resources.IsRequired}"); - _datacontext = datacontext; - InitializeComponent(); - } - private void UIElement_OnPreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) - { - _datacontext.Scenes.IsExpanded = false; + tracker.Track(this); } } } diff --git a/src/Maple/ShellViewModel.cs b/src/Maple/ShellViewModel.cs new file mode 100644 index 0000000..5b36c40 --- /dev/null +++ b/src/Maple/ShellViewModel.cs @@ -0,0 +1,444 @@ +using Maple.Domain; +using Maple.Properties; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Observables; +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Maple +{ + public sealed class ShellViewModel : BusinessViewModelBase + { + private readonly ILogger _log; + private readonly Func _dbcontextFactory; + private readonly PlaylistFactory _playlistFactory; + private readonly MediaPlayerFactory _mediaPlayerFactory; + private readonly Func _audioDeviceFactory; + + public MetaDataViewModel MetaDataViewModel { get; } + + public NavigationViewModel NavigationViewModel { get; } + + public LocalizationsViewModel Localizations { get; } + + public Playlists Playlists { get; } + public MediaPlayers MediaPlayers { get; } + public AudioDevices AudioDevices { get; } + public AudioDeviceTypes AudioDeviceTypes { get; } + public OptionsViewModel OptionsViewModel { get; } + + public ShellViewModel(IScarletCommandBuilder commandBuilder, + ILoggerFactory loggerFactory, + LocalizationsViewModel localizationsViewModel, + NavigationViewModel navigationViewModel, + MetaDataViewModel metaDataViewModel, + Playlists playlists, + MediaPlayers mediaPlayers, + AudioDevices audioDevices, + AudioDeviceTypes audioDeviceTypes, + OptionsViewModel optionsViewModel, + Func dbcontextFactory, + PlaylistFactory playlistFactory, + MediaPlayerFactory mediaPlayerFactory, + Func audioDeviceFactory) + : base(commandBuilder) + { + _log = loggerFactory.CreateLogger(); + + Localizations = localizationsViewModel ?? throw new ArgumentNullException(nameof(localizationsViewModel)); + NavigationViewModel = navigationViewModel ?? throw new ArgumentNullException(nameof(navigationViewModel)); + MetaDataViewModel = metaDataViewModel ?? throw new ArgumentNullException(nameof(metaDataViewModel)); + Playlists = playlists ?? throw new ArgumentNullException(nameof(playlists)); + MediaPlayers = mediaPlayers ?? throw new ArgumentNullException(nameof(mediaPlayers)); + AudioDevices = audioDevices ?? throw new ArgumentNullException(nameof(audioDevices)); + AudioDeviceTypes = audioDeviceTypes ?? throw new ArgumentNullException(nameof(audioDeviceTypes)); + OptionsViewModel = optionsViewModel ?? throw new ArgumentNullException(nameof(optionsViewModel)); + + _dbcontextFactory = dbcontextFactory ?? throw new ArgumentNullException(nameof(dbcontextFactory)); + _playlistFactory = playlistFactory ?? throw new ArgumentNullException(nameof(playlistFactory)); + _mediaPlayerFactory = mediaPlayerFactory ?? throw new ArgumentNullException(nameof(mediaPlayerFactory)); + _audioDeviceFactory = audioDeviceFactory ?? throw new ArgumentNullException(nameof(audioDeviceFactory)); + } + + protected override async Task RefreshInternal(CancellationToken token) + { + try + { + using (var context = _dbcontextFactory()) + { + context.Database.Migrate(); + + await Playlists.Clear(); + await AudioDeviceTypes.Clear(); + await MediaPlayers.Clear(); + + // TODO fetch all settings + + await GetAudioDeviceTypes(context, token); + await GetAudioDevices(context, token); + await GetPlaylists(context, token); + await GetMediaPlayers(context, token); + + // TODO fetch and set selections + + await context.SaveChangesAsync(token); + } + } + catch (Exception ex) + { + _log.LogError(ex, Resources.AppStartLoadDataFailed); + throw; + } + } + + private async Task GetMediaPlayers(ApplicationDbContext context, CancellationToken token) + { + var players = await context.MediaPlayers.ToListAsync(token); + + foreach (var player in players) + { + var viewmodel = _mediaPlayerFactory.Create(player); + + viewmodel.Playlist = Playlists.GetById(viewmodel.PlaylistId); + viewmodel.AudioDevice = AudioDevices.GetById(viewmodel.AudioDeviceId); + + await MediaPlayers.Add(viewmodel); + } + + MediaPlayers.SelectedItem = MediaPlayers.Items.FirstOrDefault(); + } + + private async Task GetPlaylists(ApplicationDbContext context, CancellationToken token) + { + var playlists = await context.Playlists + .Include(p => p.MediaItems) + .ToListAsync(token); + + foreach (var playlist in playlists) + { + var viewmodel = _playlistFactory.Create(playlist); + await Playlists.Add(viewmodel); + viewmodel.SelectedItem = viewmodel.Items.FirstOrDefault(); + } + + Playlists.SelectedItem = Playlists.Items.FirstOrDefault(); + } + + private async Task GetAudioDeviceTypes(ApplicationDbContext context, CancellationToken token) + { + var models = await context.AudioDeviceTypes.OrderBy(p => p.Sequence).ThenBy(p => p.Name).ToListAsync(token); + + await AudioDeviceTypes.AddRange(models.Select(p => new AudioDeviceType(p))); + + AudioDeviceTypes.SelectedItem = AudioDeviceTypes.Items.FirstOrDefault(); + } + + private async Task GetAudioDevices(ApplicationDbContext context, CancellationToken token) + { + var audioDeviceFactory = _audioDeviceFactory(); + await AudioDevices.Clear(); + + var models = await context.AudioDevices.OrderBy(p => p.Sequence).ThenBy(p => p.AudioDeviceTypeId).ThenBy(p => p.Name).ToListAsync(token); + var devices = await audioDeviceFactory.Get(token); + var deviceLookup = devices.ToDictionary(p => p.GetKey()); + var modelLookup = models.ToDictionary(p => p.OsId.GetHashCode() ^ p.AudioDeviceTypeId); + + // add entries that are in the db, but not present in the system anymore + foreach (var model in models) + { + var key = model.GetKey(); + if (deviceLookup.ContainsKey(key)) + { + // update the device + var device = deviceLookup[key]; + device.UpdateFromModel(model, AudioDeviceTypes.GetById(device.Id)); + + await AudioDevices.Add(device); + } + else + { + // delete the device + context.AudioDevices.Remove(model); + } + } + + // create missing models + foreach (var device in devices) + { + var key = device.GetKey(); + if (modelLookup.ContainsKey(key)) + { + // update the device + var model = modelLookup[key]; + device.UpdateFromModel(model, AudioDeviceTypes.GetById(device.Id)); + + await AudioDevices.Add(device); + } + else + { + var model = device.GetModel(); + await AudioDevices.Add(device); + + device.UpdateFromModel(model, AudioDeviceTypes.GetById(device.Id)); + } + } + + AudioDevices.SelectedItem = AudioDevices.Items.FirstOrDefault(); + } + + protected override async Task UnloadInternal(CancellationToken token) + { + using (var context = _dbcontextFactory()) + { + await SaveAudioDeviceTypes(context, token); + await SaveAudioDevices(context, token); + await SavePlaylists(context, token); + await SaveMediaPlayers(context, token); + } + } + + private async Task SaveAudioDeviceTypes(ApplicationDbContext context, CancellationToken token) + { + var viewModels = AudioDeviceTypes.Items; + var query = context.AudioDeviceTypes.AsTracking().AsQueryable(); + + var models = await query.ToArrayAsync(token); + var lookup = models.ToDictionary(p => p.Id); + var now = DateTime.Now; + + foreach (var viewModel in viewModels) + { + if (viewModel.IsNew()) + { + var model = viewModel.GetModel(); + context.AudioDeviceTypes.Add(model); + + await context.SaveChangesAsync(token); + viewModel.Update(model); + + continue; + } + else + { + var model = lookup[viewModel.Id]; + if (viewModel.IsDeleted) + { + context.AudioDeviceTypes.Remove(model); + continue; + } + + model.Name = viewModel.Name; + model.Sequence = viewModel.Sequence; + + model.DeviceType = viewModel.DeviceType; + + model.UpdatedOn = now; + model.UpdatedBy = Environment.UserName; + + await context.SaveChangesAsync(token); + viewModel.Update(model); + } + } + + await context.SaveChangesAsync(token); + } + + private async Task SaveAudioDevices(ApplicationDbContext context, CancellationToken token) + { + var viewModels = AudioDevices.Items; + var query = context.AudioDevices.AsTracking(); + + var models = await query.ToArrayAsync(token); + var lookup = models.ToDictionary(p => p.Id); + var now = DateTime.Now; + + foreach (var viewModel in viewModels) + { + if (viewModel.IsNew()) + { + var model = viewModel.GetModel(); + + context.AudioDevices.Add(model); + await context.SaveChangesAsync(token); + viewModel.Update(model); + + continue; + } + else + { + var model = lookup[viewModel.Id]; + if (viewModel.IsDeleted) + { + context.AudioDevices.Remove(model); + continue; + } + + model.Name = viewModel.Name; + model.Sequence = viewModel.Sequence; + + model.AudioDeviceTypeId = viewModel.AudioDeviceTypeId; + + model.UpdatedOn = now; + model.UpdatedBy = Environment.UserName; + + await context.SaveChangesAsync(token); + viewModel.Update(model); + } + } + + await context.SaveChangesAsync(token); + } + + private async Task SavePlaylists(ApplicationDbContext context, CancellationToken token) + { + var viewModels = Playlists.Items; + var query = context.Playlists.AsTracking(); + + var models = await query.ToArrayAsync(token); + var lookup = models.ToDictionary(p => p.Id); + var now = DateTime.Now; + + foreach (var viewModel in viewModels) + { + if (viewModel.IsNew()) + { + var model = viewModel.GetModel(); + + context.Playlists.Add(model); + await SaveMediaItems(viewModel); + + await context.SaveChangesAsync(token); + viewModel.Update(model); + continue; + } + else + { + var model = lookup[viewModel.Id]; + if (viewModel.IsDeleted) + { + context.Playlists.Remove(model); + continue; + } + + model.Name = viewModel.Name; + model.Sequence = viewModel.Sequence; + + model.IsShuffeling = viewModel.IsShuffeling; + model.PrivacyStatus = viewModel.PrivacyStatus; + model.RepeatMode = viewModel.RepeatMode; + + model.UpdatedOn = now; + model.UpdatedBy = Environment.UserName; + + await SaveMediaItems(viewModel); + + await context.SaveChangesAsync(token); + viewModel.Update(model); + } + } + + await context.SaveChangesAsync(token); + + async Task SaveMediaItems(Playlist playlist) + { + var query = context.MediaItems.AsTracking().AsQueryable(); + + var models = await query.ToArrayAsync(token); + var lookup = models.ToDictionary(p => p.Id); + + foreach (var viewModel in playlist.Items) + { + if (viewModel.IsNew()) + { + var model = viewModel.GetModel(); + + context.MediaItems.Add(model); + + await context.SaveChangesAsync(token); + viewModel.Update(model); + continue; + } + else + { + var model = lookup[viewModel.Id]; + if (viewModel.IsDeleted) + { + context.MediaItems.Remove(model); + continue; + } + + model.Name = viewModel.Name; + model.Sequence = viewModel.Sequence; + + model.Duration = viewModel.Duration; + model.PrivacyStatus = viewModel.PrivacyStatus; + model.MediaItemType = viewModel.MediaItemType; + + model.UpdatedOn = now; + model.UpdatedBy = Environment.UserName; + + await context.SaveChangesAsync(token); + viewModel.Update(model); + } + } + + await context.SaveChangesAsync(token); + } + } + + private async Task SaveMediaPlayers(ApplicationDbContext context, CancellationToken token) + { + var viewModels = MediaPlayers.Items; + var query = context.MediaPlayers.AsTracking().AsQueryable(); + + var models = await query.ToArrayAsync(token); + var lookup = models.ToDictionary(p => p.Id); + var now = DateTime.Now; + + foreach (var viewModel in viewModels) + { + if (viewModel.IsNew()) + { + viewModel.AudioDeviceId = viewModel.AudioDevice?.Id; + viewModel.PlaylistId = viewModel.Playlist?.Id; + + var model = viewModel.GetModel(); + + context.MediaPlayers.Add(model); + + await context.SaveChangesAsync(token); + viewModel.Update(model); + continue; + } + else + { + var model = lookup[viewModel.Id]; + if (viewModel.IsDeleted) + { + context.MediaPlayers.Remove(model); + continue; + } + + model.Name = viewModel.Name; + model.Sequence = viewModel.Sequence; + + model.AudioDeviceId = viewModel.AudioDeviceId; + model.IsPrimary = viewModel.IsPrimary; + model.PlaylistId = viewModel.PlaylistId; + + model.UpdatedOn = now; + model.UpdatedBy = Environment.UserName; + + await context.SaveChangesAsync(token); + viewModel.Update(model); + } + } + + await context.SaveChangesAsync(token); + } + } +} diff --git a/src/Maple/SplashScreen.xaml.cs b/src/Maple/SplashScreen.xaml.cs deleted file mode 100644 index b6793c2..0000000 --- a/src/Maple/SplashScreen.xaml.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using Maple.Core; - -namespace Maple -{ - public partial class SplashScreen : IoCWindow - { - public SplashScreen(ILocalizationService manager, IMessenger messenger, ISplashScreenViewModel datacontext) : base(manager, messenger) - { - DataContext = datacontext ?? throw new ArgumentNullException(nameof(datacontext), $"{nameof(datacontext)} {Localization.Properties.Resources.IsRequired}"); - - InitializeComponent(); - } - } -} diff --git a/src/Maple/UI/Base/ConfigurableWindow.cs b/src/Maple/UI/Base/ConfigurableWindow.cs deleted file mode 100644 index 6fac2f1..0000000 --- a/src/Maple/UI/Base/ConfigurableWindow.cs +++ /dev/null @@ -1,134 +0,0 @@ -using System; -using System.Threading; -using System.Windows; -using System.Windows.Threading; -using MahApps.Metro.Controls; -using Maple.Core; - -namespace Maple -{ - public abstract class ConfigurableWindow : MetroWindow - { - private bool _isLoaded; - private readonly IConfigurableWindowSettings _settings; - - /// - /// Initializes a new instance of the class. - /// - /// _settings - Cannot be null. - protected ConfigurableWindow() - { - _settings = CreateSettings(); - - if (_settings == null) - throw new ArgumentNullException(nameof(_settings), $"{nameof(_settings)} {Localization.Properties.Resources.IsRequired}"); - - Loaded += delegate { _isLoaded = true; }; - - ApplySettings(); - } - - /// - /// Derived classes must return the object which exposes - /// persisted window settings. This method is only invoked - /// once per Window, during construction. - /// - /// - protected abstract IConfigurableWindowSettings CreateSettings(); - - /// - /// Raises the event. - /// - /// An that contains the event data. - protected override void OnLocationChanged(EventArgs e) - { - base.OnLocationChanged(e); - - // We need to delay this call because we are - // notified of a location change before a - // window state change. That causes a problem - // when maximizing the window because we record - // the maximized window's location, which is not - // something worth saving. - Dispatcher.BeginInvoke(DispatcherPriority.Background, new ThreadStart(() => - { - if (_isLoaded && WindowState == WindowState.Normal) - { - var loc = new Point(Left, Top); - _settings.WindowLocation = loc; - } - })); - } - - /// - /// When overridden in a derived class, participates in rendering operations that are directed by the layout system. This method is invoked after layout update, and before rendering, if the element's has changed as a result of layout update. - /// - /// The packaged parameters (), which includes old and new sizes, and which dimension actually changes. - protected override void OnRenderSizeChanged(SizeChangedInfo info) - { - base.OnRenderSizeChanged(info); - - if (_isLoaded && WindowState == WindowState.Normal) - { - _settings.WindowSize = RenderSize; - } - } - - /// - /// Raises the event. - /// - /// An that contains the event data. - protected override void OnStateChanged(EventArgs e) - { - base.OnStateChanged(e); - - if (_isLoaded) - { - // We don't want the Window to open in the - // minimized state, so ignore that value. - if (WindowState != WindowState.Minimized) - _settings.WindowState = WindowState; - else - _settings.WindowState = WindowState.Normal; - } - } - - /// - /// Applies the settings. - /// - void ApplySettings() - { - var size = _settings.WindowSize; - SetCurrentValue(WidthProperty, size.Width); - SetCurrentValue(HeightProperty, size.Height); - - var location = _settings.WindowLocation; - - // If the user's machine had two monitors but now only - // has one, and the Window was previously on the other - // monitor, we need to move the Window into view. - var outOfBounds = location.X <= -size.Width - || location.Y <= -size.Height - || SystemParameters.VirtualScreenWidth <= location.X - || SystemParameters.VirtualScreenHeight <= location.Y; - - if (_settings.IsFirstRun || outOfBounds) - WindowStartupLocation = WindowStartupLocation.CenterScreen; - else - { - WindowStartupLocation = WindowStartupLocation.Manual; - - SetCurrentValue(LeftProperty, location.X); - SetCurrentValue(TopProperty, location.Y); - - // We need to wait until the HWND window is initialized before - // setting the state, to ensure that this works correctly on - // a multi-monitor system. Thanks to Andrew Smith for this fix. - SourceInitialized += delegate - { - SetCurrentValue(WindowStateProperty, _settings.WindowState); - }; - } - } - } -} diff --git a/src/Maple/UI/Base/ConfigurableWindowSettings.cs b/src/Maple/UI/Base/ConfigurableWindowSettings.cs deleted file mode 100644 index 68a9497..0000000 --- a/src/Maple/UI/Base/ConfigurableWindowSettings.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System.Configuration; -using System.Windows; -using Maple.Core; - -namespace Maple -{ - /// - /// - /// - /// - public abstract class ConfigurableWindowSettings : IConfigurableWindowSettings - { - private readonly ApplicationSettingsBase _settings; - - private readonly string _isFirstRunProp; - private readonly string _windowLocationProp; - private readonly string _windowSizeProp; - private readonly string _windowStateProp; - - /// - /// Returns true if the application has never - /// been run before by the current user. If - /// this returns true, the Window's initial - /// location is determined by the operating - /// system, not the WindowLocation property. - /// - /// - /// true if this instance is first run; otherwise, false. - /// - public bool IsFirstRun - { - get { return GetValue(_isFirstRunProp); } - protected set { SetValue(_isFirstRunProp, value); } - } - - /// - /// Gets/sets the Window's desktop coordinate. - /// - /// - /// The window location. - /// - public Point WindowLocation - { - get { return GetValue(_windowLocationProp); } - set { SetValue(_windowLocationProp, value); } - } - - /// - /// Gets/sets the size of the Window. - /// - /// - /// The size of the window. - /// - public Size WindowSize - { - get { return GetValue(_windowSizeProp); } - set { SetValue(_windowSizeProp, value); } - } - - /// - /// Gets/sets the WindowState of the Window. - /// - /// - /// The state of the window. - /// - public WindowState WindowState - { - get { return GetValue(_windowStateProp); } - set { SetValue(_windowStateProp, value); } - } - - /// - /// Initializes a new instance of the class. - /// - /// The settings. - /// The is first run property. - /// The window location property. - /// The window size property. - /// The window state property. - protected ConfigurableWindowSettings(ApplicationSettingsBase settings, string isFirstRunProp, string windowLocationProp, string windowSizeProp, string windowStateProp) - { - _settings = settings; - - _isFirstRunProp = isFirstRunProp; - _windowLocationProp = windowLocationProp; - _windowSizeProp = windowSizeProp; - _windowStateProp = windowStateProp; - } - - /// - /// Gets the value. - /// - /// - /// Name of the property. - /// - protected T GetValue(string propName) - { - return (T)_settings[propName]; - } - - /// - /// Sets the value. - /// - /// Name of the property. - /// The value. - protected void SetValue(string propName, object value) - { - _settings[propName] = value; - _settings.Save(); - } - } -} diff --git a/src/Maple/UI/Base/IocUserControl.cs b/src/Maple/UI/Base/IocUserControl.cs deleted file mode 100644 index b32b157..0000000 --- a/src/Maple/UI/Base/IocUserControl.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Diagnostics; -using System.Windows.Controls; -using Maple.Core; - -namespace Maple -{ - public abstract class IoCUserControl : UserControl, IIocFrameworkElement - { - public ILocalizationService TranslationManager { get; private set; } - - protected IoCUserControl() : base() - { - if (Debugger.IsAttached) - Debug.Fail($"The constructor without parameters of {nameof(IoCUserControl)} exists only for compatibility reasons."); - } - - protected IoCUserControl(ILocalizationService manager) : base() - { - TranslationManager = manager; - } - } -} diff --git a/src/Maple/UI/Base/SharedResourceDictionary.cs b/src/Maple/UI/Base/SharedResourceDictionary.cs deleted file mode 100644 index b4b8e84..0000000 --- a/src/Maple/UI/Base/SharedResourceDictionary.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Windows; - -namespace Maple -{ - // Source: https://www.wpftutorial.net/MergedDictionaryPerformance.html - /// - /// The shared resource dictionary is a specialized resource dictionary - /// that loads it content only once. If a second instance with the same source - /// is created, it only merges the resources from the cache. - /// - /// - public class SharedResourceDictionary : ResourceDictionary - { - /// - /// Internal cache of loaded dictionaries - /// - public static readonly Dictionary _sharedDictionaries = new Dictionary(); - - /// - /// Local member of the source uri - /// - private Uri _sourceUri; - - /// - /// Gets or sets the uniform resource identifier (URI) to load resources from. - /// - public new Uri Source - { - get { return _sourceUri; } - set - { - _sourceUri = value; - - if (!_sharedDictionaries.ContainsKey(value)) - { - // If the dictionary is not yet loaded, load it by setting - // the source of the base class - base.Source = value; - - // add it to the cache - _sharedDictionaries.Add(value, this); - } - else - { - // If the dictionary is already loaded, get it from the cache - MergedDictionaries.Add(_sharedDictionaries[value]); - } - } - } - } -} diff --git a/src/Maple/UI/BindingProxy.cs b/src/Maple/UI/BindingProxy.cs deleted file mode 100644 index cd8e696..0000000 --- a/src/Maple/UI/BindingProxy.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Windows; - -namespace Maple -{ - /// - /// Proxy class for binding to objects outside the current datacontext in xaml - /// - /// - public class BindingProxy : Freezable - { - // Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc... - public static readonly DependencyProperty DataProperty = DependencyProperty.Register( - nameof(Data), - typeof(object), - typeof(BindingProxy), - new UIPropertyMetadata(null)); - - /// - /// When implemented in a derived class, creates a new instance of the derived class. - /// - /// - /// The new instance. - /// - protected override Freezable CreateInstanceCore() - { - return new BindingProxy(); - } - - /// - /// Gets or sets the data. - /// - /// - /// The data. - /// - public object Data - { - get { return GetValue(DataProperty); } - set { SetValue(DataProperty, value); } - } - } -} diff --git a/src/Maple/UI/FileSystemBrowserDetailTemplateSelector.cs b/src/Maple/UI/FileSystemBrowserDetailTemplateSelector.cs deleted file mode 100644 index cecaef7..0000000 --- a/src/Maple/UI/FileSystemBrowserDetailTemplateSelector.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Windows; -using System.Windows.Controls; -using Maple.Core; - -namespace Maple -{ - public class FileSystemBrowserDetailTemplateSelector : DataTemplateSelector - { - public DataTemplate DriveTemplate { get; set; } - public DataTemplate FolderTemplate { get; set; } - public DataTemplate FileTemplate { get; set; } - - public override DataTemplate SelectTemplate(object item, DependencyObject container) - { - switch (item) - { - case MapleFile _: - return FileTemplate; - - case MapleDirectory _: - return FolderTemplate; - - case MapleDrive _: - return DriveTemplate; - } - - return base.SelectTemplate(item, container); - } - } -} diff --git a/src/Maple/UI/Interactivity/SelectedTreeViewItemBehavior.cs b/src/Maple/UI/Interactivity/SelectedTreeViewItemBehavior.cs deleted file mode 100644 index 7a6b232..0000000 --- a/src/Maple/UI/Interactivity/SelectedTreeViewItemBehavior.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System.Windows; -using System.Windows.Controls; -using System.Windows.Interactivity; - -namespace Maple -{ - /// - /// Provides oneway readonly Binding Support for the Treeview control to support binding to a selected item, - /// - /// - /// - public class SelectedTreeViewItemBehavior : Behavior - { - /// - /// Gets or sets the selected item. - /// - /// - /// The selected item. - /// - /// - public object SelectedItem - { - get { return GetValue(SelectedItemProperty); } - set { SetValue(SelectedItemProperty, value); } - } - - /// - /// The selected item property - /// - /// - public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register( - nameof(SelectedItem), - typeof(object), - typeof(SelectedTreeViewItemBehavior), - new UIPropertyMetadata(default(object), OnSelectedItemChanged)); - - private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) - { - var item = e.NewValue as TreeViewItem; - - item?.SetCurrentValue(TreeViewItem.IsSelectedProperty, true); - } - - /// - /// Called when [attached]. - /// - /// - protected override void OnAttached() - { - base.OnAttached(); - - AssociatedObject.SelectedItemChanged += OnTreeViewSelectedItemChanged; - } - - /// - /// Called when [detaching]. - /// - /// - protected override void OnDetaching() - { - base.OnDetaching(); - - if (AssociatedObject != null) - AssociatedObject.SelectedItemChanged -= OnTreeViewSelectedItemChanged; - } - - private void OnTreeViewSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs e) - { - SetCurrentValue(SelectedItemProperty, e.NewValue); - } - } -} diff --git a/src/Maple/UI/IoCResourceDictionary.cs b/src/Maple/UI/IoCResourceDictionary.cs deleted file mode 100644 index 127cfe2..0000000 --- a/src/Maple/UI/IoCResourceDictionary.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Diagnostics; -using Maple.Core; - -namespace Maple -{ - /// - /// SharedResourceDictionary to support - /// - /// - /// - public class IoCResourceDictionary : SharedResourceDictionary, IIocFrameworkElement - { - /// - /// Gets the translation manager. - /// - /// - /// The translation manager. - /// - public ILocalizationService TranslationManager { get; private set; } - - /// - /// Initializes a new instance of the class. - /// - public IoCResourceDictionary() : base() - { - Debug.Fail($"The constructor without parameters of {nameof(IoCResourceDictionary)} exists only for compatibility reasons."); - } - - /// - /// Initializes a new instance of the class. - /// - /// The translation manager. - public IoCResourceDictionary(ILocalizationService service, Uri url) : base() - { - TranslationManager = service; - Source = url; - Add(typeof(ILocalizationService).Name, service); - } - } -} diff --git a/src/Maple/UI/ListBox.cs b/src/Maple/UI/ListBox.cs deleted file mode 100644 index 2587dcc..0000000 --- a/src/Maple/UI/ListBox.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Collections; -using System.Windows; -using System.Windows.Controls; - -namespace Maple -{ - public class ListBox : System.Windows.Controls.ListBox - { - public static readonly DependencyProperty SelectedItemsListProperty = DependencyProperty.Register( - nameof(SelectedEntriesList), - typeof(IList), - typeof(ListBox), - new FrameworkPropertyMetadata(default(IList), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); - - public IList SelectedEntriesList - { - get { return (IList)GetValue(SelectedItemsListProperty); } - set { SetValue(SelectedItemsListProperty, value); } - } - - public ListBox() - { - SelectionChanged += ListBoxCustom_SelectionChanged; - } - - void ListBoxCustom_SelectionChanged(object sender, SelectionChangedEventArgs e) - { - SelectedEntriesList = SelectedItems; - } - } -} diff --git a/src/Maple/UI/MarkupExtensions/Base/ConverterMarkupExtension.cs b/src/Maple/UI/MarkupExtensions/Base/ConverterMarkupExtension.cs deleted file mode 100644 index 47aed3d..0000000 --- a/src/Maple/UI/MarkupExtensions/Base/ConverterMarkupExtension.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Globalization; -using System.Windows.Data; -using System.Windows.Markup; - -namespace Maple -{ - public abstract class ConverterMarkupExtension : MarkupExtension, IValueConverter - where T : class, new() - { - private static T _debugConverter = null; - - public override object ProvideValue(IServiceProvider serviceProvider) - { - return _debugConverter ?? (_debugConverter = new T()); - } - - public abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture); - - public abstract object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture); - } -} diff --git a/src/Maple/UI/MarkupExtensions/Base/MultiConverterMarkupExtension.cs b/src/Maple/UI/MarkupExtensions/Base/MultiConverterMarkupExtension.cs deleted file mode 100644 index 27dbbfa..0000000 --- a/src/Maple/UI/MarkupExtensions/Base/MultiConverterMarkupExtension.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Globalization; -using System.Windows.Data; -using System.Windows.Markup; - -namespace Maple -{ - public abstract class MultiConverterMarkupExtension : MarkupExtension, IMultiValueConverter - where T : class, new() - { - private static T _debugConverter = null; - - public override object ProvideValue(IServiceProvider serviceProvider) - { - return _debugConverter ?? (_debugConverter = new T()); - } - - public abstract object Convert(object[] values, Type targetType, object parameter, CultureInfo culture); - - public abstract object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture); - } -} diff --git a/src/Maple/UI/MarkupExtensions/BreakingDebugConverter.cs b/src/Maple/UI/MarkupExtensions/BreakingDebugConverter.cs deleted file mode 100644 index 7387b12..0000000 --- a/src/Maple/UI/MarkupExtensions/BreakingDebugConverter.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Diagnostics; -using System.Globalization; -using System.Windows.Data; - -namespace Maple -{ - [ValueConversion(typeof(object), typeof(object))] - public class BreakingDebugConverter : ConverterMarkupExtension, IValueConverter - { - public override object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - Debugger.Break(); - return value; - } - - public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - Debugger.Break(); - return value; - } - } -} diff --git a/src/Maple/UI/MarkupExtensions/BrushRoundConverter.cs b/src/Maple/UI/MarkupExtensions/BrushRoundConverter.cs deleted file mode 100644 index 19f812f..0000000 --- a/src/Maple/UI/MarkupExtensions/BrushRoundConverter.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Globalization; -using System.Windows.Data; -using System.Windows.Media; - -namespace Maple -{ - [ValueConversion(typeof(SolidColorBrush), typeof(Brush))] - public class BrushRoundConverter : ConverterMarkupExtension, IValueConverter - { - public Brush HighValue { get; set; } = Brushes.White; - public Brush LowValue { get; set; } = Brushes.Black; - - public override object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - var solidColorBrush = value as SolidColorBrush; - if (solidColorBrush == null) - return null; - - var color = solidColorBrush.Color; - - var brightness = 0.3 * color.R + 0.59 * color.G + 0.11 * color.B; - - return brightness < 123 ? LowValue : HighValue; - } - - public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - return Binding.DoNothing; - } - } -} diff --git a/src/Maple/UI/MarkupExtensions/CaseConverter.cs b/src/Maple/UI/MarkupExtensions/CaseConverter.cs deleted file mode 100644 index 1de13e6..0000000 --- a/src/Maple/UI/MarkupExtensions/CaseConverter.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Windows.Controls; -using System.Windows.Data; - -namespace Maple -{ - [ValueConversion(typeof(string), typeof(string))] - public class CaseConverter : ConverterMarkupExtension, IValueConverter - { - public CharacterCasing Case { get; set; } - - public CaseConverter() - { - Case = CharacterCasing.Upper; - } - - public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) - { - if (value is string str) - { - switch (Case) - { - case CharacterCasing.Lower: - return str.ToLower(); - case CharacterCasing.Normal: - return str; - case CharacterCasing.Upper: - return str.ToUpper(); - default: - return str; - } - } - return string.Empty; - } - - public override object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) - { - return Binding.DoNothing; - } - } -} diff --git a/src/Maple/UI/MarkupExtensions/MathMultipleConverter.cs b/src/Maple/UI/MarkupExtensions/MathMultipleConverter.cs deleted file mode 100644 index b76554b..0000000 --- a/src/Maple/UI/MarkupExtensions/MathMultipleConverter.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Globalization; -using System.Windows.Data; -using MaterialDesignThemes.Wpf.Converters; - -namespace Maple -{ - [ValueConversion(typeof(object[]), typeof(double))] - public sealed class MathMultipleConverter : MultiConverterMarkupExtension, IMultiValueConverter - { - public MathOperation Operation { get; set; } - - public override object Convert(object[] value, Type targetType, object parameter, CultureInfo culture) - { - if (value == null || value.Length < 2 || value[0] == null || value[1] == null) - return Binding.DoNothing; - - if (!double.TryParse(value[0].ToString(), out var value1) || !double.TryParse(value[1].ToString(), out var value2)) - return 0; - - switch (Operation) - { - default: - // (case MathOperation.Add:) - return value1 + value2; - case MathOperation.Divide: - return value1 / value2; - case MathOperation.Multiply: - return value1 * value2; - case MathOperation.Subtract: - return value1 - value2; - } - } - - public override object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) - { - return new[] - { - Binding.DoNothing, - Binding.DoNothing, - }; - } - } -} diff --git a/src/Maple/UI/MarkupExtensions/PrintingDebugConverter.cs b/src/Maple/UI/MarkupExtensions/PrintingDebugConverter.cs deleted file mode 100644 index 03f3b6e..0000000 --- a/src/Maple/UI/MarkupExtensions/PrintingDebugConverter.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Diagnostics; -using System.Globalization; -using System.Windows.Data; - -namespace Maple -{ - [ValueConversion(typeof(object), typeof(object))] - public class PrintingDebugConverter : ConverterMarkupExtension, IValueConverter - { - public override object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - Debug.WriteLine(value); - return value; - } - - public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - Debug.WriteLine(value); - return value; - } - } -} diff --git a/src/Maple/UI/MarkupExtensions/RadioButtonCheckedConverter.cs b/src/Maple/UI/MarkupExtensions/RadioButtonCheckedConverter.cs deleted file mode 100644 index d3d7d3e..0000000 --- a/src/Maple/UI/MarkupExtensions/RadioButtonCheckedConverter.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Windows.Data; - -namespace Maple -{ - /// - /// - /// - /// - [ValueConversion(typeof(object), typeof(bool))] - public class RadioButtonCheckedConverter : ConverterMarkupExtension, IValueConverter - { - /// - /// Converts a value. - /// - /// The value produced by the binding source. - /// The type of the binding target property. - /// The converter parameter to use. - /// The culture to use in the converter. - /// - /// A converted value. If the method returns null, the valid null value is used. - /// - public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) - { - return value.Equals(parameter); - } - - /// - /// Converts a value. - /// - /// The value that is produced by the binding target. - /// The type to convert to. - /// The converter parameter to use. - /// The culture to use in the converter. - /// - /// A converted value. If the method returns null, the valid null value is used. - /// - public override object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) - { - return value.Equals(true) ? parameter : Binding.DoNothing; - } - } -} diff --git a/src/Maple/UI/ShellSettings.cs b/src/Maple/UI/ShellSettings.cs deleted file mode 100644 index 7a39dbb..0000000 --- a/src/Maple/UI/ShellSettings.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Maple.Properties; - -namespace Maple -{ - public class ShellSettings : ConfigurableWindowSettings - { - // the values of these consts have to be added in the project settings with their according type set - // so, IsFirstRun has to be added and be set as a bool for instance - - const string IS_FIRST_RUN = "IsFirstRun"; - const string WINDOW_LOCATION = "ShellWindowLocation"; - const string WINDOW_SIZE = "ShellWindowSize"; - const string WINDOW_STATE = "ShellWindowState"; - - public ShellSettings(IoCWindow window) - : base( - Settings.Default, - IS_FIRST_RUN, - WINDOW_LOCATION, - WINDOW_SIZE, - WINDOW_STATE) - { - // Note: You only want to have this code - // in the application's main Window, not - // in dialog boxes or other child Windows. - window.Closed += delegate - { - if (IsFirstRun) - IsFirstRun = false; - }; - } - } -} diff --git a/src/Maple/UI/UserControls/MediaPlayerPage.xaml b/src/Maple/UI/UserControls/MediaPlayerPage.xaml deleted file mode 100644 index 1c24d5b..0000000 --- a/src/Maple/UI/UserControls/MediaPlayerPage.xaml +++ /dev/null @@ -1,285 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Maple/UI/UserControls/Options/OptionsPage.xaml.cs b/src/Maple/UI/UserControls/Options/OptionsPage.xaml.cs deleted file mode 100644 index 3228e2c..0000000 --- a/src/Maple/UI/UserControls/Options/OptionsPage.xaml.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Maple.Core; - -namespace Maple -{ - public partial class OptionsPage - { - public OptionsPage(ILocalizationService manager) - : base(manager) - { - InitializeComponent(); - } - } -} diff --git a/src/Maple/UI/UserControls/Playlist/NewPlaylistOptionsPage.xaml b/src/Maple/UI/UserControls/Playlist/NewPlaylistOptionsPage.xaml deleted file mode 100644 index e7bda0b..0000000 --- a/src/Maple/UI/UserControls/Playlist/NewPlaylistOptionsPage.xaml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - NewPlaylistOptionsPage - - - diff --git a/src/Maple/UI/UserControls/Playlist/NewPlaylistOptionsPage.xaml.cs b/src/Maple/UI/UserControls/Playlist/NewPlaylistOptionsPage.xaml.cs deleted file mode 100644 index 852826c..0000000 --- a/src/Maple/UI/UserControls/Playlist/NewPlaylistOptionsPage.xaml.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Maple.Core; - -namespace Maple -{ - public partial class NewPlaylistOptionsPage - { - public NewPlaylistOptionsPage(ILocalizationService manager) - : base(manager) - { - InitializeComponent(); - } - } -} diff --git a/src/Maple/UI/UserControls/Playlist/NewPlaylistPage.xaml b/src/Maple/UI/UserControls/Playlist/NewPlaylistPage.xaml deleted file mode 100644 index a10867f..0000000 --- a/src/Maple/UI/UserControls/Playlist/NewPlaylistPage.xaml +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Maple/UI/UserControls/Playlist/PlaylistsPage.xaml.cs b/src/Maple/UI/UserControls/Playlist/PlaylistsPage.xaml.cs deleted file mode 100644 index dc83d72..0000000 --- a/src/Maple/UI/UserControls/Playlist/PlaylistsPage.xaml.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Maple.Core; - -namespace Maple -{ - public partial class PlaylistsPage - { - public PlaylistsPage(ILocalizationService manager) - : base(manager) - { - InitializeComponent(); - } - } -} diff --git a/src/Maple/Utils/Validation/Base/BaseValidator.cs b/src/Maple/Util/BaseValidator.cs similarity index 66% rename from src/Maple/Utils/Validation/Base/BaseValidator.cs rename to src/Maple/Util/BaseValidator.cs index 66d88a9..e4dfb01 100644 --- a/src/Maple/Utils/Validation/Base/BaseValidator.cs +++ b/src/Maple/Util/BaseValidator.cs @@ -1,7 +1,6 @@ -using System; +using System; using FluentValidation; -using Maple.Core; -using Maple.Localization.Properties; +using MvvmScarletToolkit.Abstractions; namespace Maple { @@ -11,7 +10,7 @@ public abstract class BaseValidator : AbstractValidator, IValidator protected BaseValidator(ILocalizationService translationService) { - _translationService = translationService ?? throw new ArgumentNullException(nameof(translationService), $"{nameof(translationService)} {Resources.IsRequired}"); + _translationService = translationService ?? throw new ArgumentNullException(nameof(translationService)); } } } diff --git a/src/Maple/Util/DialogWindow.cs b/src/Maple/Util/DialogWindow.cs new file mode 100644 index 0000000..190bef6 --- /dev/null +++ b/src/Maple/Util/DialogWindow.cs @@ -0,0 +1,63 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Input; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Abstractions; + +namespace Maple +{ + public class DialogWindow : IoCWindow + { + public ICommand AcceptCommand + { + get { return (ICommand)GetValue(AcceptCommandProperty); } + set { SetValue(AcceptCommandProperty, value); } + } + + public static readonly DependencyProperty AcceptCommandProperty = DependencyProperty.Register( + nameof(AcceptCommand), + typeof(ICommand), + typeof(DialogWindow), + new PropertyMetadata(default(ICommand))); + + private readonly IScarletCommandBuilder _commandBuilder; + + public DialogWindow() + : base() + { + } + + public DialogWindow(IScarletCommandBuilder commandBuilder, ILocalizationService localizationService, Window owner, CancellationToken abort) + : base(commandBuilder, localizationService) + { + _commandBuilder = commandBuilder ?? throw new ArgumentNullException(nameof(commandBuilder)); + + if (owner is null) + { + throw new ArgumentNullException(nameof(owner)); + } + + Owner = owner; + AcceptCommand = commandBuilder.Create(Accept, CanAccept) + .WithAsyncCancellation() + .WithSingleExecution() + .Build(); + + abort.Register(Close); + } + + protected virtual async Task Accept(CancellationToken token) + { + await _commandBuilder.Dispatcher.Invoke(() => DialogResult = true); + await _commandBuilder.Dispatcher.Invoke(() => Close()); + } + + protected virtual bool CanAccept() + { + return true; + } + } +} diff --git a/src/Maple.Core/Extensions/IValidatorExtensions.cs b/src/Maple/Util/Extensions/IValidatorExtensions.cs similarity index 90% rename from src/Maple.Core/Extensions/IValidatorExtensions.cs rename to src/Maple/Util/Extensions/IValidatorExtensions.cs index 0992a28..f37ba73 100644 --- a/src/Maple.Core/Extensions/IValidatorExtensions.cs +++ b/src/Maple/Util/Extensions/IValidatorExtensions.cs @@ -1,8 +1,8 @@ -using FluentValidation; +using FluentValidation; using FluentValidation.Internal; using FluentValidation.Results; -namespace Maple.Core +namespace Maple { public static class IValidatorExtensions { diff --git a/src/Maple/Util/Extensions/LinqExtensions.cs b/src/Maple/Util/Extensions/LinqExtensions.cs new file mode 100644 index 0000000..ad63c73 --- /dev/null +++ b/src/Maple/Util/Extensions/LinqExtensions.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Maple +{ + public static class LinqExtensions + { + public static T Random(this IEnumerable baseCollection) + { + if (baseCollection is null) + throw new ArgumentNullException(nameof(baseCollection)); + + // note: creating a Random instance each call may not be correct for you, + // consider a thread-safe static instance + var r = new Random(); + var list = baseCollection as IList ?? baseCollection.ToList(); + return list.Count == 0 ? default : list[r.Next(0, list.Count)]; + } + } +} diff --git a/src/Maple/Util/FileSystemBrowserDetailTemplateSelector.cs b/src/Maple/Util/FileSystemBrowserDetailTemplateSelector.cs new file mode 100644 index 0000000..1488716 --- /dev/null +++ b/src/Maple/Util/FileSystemBrowserDetailTemplateSelector.cs @@ -0,0 +1,25 @@ +using System.Windows; +using System.Windows.Controls; +using MvvmScarletToolkit.Wpf.FileSystemBrowser; + +namespace Maple +{ + public sealed class FileSystemBrowserDetailTemplateSelector : DataTemplateSelector + { + public DataTemplate DriveTemplate { get; set; } + public DataTemplate FolderTemplate { get; set; } + public DataTemplate FileTemplate { get; set; } + + public override DataTemplate SelectTemplate(object item, DependencyObject container) + { + return item switch + { + ScarletFile _ => FileTemplate, + ScarletDirectory _ => FolderTemplate, + ScarletDrive _ => DriveTemplate, + + _ => base.SelectTemplate(item, container), + }; + } + } +} diff --git a/src/Maple/Util/FileSystemBrowserDialog.xaml b/src/Maple/Util/FileSystemBrowserDialog.xaml new file mode 100644 index 0000000..346e852 --- /dev/null +++ b/src/Maple/Util/FileSystemBrowserDialog.xaml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Maple/Util/FileSystemBrowserDialog.xaml.cs b/src/Maple/Util/FileSystemBrowserDialog.xaml.cs new file mode 100644 index 0000000..92d9a3f --- /dev/null +++ b/src/Maple/Util/FileSystemBrowserDialog.xaml.cs @@ -0,0 +1,45 @@ +using System; +using System.Threading; +using System.Windows; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Abstractions; +using MvvmScarletToolkit.Wpf.FileSystemBrowser; + +namespace Maple +{ + public partial class FileSystemBrowserDialog : DialogWindow + { + private readonly FileSystemViewModel _fileSystemViewModel; + + public FileSystemBrowserDialog() + : base() + { + } + + public FileSystemBrowserDialog(IScarletCommandBuilder commandBuilder, ILocalizationService localizationService, Window owner, CancellationToken abort, FileSystemViewModel fileSystemViewModel) + : base(commandBuilder, localizationService, owner, abort) + { + _fileSystemViewModel = fileSystemViewModel ?? throw new ArgumentNullException(nameof(fileSystemViewModel)); + + if (owner is null) + { + throw new ArgumentNullException(nameof(owner)); + } + + InitializeComponent(); + + Owner = owner; + DataContext = fileSystemViewModel; + } + + public FileSystemBrowserDialog(DialogWindow owner, CancellationToken abort, FileSystemViewModel fileSystemViewModel) + : this(owner.CommandBuilder, owner.LocalizationService, owner, abort, fileSystemViewModel) + { + } + + protected override bool CanAccept() + { + return _fileSystemViewModel.SelectedItem is IFileSystemFile; + } + } +} diff --git a/src/Maple/Util/ImageFilePathFallback.cs b/src/Maple/Util/ImageFilePathFallback.cs new file mode 100644 index 0000000..b91dd4d --- /dev/null +++ b/src/Maple/Util/ImageFilePathFallback.cs @@ -0,0 +1,52 @@ +using System; +using System.Globalization; +using System.IO; +using System.Windows.Data; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using MvvmScarletToolkit; + +namespace Maple +{ + [ValueConversion(typeof(string), typeof(ImageSource))] + public sealed class ImageFilePathFallback : ConverterMarkupExtension + { + public override object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (!(value is string path)) + { + return GetDefault(); + } + + if (path.Length <= 3) + { + return GetDefault(); + } + + if (!File.Exists(path)) + { + return GetDefault(); + } + + var bitmap = new BitmapImage(); + + bitmap.BeginInit(); + bitmap.CacheOption = BitmapCacheOption.OnLoad; + bitmap.UriSource = new Uri(path, UriKind.RelativeOrAbsolute); + bitmap.EndInit(); + + return bitmap; + } + + private static BitmapSource GetDefault() + { + var format = PixelFormats.Bgra32; + var width = 200; + var height = 200; + var rawStride = ((width * format.BitsPerPixel) + 7) / 8; + var rawImage = new byte[rawStride * height]; + + return BitmapSource.Create(width, height, 96, 96, format, null, rawImage, rawStride); + } + } +} diff --git a/src/Maple/Util/IoCResourceDictionary.cs b/src/Maple/Util/IoCResourceDictionary.cs new file mode 100644 index 0000000..252c1c2 --- /dev/null +++ b/src/Maple/Util/IoCResourceDictionary.cs @@ -0,0 +1,25 @@ +using System; +using System.ComponentModel; +using System.Windows; +using MvvmScarletToolkit.Abstractions; + +namespace Maple +{ + public sealed class IoCResourceDictionary : ResourceDictionary, IIocFrameworkElement + { + public ILocalizationService LocalizationService { get; } + + public IScarletEventManager WeakEventManager { get; } + + public IoCResourceDictionary(ILocalizationService localizationService, IScarletEventManager weakEventManager, Uri source) + : base() + { + LocalizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService)); + WeakEventManager = weakEventManager ?? throw new ArgumentNullException(nameof(weakEventManager)); + Source = source ?? throw new ArgumentNullException(nameof(source)); + + Add(typeof(IScarletEventManager).Name, weakEventManager); + Add(typeof(ILocalizationService).Name, localizationService); + } + } +} diff --git a/src/Maple/UI/Base/IoCWindow.cs b/src/Maple/Util/IoCWindow.cs similarity index 50% rename from src/Maple/UI/Base/IoCWindow.cs rename to src/Maple/Util/IoCWindow.cs index 21b9769..c3cfc00 100644 --- a/src/Maple/UI/Base/IoCWindow.cs +++ b/src/Maple/Util/IoCWindow.cs @@ -1,59 +1,69 @@ -using System; +using System; +using System.ComponentModel; using System.Diagnostics; using System.IO; +using System.Threading; +using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; -using Maple.Core; +using AdonisUI.Controls; using Maple.Domain; +using MvvmScarletToolkit; +using MvvmScarletToolkit.Abstractions; namespace Maple { - public abstract class IoCWindow : ConfigurableWindow, IIocFrameworkElement + public class IoCWindow : AdonisWindow, IIocFrameworkElement { - private IConfigurableWindowSettings _settings; - private IMessenger _messenger; - public ILocalizationService TranslationManager { get; private set; } + private readonly IScarletMessenger _messenger; - protected IoCWindow() + public ILocalizationService LocalizationService { get; } + public IScarletEventManager WeakEventManager { get; } + public IScarletCommandBuilder CommandBuilder { get; } + + public IoCWindow() : base() { if (Debugger.IsAttached) Debug.Fail($"The constructor without parameters of {nameof(IoCWindow)} exists only for compatibility reasons."); } - protected IoCWindow(ILocalizationService container, IMessenger messenger) + protected IoCWindow(IScarletCommandBuilder commandBuilder, ILocalizationService localizationService) : base() { - TranslationManager = container ?? throw new ArgumentNullException(nameof(container), $"{nameof(container)} {Localization.Properties.Resources.IsRequired}"); - _messenger = messenger ?? throw new ArgumentNullException(nameof(messenger), $"{nameof(messenger)} {Localization.Properties.Resources.IsRequired}"); + LocalizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService)); + CommandBuilder = commandBuilder ?? throw new ArgumentNullException(nameof(commandBuilder)); + WeakEventManager = CommandBuilder.WeakEventManager ?? throw new ArgumentNullException(nameof(IScarletCommandBuilder.WeakEventManager)); + _messenger = CommandBuilder.Messenger ?? throw new ArgumentNullException(nameof(IScarletCommandBuilder.Messenger)); _messenger.Subscribe(PrimaryColorChanged); + + UpdateImage(Colors.DarkOrange); } - /// - /// Derived classes must return the object which exposes - /// persisted window settings. This method is only invoked - /// once per Window, during construction. - /// - /// - protected override IConfigurableWindowSettings CreateSettings() + public Task Invoke(Action action, CancellationToken token) { - return _settings = _settings ?? new ShellSettings(this); + return CommandBuilder.Dispatcher.Invoke(action, token); } private void PrimaryColorChanged(UiPrimaryColorChangedMessage e) { - var data = string.Empty; - if (PackIcon.TryGet(PackIconKind.ApplicationIcon, out data)) + UpdateImage(e.Content); + } + + private void UpdateImage(Color color) + { + if (MaplePackIcon.TryGet(PackIconKind.ApplicationIcon, out var data)) { var geo = Geometry.Parse(data); - SetCurrentValue(IconProperty, SetImage(geo, e.Content)); + var image = GetImage(geo, color); + SetCurrentValue(IconProperty, image); } } - private BitmapSource SetImage(Geometry geo, Color color) + private BitmapSource GetImage(Geometry geo, Color color) { var canvas = new Canvas { @@ -62,16 +72,14 @@ private BitmapSource SetImage(Geometry geo, Color color) Background = new SolidColorBrush(Colors.Transparent) }; - var path = new System.Windows.Shapes.Path() + canvas.Children.Add(new System.Windows.Shapes.Path() { Data = geo, Stretch = Stretch.Fill, Fill = new SolidColorBrush(color), Width = 36, Height = 36, - }; - - canvas.Children.Add(path); + }); var size = new Size(36, 36); canvas.Measure(size); @@ -90,10 +98,13 @@ private BitmapSource SetImage(Geometry geo, Color color) var bitmapImage = new BitmapImage(); bitmapImage.BeginInit(); - bitmapImage.StreamSource = memory; bitmapImage.CacheOption = BitmapCacheOption.OnLoad; + bitmapImage.StreamSource = memory; + bitmapImage.UriSource = null; bitmapImage.EndInit(); + bitmapImage.Freeze(); + return bitmapImage; } } diff --git a/src/Maple/UI/PackIcon.cs b/src/Maple/Util/MaplePackIcon.cs similarity index 94% rename from src/Maple/UI/PackIcon.cs rename to src/Maple/Util/MaplePackIcon.cs index ab5d6b7..5cbab59 100644 --- a/src/Maple/UI/PackIcon.cs +++ b/src/Maple/Util/MaplePackIcon.cs @@ -1,29 +1,27 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Windows; -using MahApps.Metro.IconPacks; +using ControlzEx; using Maple.Domain; namespace Maple { - /// - /// - /// - /// - public class PackIcon : PackIcon + public sealed class MaplePackIcon : PackIconBase { private static IDictionary _cache; + /// - /// Initializes the class. + /// Initializes the class. /// - static PackIcon() + static MaplePackIcon() { - DefaultStyleKeyProperty.OverrideMetadata(typeof(PackIcon), new FrameworkPropertyMetadata(typeof(PackIcon))); + DefaultStyleKeyProperty.OverrideMetadata(typeof(MaplePackIcon), new FrameworkPropertyMetadata(typeof(MaplePackIcon))); } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public PackIcon() : base(CreateIconData) + public MaplePackIcon() + : base(CreateIconData) { } diff --git a/src/Maple/Util/StringLengthToVisibility.cs b/src/Maple/Util/StringLengthToVisibility.cs new file mode 100644 index 0000000..e3f8f85 --- /dev/null +++ b/src/Maple/Util/StringLengthToVisibility.cs @@ -0,0 +1,41 @@ +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; +using System.Windows.Markup; +using MvvmScarletToolkit; + +namespace Maple +{ + [ValueConversion(typeof(int), typeof(bool))] + public sealed class StringLengthToVisibility : ConverterMarkupExtension + { + [ConstructorArgument("visibility")] + public Visibility Visibility { get; set; } + + public StringLengthToVisibility() + { + Visibility = Visibility.Hidden; + } + + public StringLengthToVisibility(Visibility visibility) + { + Visibility = visibility; + } + + public override object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is null) + { + return Visibility.Visible; + } + + if (value is string path) + { + return path.Length <= 0 ? Visibility : Visibility.Visible; + } + + return Visibility.Visible; + } + } +} diff --git a/src/Maple/Util/UiPrimaryColorChangedMessage.cs b/src/Maple/Util/UiPrimaryColorChangedMessage.cs new file mode 100644 index 0000000..e47b08b --- /dev/null +++ b/src/Maple/Util/UiPrimaryColorChangedMessage.cs @@ -0,0 +1,13 @@ +using System.Windows.Media; +using MvvmScarletToolkit; + +namespace Maple +{ + public class UiPrimaryColorChangedMessage : GenericScarletMessage + { + public UiPrimaryColorChangedMessage(object sender, Color color) + : base(sender, color) + { + } + } +} diff --git a/src/Maple/Utils/DependencyInjectionFactory.cs b/src/Maple/Utils/DependencyInjectionFactory.cs deleted file mode 100644 index b0c7e3e..0000000 --- a/src/Maple/Utils/DependencyInjectionFactory.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System.Threading.Tasks; -using DryIoc; -using FluentValidation; -using Maple.Core; -using Maple.Data; -using Maple.Domain; -using Maple.Youtube; - -namespace Maple -{ - /// - /// Factory class that provides an Instance of - /// - public static class DependencyInjectionFactory - { - public static Task Get() - { - var c = new Container(); - return Task.Run(() => InitializeContainer()); - - IContainer InitializeContainer() - { - RegisterViewModels(); - RegisterServices(); - RegisterValidation(); - RegisterControls(); - - c.Resolve().LoadAsync(); - - //if (Debugger.IsAttached) - // Debugging(); - - return c; - } - - void RegisterControls() - { - c.Register(); - c.Register(); - } - - void RegisterViewModels() - { - // TODO register disposeables - - // save-/loadable ViewModels - c.RegisterMany(new[] { typeof(ILoadableViewModel), typeof(IPlaylistsViewModel) }, typeof(Playlists), Reuse.Singleton); - c.RegisterMany(new[] { typeof(ILoadableViewModel), typeof(IMediaPlayersViewModel) }, typeof(MediaPlayers), Reuse.Singleton, setup: Setup.With(allowDisposableTransient: true)); - c.RegisterMany(new[] { typeof(ILoadableViewModel), typeof(ICultureViewModel) }, typeof(Cultures), Reuse.Singleton); - c.RegisterMany(new[] { typeof(ILoadableViewModel), typeof(IUIColorsViewModel) }, typeof(UIColorsViewModel), Reuse.Singleton); - - //generic ViewModels - c.Register(Reuse.Singleton, setup: Setup.With(allowDisposableTransient: true)); - c.Register(Reuse.Singleton, setup: Setup.With(allowDisposableTransient: true)); - c.Register(Reuse.Singleton); - c.Register(Reuse.Singleton); - c.Register(Reuse.Singleton, setup: Setup.With(allowDisposableTransient: true)); - c.Register(Reuse.Singleton, setup: Setup.With(allowDisposableTransient: true)); - c.Register(Reuse.Singleton, setup: Setup.With(allowDisposableTransient: true)); - - c.Register(setup: Setup.With(allowDisposableTransient: true)); - c.Register(setup: Setup.With(allowDisposableTransient: true)); - - c.Register(Reuse.Singleton); - }; - - void RegisterServices() - { - c.Register(setup: Setup.With(allowDisposableTransient: true)); - c.Register(Reuse.Singleton); - c.Register(Reuse.Singleton, setup: Setup.With(allowDisposableTransient: true)); - - c.Register(Reuse.Singleton); - c.Register(Reuse.Transient, setup: Setup.With(allowDisposableTransient: true)); - - c.Register(Reuse.Singleton); - c.Register(Reuse.Singleton); - c.Register(Reuse.Singleton); - - c.Register(); - c.Register(); - c.Register(); - c.Register(); - c.Register(); - - c.Register(Reuse.Singleton); - c.Register(Reuse.Singleton); - c.Register(Reuse.Singleton); - - c.Register(Reuse.Singleton); - c.Register(Reuse.Singleton); - - c.Register(Reuse.Singleton); - c.Register(Reuse.Singleton); - c.Register(setup: Setup.DecoratorWith(order: 1)); - c.Register(setup: Setup.DecoratorWith(order: 2)); - } - - void RegisterValidation() - { - c.Register, PlaylistValidator>(Reuse.Singleton); - c.Register, PlaylistsValidator>(Reuse.Singleton); - c.Register, MediaPlayerValidator>(Reuse.Singleton); - c.Register, MediaItemValidator>(Reuse.Singleton); - } - } - } -} diff --git a/src/Maple/Utils/Mappers/Base/BaseMapper.cs b/src/Maple/Utils/Mappers/Base/BaseMapper.cs deleted file mode 100644 index 74fa2f9..0000000 --- a/src/Maple/Utils/Mappers/Base/BaseMapper.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using AutoMapper; -using FluentValidation; -using Maple.Core; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple -{ - public abstract class BaseMapper - { - protected IMapper Mapper { get; set; } - protected readonly ILocalizationService _translationService; - protected readonly ISequenceService _sequenceProvider; - protected readonly ILoggingService _log; - protected readonly IValidator _validator; - protected readonly IMessenger _messenger; - protected readonly ViewModelServiceContainer _container; - - protected BaseMapper(ViewModelServiceContainer container, IValidator validator) - { - _container = container; - _translationService = container.LocalizationService; - _sequenceProvider = container.SequenceService; - _log = container.Log; - _messenger = container.Messenger; - _validator = validator ?? throw new ArgumentNullException(nameof(validator), $"{nameof(validator)} {Resources.IsRequired}"); - } - - protected abstract void InitializeMapper(); - } -} diff --git a/src/Maple/Utils/Mappers/MapperExtensions.cs b/src/Maple/Utils/Mappers/MapperExtensions.cs deleted file mode 100644 index 5836b58..0000000 --- a/src/Maple/Utils/Mappers/MapperExtensions.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using AutoMapper; -using Maple.Core; - -namespace Maple -{ - /// - /// Extensions for - /// - public static class MapperExtensions - { - - public static IEnumerable GetMany(this IMediaItemMapper mapper, IEnumerable items) - { - return items.ForEach(mapper.Get); - } - - public static IList GetManyAsList(this IMediaItemMapper mapper, IEnumerable items) - { - return items.ForEach(mapper.Get).ToList(); - } - - public static IEnumerable GetMany(this IPlaylistMapper mapper, IEnumerable items) - { - return items.ForEach(mapper.Get); - } - - public static IEnumerable GetManyData(this IPlaylistMapper mapper, IEnumerable items) - { - return items.ForEach(mapper.GetData); - } - - public static IMappingExpression Ignore(this IMappingExpression map, - Expression> selector) - { - map.ForMember(selector, config => config.Ignore()); - return map; - } - } -} diff --git a/src/Maple/Utils/Mappers/MediaItemMapper.cs b/src/Maple/Utils/Mappers/MediaItemMapper.cs deleted file mode 100644 index d6fbc16..0000000 --- a/src/Maple/Utils/Mappers/MediaItemMapper.cs +++ /dev/null @@ -1,69 +0,0 @@ -using AutoMapper; -using FluentValidation; -using Maple.Core; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple -{ - /// - /// Provides logic to map between different domain objects of the MediaItemType - /// - /// - public sealed class MediaItemMapper : BaseMapper, IMediaItemMapper - { - /// - /// Initializes a new instance of the class. - /// - public MediaItemMapper(ViewModelServiceContainer container, IValidator validator) - : base(container, validator) - { - InitializeMapper(); - } - - protected override void InitializeMapper() - { - var config = new MapperConfiguration(cfg => - { - }); - - config.AssertConfigurationIsValid(); - Mapper = config.CreateMapper(); - } - - public MediaItem GetNewMediaItem(int sequence, Playlist playlist) - { - return new MediaItem(GetDataNewMediaItem(playlist.Model), _validator, _messenger) - { - Title = _translationService.Translate(nameof(Resources.New)), - Description = string.Empty, - Playlist = playlist, - }; - } - - public MediaItemModel GetDataNewMediaItem(PlaylistModel playlist) - { - return new MediaItemModel() - { - Title = _translationService.Translate(nameof(Resources.New)), - Description = string.Empty, - Playlist = playlist, - }; - } - - public MediaItem Get(MediaItemModel mediaitem) - { - return new MediaItem(mediaitem, _validator, _messenger); - } - - /// - /// Gets the data. - /// - /// The mediaitem. - /// - public MediaItemModel GetData(MediaItem mediaitem) - { - return mediaitem.Model; - } - } -} diff --git a/src/Maple/Utils/Mappers/MediaPlayerMapper.cs b/src/Maple/Utils/Mappers/MediaPlayerMapper.cs deleted file mode 100644 index fdc7207..0000000 --- a/src/Maple/Utils/Mappers/MediaPlayerMapper.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using AutoMapper; -using FluentValidation; -using Maple.Core; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple -{ - public sealed class MediaPlayerMapper : BaseMapper, IMediaPlayerMapper - { - private readonly IMediaPlayer _mediaPlayer; - private readonly AudioDevices _devices; - - public MediaPlayerMapper(ViewModelServiceContainer container, IMediaPlayer mediaPlayer, AudioDevices devices, IValidator validator) - : base(container, validator) - { - _mediaPlayer = mediaPlayer ?? throw new ArgumentNullException(nameof(mediaPlayer), $"{nameof(mediaPlayer)} {Resources.IsRequired}"); - _devices = devices ?? throw new ArgumentNullException(nameof(devices), $"{nameof(devices)} {Resources.IsRequired}"); - - InitializeMapper(); - } - - protected override void InitializeMapper() - { - var config = new MapperConfiguration(cfg => // TODO mapper configuration - { - }); - - config.AssertConfigurationIsValid(); - Mapper = config.CreateMapper(); - } - - public MediaPlayer GetNewMediaPlayer(int sequence, Playlist playlist = null) - { - return new MediaPlayer(_container, _mediaPlayer, _validator, _devices, playlist, new MediaPlayerModel() - { - Sequence = sequence, - IsPrimary = false, - Name = _translationService.Translate(nameof(Resources.New)), - Playlist = playlist?.Model, - }); - } - - public MediaPlayer Get(MediaPlayerModel model) - { - throw new NotImplementedException(); // by design - } - - public MediaPlayerModel GetData(MediaPlayer viewModel) - { - return viewModel.Model; - } - - public MainMediaPlayer GetMain(MediaPlayerModel player, Playlist playlist) - { - return new MainMediaPlayer(_container, _mediaPlayer, _validator, _devices, playlist, player); - } - - public MediaPlayer Get(MediaPlayerModel player, Playlist playlist) - { - return new MediaPlayer(_container, _mediaPlayer, _validator, _devices, playlist, player); - } - } -} diff --git a/src/Maple/Utils/Mappers/PlaylistMapper.cs b/src/Maple/Utils/Mappers/PlaylistMapper.cs deleted file mode 100644 index c8d2d5d..0000000 --- a/src/Maple/Utils/Mappers/PlaylistMapper.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using AutoMapper; -using FluentValidation; -using Maple.Core; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple -{ - /// - /// Provides logic to map between different domain objects of the Playlisttype - /// - /// - public sealed class PlaylistMapper : BaseMapper, IPlaylistMapper - { - private readonly IMediaItemMapper _mediaItemMapper; - private readonly IDialogViewModel _dialogViewModel; - - /// - /// Initializes a new instance of the class. - /// - /// The dialog view model. - public PlaylistMapper(ViewModelServiceContainer container, IMediaItemMapper mediaItemMapper, IDialogViewModel dialogViewModel, IValidator validator) - : base(container, validator) - { - _dialogViewModel = dialogViewModel ?? throw new ArgumentNullException(nameof(dialogViewModel), $"{nameof(dialogViewModel)} {Resources.IsRequired}"); - _mediaItemMapper = mediaItemMapper ?? throw new ArgumentNullException(nameof(mediaItemMapper), $"{nameof(mediaItemMapper)} {Resources.IsRequired}"); - - InitializeMapper(); - } - - protected override void InitializeMapper() - { - var config = new MapperConfiguration(cfg => - { - }); - - config.AssertConfigurationIsValid(); - Mapper = config.CreateMapper(); - } - - public Playlist GetNewPlaylist() - { - return new Playlist(_container, _validator, _dialogViewModel, _mediaItemMapper, new PlaylistModel - { - Title = _translationService.Translate(nameof(Resources.New)), - Description = string.Empty, - Location = string.Empty, - RepeatMode = 0, - IsShuffeling = false, - Sequence = 0, - }); - } - - public Playlist Get(PlaylistModel model) - { - return new Playlist(_container, _validator, _dialogViewModel, _mediaItemMapper, model); - } - - public PlaylistModel GetData(Playlist mediaitem) - { - return mediaitem.Model; - } - } -} diff --git a/src/Maple/Utils/Validation/MediaItemValidator.cs b/src/Maple/Utils/Validation/MediaItemValidator.cs deleted file mode 100644 index b744c44..0000000 --- a/src/Maple/Utils/Validation/MediaItemValidator.cs +++ /dev/null @@ -1,16 +0,0 @@ -using FluentValidation; -using Maple.Core; - -namespace Maple -{ - public class MediaItemValidator : BaseValidator, IValidator - { - public MediaItemValidator(ILocalizationService translationService) - : base(translationService) - { - RuleFor(mediaItem => mediaItem.Title).NotEmpty(); // TODO finalize Validator configuration - RuleFor(mediaItem => mediaItem.Description).NotEmpty(); - RuleFor(mediaItem => mediaItem.Location).NotEmpty(); - } - } -} diff --git a/src/Maple/Utils/Validation/MediaPlayerValidator.cs b/src/Maple/Utils/Validation/MediaPlayerValidator.cs deleted file mode 100644 index 764ca08..0000000 --- a/src/Maple/Utils/Validation/MediaPlayerValidator.cs +++ /dev/null @@ -1,20 +0,0 @@ -using FluentValidation; -using Maple.Core; - -namespace Maple -{ - public class MediaPlayerValidator : BaseValidator, IValidator - { - public MediaPlayerValidator(ILocalizationService translationService) - : base(translationService) - { - RuleFor(mediaPlayer => mediaPlayer.Name).NotEmpty(); // TODO finalize Validator configuration - - RuleFor(mediaPlayer => mediaPlayer.AudioDevices).NotEmpty(); - RuleFor(mediaPlayer => mediaPlayer.Model).NotEmpty(); - - RuleFor(mediaPlayer => mediaPlayer.Player).NotEmpty(); - RuleFor(mediaPlayer => mediaPlayer.Playlist).NotEmpty(); - } - } -} diff --git a/src/Maple/Utils/Validation/PlaylistValidator.cs b/src/Maple/Utils/Validation/PlaylistValidator.cs deleted file mode 100644 index 6a800b0..0000000 --- a/src/Maple/Utils/Validation/PlaylistValidator.cs +++ /dev/null @@ -1,32 +0,0 @@ -using FluentValidation; -using Maple.Core; - -namespace Maple -{ - public class PlaylistValidator : BaseValidator, IValidator - { - public PlaylistValidator(ILocalizationService translationService, IValidator mediaItemValidator) - : base(translationService) - { - RuleFor(playlist => playlist.Title).NotEmpty(); - RuleFor(playlist => playlist.Title).Length(1, 1024); - - RuleFor(playlist => playlist.Description).NotEmpty(); - RuleFor(playlist => playlist.Description).Length(0, 1024); - - RuleFor(playlist => playlist.PrivacyStatus).NotNull(); - - RuleFor(playlist => playlist.UpdatedBy).NotEmpty(); - RuleFor(playlist => playlist.UpdatedBy).NotEmpty(); - RuleFor(playlist => playlist.CreatedBy).NotEmpty(); - RuleFor(playlist => playlist.CreatedOn).NotEmpty(); - - RuleFor(playlist => playlist.RepeatModes).NotEmpty(); - RuleFor(playlist => playlist.RepeatMode).NotNull(); - - RuleFor(playlist => playlist.SelectedItem).NotNull(); - RuleFor(playlist => playlist.Items).NotNull(); - RuleFor(playlist => playlist.Items).SetCollectionValidator(mediaItemValidator); - } - } -} diff --git a/src/Maple/Utils/Validation/PlaylistsValidator.cs b/src/Maple/Utils/Validation/PlaylistsValidator.cs deleted file mode 100644 index 5c3c8af..0000000 --- a/src/Maple/Utils/Validation/PlaylistsValidator.cs +++ /dev/null @@ -1,15 +0,0 @@ -using FluentValidation; -using Maple.Core; - -namespace Maple -{ - public class PlaylistsValidator : BaseValidator, IValidator - { - public PlaylistsValidator(ILocalizationService translationService, IValidator playlistValidator) - : base(translationService) - { - RuleFor(playlists => playlists.Items).NotEmpty() - .SetCollectionValidator(playlistValidator); - } - } -} diff --git a/src/Maple/ViewModels/Dialogs/Base/DialogBaseViewModel.cs b/src/Maple/ViewModels/Dialogs/Base/DialogBaseViewModel.cs deleted file mode 100644 index e05fbd6..0000000 --- a/src/Maple/ViewModels/Dialogs/Base/DialogBaseViewModel.cs +++ /dev/null @@ -1,159 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Input; -using Maple.Core; - -namespace Maple -{ - public abstract class DialogBaseViewModel : ViewModel - { - public EventHandler DialogClosed; - - public ExceptionContentDialogViewModel ExceptionDialogViewModel { get; protected set; } - public MessageContentDialogViewModel MessageDialogViewModel { get; protected set; } - public ProgressContentDialogViewModel ProgressDialogViewModel { get; protected set; } - - public ICommand CloseDialogCommand { get; protected set; } - public ICommand CancelDialogCommand { get; protected set; } - public ICommand AcceptDialogCommand { get; protected set; } - - public Action AcceptAction { get; protected set; } - public Action CancelAction { get; protected set; } - - public Func CanCancelFunc { get; protected set; } - public Func CanAcceptFunc { get; protected set; } - - private bool _isOpen; - public bool IsOpen - { - get { return _isOpen; } - set { SetValue(ref _isOpen, value, OnChanged: OnOpenChanged); } - } - - private bool _isCancelVisible; - public bool IsCancelVisible - { - get { return _isCancelVisible; } - set { SetValue(ref _isCancelVisible, value); } - } - - private string _title; - public string Title - { - get { return _title; } - protected set { SetValue(ref _title, value); } - } - - private string _titleDetail; - public string TitleDetail - { - get { return _titleDetail; } - protected set { SetValue(ref _titleDetail, value); } - } - - private ObservableObject _context; - public ObservableObject Context - { - get { return _context; } - set { SetValue(ref _context, value); } - } - - protected DialogBaseViewModel(IMessenger messenger) - : base(messenger) - { - } - - private void OnOpenChanged() - { - if (!IsOpen) - DialogClosed?.Invoke(this, EventArgs.Empty); - } - - /// - /// Accepts this instance. - /// - public void Accept() - { - AcceptAction?.Invoke(); - Close(); - } - - /// - /// Determines whether this instance can accept. - /// - /// - /// true if this instance can accept; otherwise, false. - /// - public bool CanAccept() - { - return CanClose() && (CanAcceptFunc?.Invoke() ?? true) == true; - } - - /// - /// Cancels this instance. - /// - public void Cancel() - { - CancelAction?.Invoke(); - Close(); - } - - /// - /// Determines whether this instance can cancel. - /// - /// - /// true if this instance can cancel; otherwise, false. - /// - public bool CanCancel() - { - return CanClose() && (CanCancelFunc?.Invoke() ?? true) == true; - } - - public Task Open() - { - return Open(CancellationToken.None); - } - - /// - /// Opens this instance. - /// - /// - public async Task Open(CancellationToken token) - { - var tcs = new TaskCompletionSource(); - var registration = token.Register(() => tcs.TrySetCanceled()); - void lambda(object s, EventArgs e) => tcs.TrySetResult(null); - try - { - DialogClosed += lambda; - IsOpen = true; // open dialog - await tcs.Task.ConfigureAwait(false); // wait for dialog to close - } - finally - { - DialogClosed -= lambda; - registration.Dispose(); - } - } - - /// - /// Closes this instance. - /// - public void Close() - { - IsOpen = false; - } - - /// - /// Determines whether this instance can close. - /// - /// - /// true if this instance can close; otherwise, false. - /// - public bool CanClose() - { - return IsOpen; - } - } -} diff --git a/src/Maple/ViewModels/Dialogs/Base/IDialogViewModel.cs b/src/Maple/ViewModels/Dialogs/Base/IDialogViewModel.cs deleted file mode 100644 index e517e82..0000000 --- a/src/Maple/ViewModels/Dialogs/Base/IDialogViewModel.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Maple.Core; - -namespace Maple -{ - public interface IDialogViewModel - { - Task ShowExceptionDialog(Exception exception); - Task<(bool Result, IList Files)> ShowFileBrowserDialog(FileSystemBrowserOptions options, CancellationToken token); - Task<(bool Result, IFileSystemDirectory Directory)> ShowFolderBrowserDialog(FileSystemBrowserOptions options, CancellationToken token); - Task<(bool Result, ICollection MediaItems)> ShowMediaItemFolderSelectionDialog(FileSystemFolderBrowserOptions options, CancellationToken token); - Task<(bool Result, ICollection MediaItems)> ShowMediaItemSelectionDialog(FileSystemBrowserOptions options, CancellationToken token); - Task ShowMessageDialog(string message, string title); - Task ShowProgressDialog(); - Task> ShowUrlParseDialog(CancellationToken token); - } -} \ No newline at end of file diff --git a/src/Maple/ViewModels/Dialogs/DialogContentViewModels/ExceptionContentDialogViewModel.cs b/src/Maple/ViewModels/Dialogs/DialogContentViewModels/ExceptionContentDialogViewModel.cs deleted file mode 100644 index 9fbae6a..0000000 --- a/src/Maple/ViewModels/Dialogs/DialogContentViewModels/ExceptionContentDialogViewModel.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using Maple.Core; - -namespace Maple -{ - public class ExceptionContentDialogViewModel : ObservableObject - { - private Exception _exception; - public Exception Exception - { - get { return _exception; } - set { SetValue(ref _exception, value, OnChanged: () => OnPropertyChanged(nameof(ExceptionText))); } - } - - public string ExceptionText => Exception?.ToString(); - } -} diff --git a/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FileBrowserContentDialogViewModel.cs b/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FileBrowserContentDialogViewModel.cs deleted file mode 100644 index 3c9377b..0000000 --- a/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FileBrowserContentDialogViewModel.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using Maple.Core; -using Maple.Localization.Properties; - -namespace Maple -{ - public class FileBrowserContentDialogViewModel : ObservableObject - { - private FileSystemBrowserOptions _options; - - private FileSystemViewModel _fileSystemViewModel; - public FileSystemViewModel FileSystemViewModel - { - get { return _fileSystemViewModel; } - private set { SetValue(ref _fileSystemViewModel, value); } - } - - public FileBrowserContentDialogViewModel(FileSystemViewModel fileSystemViewModel, FileSystemBrowserOptions options) - { - _options = options ?? throw new ArgumentNullException(nameof(options), $"{nameof(options)} {Resources.IsRequired}"); - FileSystemViewModel = fileSystemViewModel ?? throw new ArgumentNullException(nameof(fileSystemViewModel), $"{nameof(fileSystemViewModel)} {Resources.IsRequired}"); - } - } -} diff --git a/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FileSystemBrowserOptions.cs b/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FileSystemBrowserOptions.cs deleted file mode 100644 index 02f388e..0000000 --- a/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FileSystemBrowserOptions.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Maple.Core; - -namespace Maple -{ - public class FileSystemBrowserOptions : ObservableObject - { - private bool _multiSelection; - public bool MultiSelection - { - get { return _multiSelection; } - set { SetValue(ref _multiSelection, value); } - } - - private bool _canCancel; - public bool CanCancel - { - get { return _canCancel; } - set { SetValue(ref _canCancel, value); } - } - - private string _title; - public string Title - { - get { return _title; } - set { SetValue(ref _title, value); } - } - } -} diff --git a/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FileSystemFolderBrowserOptions.cs b/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FileSystemFolderBrowserOptions.cs deleted file mode 100644 index ce464be..0000000 --- a/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FileSystemFolderBrowserOptions.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Maple -{ - public class FileSystemFolderBrowserOptions : FileSystemBrowserOptions - { - private bool _includeSubFolders; - public bool IncludeSubFolders - { - get { return _includeSubFolders; } - set { SetValue(ref _includeSubFolders, value); } - } - } -} diff --git a/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FolderBrowserContentDialogViewModel.cs b/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FolderBrowserContentDialogViewModel.cs deleted file mode 100644 index cba7ecc..0000000 --- a/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FolderBrowserContentDialogViewModel.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using Maple.Core; -using Maple.Localization.Properties; - -namespace Maple -{ - public class FolderBrowserContentDialogViewModel : ObservableObject - { - private FileSystemBrowserOptions _options; - private FileSystemViewModel _fileSystemViewModel; - - public FileSystemViewModel FileSystemViewModel - { - get { return _fileSystemViewModel; } - private set { SetValue(ref _fileSystemViewModel, value); } - } - - public FolderBrowserContentDialogViewModel(FileSystemViewModel fileSystemViewModel, FileSystemBrowserOptions options) - { - _options = options ?? throw new ArgumentNullException(nameof(options), $"{nameof(options)} {Resources.IsRequired}"); - FileSystemViewModel = fileSystemViewModel ?? throw new ArgumentNullException(nameof(fileSystemViewModel), $"{nameof(fileSystemViewModel)} {Resources.IsRequired}"); - } - } -} diff --git a/src/Maple/ViewModels/Dialogs/DialogContentViewModels/MessageContentDialogViewModel.cs b/src/Maple/ViewModels/Dialogs/DialogContentViewModels/MessageContentDialogViewModel.cs deleted file mode 100644 index 02a4621..0000000 --- a/src/Maple/ViewModels/Dialogs/DialogContentViewModels/MessageContentDialogViewModel.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Maple.Core; - -namespace Maple -{ - public class MessageContentDialogViewModel : ObservableObject - { - private string _message; - public string Message - { - get { return _message; } - set { SetValue(ref _message, value); } - } - } -} diff --git a/src/Maple/ViewModels/Dialogs/DialogContentViewModels/ProgressContentDialogViewModel.cs b/src/Maple/ViewModels/Dialogs/DialogContentViewModels/ProgressContentDialogViewModel.cs deleted file mode 100644 index 3381bff..0000000 --- a/src/Maple/ViewModels/Dialogs/DialogContentViewModels/ProgressContentDialogViewModel.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Maple.Core; - -namespace Maple -{ - public class ProgressContentDialogViewModel : ObservableObject - { - } -} diff --git a/src/Maple/ViewModels/Dialogs/DialogViewModel.cs b/src/Maple/ViewModels/Dialogs/DialogViewModel.cs deleted file mode 100644 index 7da5526..0000000 --- a/src/Maple/ViewModels/Dialogs/DialogViewModel.cs +++ /dev/null @@ -1,238 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Maple.Core; -using Maple.Localization.Properties; -using Maple.Youtube; - -namespace Maple -{ - public class DialogViewModel : DialogBaseViewModel, IDialogViewModel - { - private readonly ILocalizationService _translator; - private readonly IYoutubeUrlParser _service; - private readonly IMediaItemMapper _mediaItemMapper; - private readonly FileSystemViewModel _fileSystemViewModel; - - private readonly Func _createMediaItemFactory; - - public DialogViewModel(ILocalizationService translator, IYoutubeUrlParser service, IMediaItemMapper mediaItemMapper, IMessenger messenger, FileSystemViewModel fileSystemViewModel, Func createMediaItemFactory) - : base(messenger) - { - _translator = translator ?? throw new ArgumentNullException(nameof(translator), $"{nameof(translator)} {Resources.IsRequired}"); - _service = service ?? throw new ArgumentNullException(nameof(service), $"{nameof(service)} {Resources.IsRequired}"); - _mediaItemMapper = mediaItemMapper ?? throw new ArgumentNullException(nameof(mediaItemMapper), $"{nameof(mediaItemMapper)} {Resources.IsRequired}"); - _fileSystemViewModel = fileSystemViewModel ?? throw new ArgumentNullException(nameof(fileSystemViewModel), $"{nameof(fileSystemViewModel)} {Resources.IsRequired}"); - _createMediaItemFactory = createMediaItemFactory ?? throw new ArgumentNullException(nameof(createMediaItemFactory), $"{nameof(createMediaItemFactory)} {Resources.IsRequired}"); - - - CloseDialogCommand = new RelayCommand(Close, () => CanClose()); - CancelDialogCommand = new RelayCommand(Cancel, () => CanCancel()); - AcceptDialogCommand = new RelayCommand(Accept, () => CanAccept()); - - ExceptionDialogViewModel = new ExceptionContentDialogViewModel(); - MessageDialogViewModel = new MessageContentDialogViewModel(); - ProgressDialogViewModel = new ProgressContentDialogViewModel(); - } - - /// - /// Shows the message dialog. - /// - /// The message. - /// The title. - /// - /// - public Task ShowMessageDialog(string message, string title) - { - if (IsOpen) - throw new InvalidOperationException(Resources.DialogOpenAlready); - - TitleDetail = string.Empty; - Context = MessageDialogViewModel; - Title = title; - MessageDialogViewModel.Message = message; - IsCancelVisible = false; - - return Open(); - } - - /// - /// Shows the exception dialog. - /// - /// The exception. - /// - public Task ShowExceptionDialog(Exception exception) - { - if (IsOpen) // no exception spam, could probably be improved TODO ? - return Task.CompletedTask; - - TitleDetail = string.Empty; - Context = ExceptionDialogViewModel; - Title = exception.GetType().Name; - ExceptionDialogViewModel.Exception = exception; - IsCancelVisible = false; - - return Open(); - } - - /// - /// Shows the file browser dialog. - /// - /// - /// - public async Task<(bool Result, IList Files)> ShowFileBrowserDialog(FileSystemBrowserOptions options, CancellationToken token) - { - if (IsOpen) - throw new InvalidOperationException(Resources.DialogOpenAlready); - - var tuple = default((bool Result, IList Files)); - var viewModel = new FileBrowserContentDialogViewModel(_fileSystemViewModel, options); - - TitleDetail = string.Empty; - Context = viewModel; - Title = options.Title; - IsCancelVisible = options.CanCancel; - - using (Messenger.Subscribe(FileSystemInfoChanged)) - { - AcceptAction = () => - { - var items = viewModel.FileSystemViewModel.SelectedItems; - tuple = (true, items.Select(p => p as IFileSystemFile).Where(p => p != null).ToList()); - }; - - CancelAction = () => - { - var items = viewModel.FileSystemViewModel.SelectedItems; - tuple = (false, new List()); - }; - - await Open(token).ConfigureAwait(false); - } - - return tuple; - } - - public async Task<(bool Result, ICollection MediaItems)> ShowMediaItemSelectionDialog(FileSystemBrowserOptions options, CancellationToken token) - { - var mediaItems = new List(); - (var Result, var Files) = await ShowFileBrowserDialog(options, token).ConfigureAwait(true); - - if (!Result) - return (Result, mediaItems); - - foreach (var file in Files) - { - // TODO parse the files and generate mediaitems from them - } - - return (Result, mediaItems); - } - - public async Task<(bool Result, ICollection MediaItems)> ShowMediaItemFolderSelectionDialog(FileSystemFolderBrowserOptions options, CancellationToken token) - { - var mediaItems = new List(); - (var Result, var Folder) = await ShowFolderBrowserDialog(options, token).ConfigureAwait(true); - - if (!Result) - return (Result, mediaItems); - - // should handle items depending on options - - foreach (var file in Folder.Children) - { - // TODO get the files from the folder - // TODO parse the files from the folder and generate mediaitems from them - } - - return (Result, mediaItems); - } - - /// - /// Shows the folder browser dialog. - /// - /// - /// - public async Task<(bool Result, IFileSystemDirectory Directory)> ShowFolderBrowserDialog(FileSystemBrowserOptions options, CancellationToken token) - { - if (IsOpen) - throw new InvalidOperationException(Resources.DialogOpenAlready); - - var tuple = default((bool Result, IFileSystemDirectory Directory)); - var viewModel = new FileBrowserContentDialogViewModel(_fileSystemViewModel, options); - - TitleDetail = string.Empty; - Context = viewModel; - Title = options.Title; - IsCancelVisible = options.CanCancel; - - using (Messenger.Subscribe(FileSystemInfoChanged)) - { - AcceptAction = () => - { - var items = viewModel.FileSystemViewModel.SelectedItems; - items.Add(viewModel.FileSystemViewModel.SelectedItem); - tuple = (true, items.Distinct().FirstOrDefault() as IFileSystemDirectory); // TODO handle multi select option - }; - - CancelAction = () => - { - var items = viewModel.FileSystemViewModel.SelectedItems; - tuple = (false, default(IFileSystemDirectory)); - }; - - await Open(token).ConfigureAwait(false); - } - - return tuple; - } - - /// - /// Shows the progress dialog. - /// - /// - /// - public Task ShowProgressDialog() - { - if (IsOpen) - throw new InvalidOperationException(Resources.DialogOpenAlready); - - return ShowExceptionDialog(new NotImplementedException()); - } - - /// - /// Shows the URL parse dialog. - /// - /// - public async Task> ShowUrlParseDialog(CancellationToken token) - { - var result = new List(); - var viewmodel = new CreateMediaItem(_service, _mediaItemMapper, Messenger); - - TitleDetail = string.Empty; - Context = viewmodel; - Title = _translator.Translate(nameof(Resources.VideoAdd)); - - AcceptAction = () => - { - if (viewmodel.Result?.MediaItems?.Any() == true) - { - var items = _mediaItemMapper.GetMany(viewmodel.Result.MediaItems); - result.AddRange(items); - } - }; - - await Open(token).ConfigureAwait(false); - - return result; - } - - - private void FileSystemInfoChanged(FileSystemInfoChangedMessage e) - { - TitleDetail = e.Content.FullName; - } - } -} diff --git a/src/Maple/ViewModels/Interfaces/ICultureViewModel.cs b/src/Maple/ViewModels/Interfaces/ICultureViewModel.cs deleted file mode 100644 index 1af604a..0000000 --- a/src/Maple/ViewModels/Interfaces/ICultureViewModel.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Maple.Core; - -namespace Maple -{ - public interface ICultureViewModel : ILoadableViewModel, ISaveableViewModel - { - } -} \ No newline at end of file diff --git a/src/Maple/ViewModels/Interfaces/IMediaItemsViewModel.cs b/src/Maple/ViewModels/Interfaces/IMediaItemsViewModel.cs deleted file mode 100644 index 3ebd2bb..0000000 --- a/src/Maple/ViewModels/Interfaces/IMediaItemsViewModel.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Maple.Core; - -namespace Maple -{ - public interface IMediaItemsViewModel : ISaveableViewModel - { - IReadOnlyCollection Items { get; } - - void Add(Playlist playlist); - Task LoadAsync(); - void Save(); - } -} \ No newline at end of file diff --git a/src/Maple/ViewModels/Interfaces/IMediaPlayersViewModel.cs b/src/Maple/ViewModels/Interfaces/IMediaPlayersViewModel.cs deleted file mode 100644 index b035984..0000000 --- a/src/Maple/ViewModels/Interfaces/IMediaPlayersViewModel.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using Maple.Core; - -namespace Maple -{ - public interface IMediaPlayersViewModel : ILoadableViewModel, ISaveableViewModel, IDisposable - { - IReadOnlyCollection Items { get; } - } -} \ No newline at end of file diff --git a/src/Maple/ViewModels/Interfaces/IPlaylistsViewModel.cs b/src/Maple/ViewModels/Interfaces/IPlaylistsViewModel.cs deleted file mode 100644 index 2c2a01a..0000000 --- a/src/Maple/ViewModels/Interfaces/IPlaylistsViewModel.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Maple.Core; - -namespace Maple -{ - public interface IPlaylistsViewModel : ILoadableViewModel, ISaveableViewModel - { - void Add(); - } -} \ No newline at end of file diff --git a/src/Maple/ViewModels/Interfaces/ISplashScreenViewModel.cs b/src/Maple/ViewModels/Interfaces/ISplashScreenViewModel.cs deleted file mode 100644 index c17a849..0000000 --- a/src/Maple/ViewModels/Interfaces/ISplashScreenViewModel.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Windows.Input; - -namespace Maple -{ - public interface ISplashScreenViewModel : IDisposable - { - ICommand DisposeCommand { get; } - ICommand LoadCommand { get; } - string Message { get; } - string Version { get; } - } -} \ No newline at end of file diff --git a/src/Maple/ViewModels/Interfaces/IUIColorsViewModel.cs b/src/Maple/ViewModels/Interfaces/IUIColorsViewModel.cs deleted file mode 100644 index eca7058..0000000 --- a/src/Maple/ViewModels/Interfaces/IUIColorsViewModel.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Windows.Input; -using Maple.Core; - -namespace Maple -{ - public interface IUIColorsViewModel : ILoadableViewModel, ISaveableViewModel - { - ICommand ApplyAccentCommand { get; } - ICommand ApplyPrimaryCommand { get; } - ICommand ToggleBaseCommand { get; } - - void OnPrimaryColorChanged(UiPrimaryColorChangedMessage args); - } -} \ No newline at end of file diff --git a/src/Maple/ViewModels/MediaItems/CreateMediaItem.cs b/src/Maple/ViewModels/MediaItems/CreateMediaItem.cs deleted file mode 100644 index 07a16b8..0000000 --- a/src/Maple/ViewModels/MediaItems/CreateMediaItem.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Threading.Tasks; -using System.Windows.Input; -using Maple.Core; -using Maple.Localization.Properties; -using Maple.Youtube; - -namespace Maple -{ - /// - /// viewmodel for creating mediaitem from a string (path/url) - /// - public class CreateMediaItem : BaseListViewModel - { - private IYoutubeUrlParser _dataParsingService; - private IMediaItemMapper _mapper; - - public ICommand ParseCommand { get; private set; } - - private string _source; - public string Source - { - get { return _source; } - set { SetValue(ref _source, value); } - } - - private UrlParseResult _result; - public UrlParseResult Result - { - get { return _result; } - private set { SetValue(ref _result, value); } - } - - public CreateMediaItem(IYoutubeUrlParser dataParsingService, IMediaItemMapper mapper, IMessenger messenger) - : base(messenger) - { - _dataParsingService = dataParsingService ?? throw new ArgumentNullException(nameof(dataParsingService), $"{nameof(mapper)} {Resources.IsRequired}"); - _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper), $"{nameof(mapper)} {Resources.IsRequired}"); - - InitializeCommands(); - } - - private void InitializeCommands() - { - ParseCommand = AsyncCommand.Create(Parse, CanParse); - } - - private async Task Parse() - { - Result = await _dataParsingService.Parse(Source, ParseResultType.MediaItems) - .ConfigureAwait(true); - - if (Result.Count > 0 && Result.MediaItems?.Count > 0) - AddRange(_mapper.GetMany(Result.MediaItems)); - } - - private bool CanParse() - { - return !string.IsNullOrWhiteSpace(Source); - } - } -} diff --git a/src/Maple/ViewModels/MediaItems/MediaItem.cs b/src/Maple/ViewModels/MediaItems/MediaItem.cs deleted file mode 100644 index 5639dfb..0000000 --- a/src/Maple/ViewModels/MediaItems/MediaItem.cs +++ /dev/null @@ -1,158 +0,0 @@ -using System; -using System.Diagnostics; -using FluentValidation; -using Maple.Core; -using Maple.Domain; - -namespace Maple -{ - /// - /// - /// - /// - /// - [DebuggerDisplay("{Title}, {Sequence} {Location}")] - public class MediaItem : ValidableBaseDataViewModel, IMediaItem - { - public bool IsNew => Model.IsNew; - public bool IsDeleted => Model.IsDeleted; - - public int Id - { - get { return Model.Id; } - } - - private int _sequence; - public int Sequence - { - get { return _sequence; } - set { SetValue(ref _sequence, value, OnChanged: () => Model.Sequence = value); } - } - - private TimeSpan _duration; - public TimeSpan Duration - { - get { return _duration; } - private set { SetValue(ref _duration, value, OnChanged: () => Model.Duration = value.Ticks); } - } - - private PrivacyStatus _privacyStatus; - public PrivacyStatus PrivacyStatus - { - get { return _privacyStatus; } - private set { SetValue(ref _privacyStatus, value, OnChanged: () => Model.PrivacyStatus = (int)value); } - } - - private MediaItemType _mediaItemType; - public MediaItemType MediaItemType - { - get { return _mediaItemType; } - set { SetValue(ref _mediaItemType, value, OnChanged: () => Model.MediaItemType = (int)value); } - } - - private string _title; - public string Title - { - get { return _title; } - set { SetValue(ref _title, value, OnChanged: () => Model.Title = value); } - } - - private string _description; - public string Description - { - get { return _description; } - set { SetValue(ref _description, value, OnChanged: () => Model.Description = value); } - } - - private string _location; - public string Location - { - get { return _location; } - private set { SetValue(ref _location, value, OnChanged: () => Model.Location = value); } - } - - private bool _isSelected; - public bool IsSelected - { - get { return _isSelected; } - set { SetValue(ref _isSelected, value); } - } - - private string _createdBy; - public string CreatedBy - { - get { return _createdBy; } - private set { SetValue(ref _createdBy, value, OnChanged: () => Model.CreatedBy = value); } - } - - private string _updatedBy; - public string UpdatedBy - { - get { return _updatedBy; } - set { SetValue(ref _updatedBy, value, OnChanged: () => Model.UpdatedBy = value); } - } - - private DateTime _updatedOn; - public DateTime UpdatedOn - { - get { return _updatedOn; } - set { SetValue(ref _updatedOn, value, OnChanged: () => Model.UpdatedOn = value); } - } - - private DateTime _createdOn; - public DateTime CreatedOn - { - get { return _updatedOn; } - private set { SetValue(ref _updatedOn, value, OnChanged: () => Model.CreatedOn = value); } - } - - private Playlist _playlist; - public Playlist Playlist - { - get { return _playlist; } - set { SetValue(ref _playlist, value, OnChanged: () => Model.Playlist = value.Model); } - } - - /// - /// Gets a value indicating whether this instance is file. - /// - /// - /// true if this instance is file; otherwise, false. - /// - public bool IsFile => IOUtils.IsLocalFile(Location); - - /// - /// Initializes a new instance of the class. - /// - /// The model. - public MediaItem(MediaItemModel model, IValidator validator, IMessenger messenger) - : base(model, validator, messenger) - { - _location = model.Location; - _description = model.Description; - _title = model.Title; - _sequence = model.Sequence; - _duration = TimeSpan.FromTicks(model.Duration); - _privacyStatus = (PrivacyStatus)model.PrivacyStatus; - _mediaItemType = (MediaItemType)model.MediaItemType; - _createdBy = model.CreatedBy; - _createdOn = model.CreatedOn; - _updatedBy = model.UpdatedBy; - _updatedOn = model.UpdatedOn; - - Validate(); - } - - /// - /// Returns a that represents this instance. - /// - /// - /// A that represents this instance. - /// - public override string ToString() - { - var result = Title == string.Empty ? Location : Title; - return result; - } - } -} diff --git a/src/Maple/ViewModels/MediaItems/MediaItems.cs b/src/Maple/ViewModels/MediaItems/MediaItems.cs deleted file mode 100644 index ce97881..0000000 --- a/src/Maple/ViewModels/MediaItems/MediaItems.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using Maple.Core; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple -{ - public class MediaItems : BaseDataListViewModel, IMediaItemsViewModel - { - private readonly Func _repositoryFactory; - private readonly IMediaItemMapper _mediaItemMapper; - - public MediaItems(ViewModelServiceContainer container, IMediaItemMapper mediaItemMapper, Func repositoryFactory) - : base(container) - { - _repositoryFactory = repositoryFactory ?? throw new ArgumentNullException(nameof(repositoryFactory), $"{nameof(repositoryFactory)} {Resources.IsRequired}"); - _mediaItemMapper = mediaItemMapper ?? throw new ArgumentNullException(nameof(mediaItemMapper), $"{nameof(mediaItemMapper)} {Resources.IsRequired}"); - } - - public void Add(Playlist playlist) - { - var sequence = _sequenceProvider.Get(Items.Select(p => (ISequence)p).ToList()); - Add(_mediaItemMapper.GetNewMediaItem(sequence, playlist)); - } - - private void SaveInternal() - { - _log.Info($"{_translationService.Translate(nameof(Resources.Saving))} {_translationService.Translate(nameof(Resources.MediaItems))}"); - using (var context = _repositoryFactory()) - { - context.Save(this); - } - } - - public override async Task LoadAsync() - { - _log.Info($"{_translationService.Translate(nameof(Resources.Loading))} {_translationService.Translate(nameof(Resources.MediaItems))}"); - Clear(); - - using (var context = _repositoryFactory()) - { - var result = await context.GetMediaItemsAsync().ConfigureAwait(true); - AddRange(result); - } - - SelectedItem = Items.FirstOrDefault(); - OnLoaded(); - } - - public override void Save() - { - SaveInternal(); - } - } -} diff --git a/src/Maple/ViewModels/MediaPlayer/AudioDevice.cs b/src/Maple/ViewModels/MediaPlayer/AudioDevice.cs deleted file mode 100644 index 066b170..0000000 --- a/src/Maple/ViewModels/MediaPlayer/AudioDevice.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Maple.Core; -using Maple.Domain; - -namespace Maple -{ - public class AudioDevice : ObservableObject, IIsSelected, ISequence, IAudioDevice - { - private bool _isSelected; - - - public bool IsSelected - { - get { return _isSelected; } - set { SetValue(ref _isSelected, value); } - } - - private int _channels; - /// - /// Number specifying whether the device supports mono (1) or stereo (2) output. - /// - /// - /// The channels. - /// - public int Channels - { - get { return _channels; } - set { SetValue(ref _channels, value); } - } - - private string _name; - public string Name - { - get { return _name; } - set { SetValue(ref _name, value); } - } - - private int _sequence; - public int Sequence - { - get { return _sequence; } - set { SetValue(ref _sequence, value); } - } - - public AudioDevice(string szPname, short wChannels) - { - Name = szPname; - Channels = wChannels; - } - - public AudioDevice() - { - Name = string.Empty; - Channels = 0; - } - - override public string ToString() - { - return Name; - } - } -} diff --git a/src/Maple/ViewModels/MediaPlayer/AudioDevices.cs b/src/Maple/ViewModels/MediaPlayer/AudioDevices.cs deleted file mode 100644 index 03afdf9..0000000 --- a/src/Maple/ViewModels/MediaPlayer/AudioDevices.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Linq; -using Maple.Core; -using Maple.Domain; - -namespace Maple -{ - /// - /// - /// - /// - public class AudioDevices : BaseListViewModel - { - public AudioDevices(ILoggingService log, IMessenger messenger) - : base(messenger) - { - AddRange(PlaybackDeviceFactory.GetAudioDevices(log).ToList()); - } - } -} diff --git a/src/Maple/ViewModels/MediaPlayer/Base/BasePlayer.cs b/src/Maple/ViewModels/MediaPlayer/Base/BasePlayer.cs deleted file mode 100644 index 0a5f181..0000000 --- a/src/Maple/ViewModels/MediaPlayer/Base/BasePlayer.cs +++ /dev/null @@ -1,67 +0,0 @@ -using Maple.Core; -using Maple.Domain; - -namespace Maple -{ - public abstract class BasePlayer : ViewModel, IMediaPlayer - { - protected readonly ILoggingService _log; - - private IRangeObservableCollection _items; - public IRangeObservableCollection Items - { - get { return _items; } - private set { SetValue(ref _items, value); } - } - - private IAudioDevice _audioDevice; - public IAudioDevice AudioDevice - { - get { return _audioDevice; } - set - { - SetValue(ref _audioDevice, value, - OnChanging: () => Messenger.Publish(new ViewModelSelectionChangingMessage(this, _audioDevice)), - OnChanged: () => Messenger.Publish(new ViewModelSelectionChangingMessage(this, value))); - } - } - - private IMediaItem _current; - public IMediaItem Current - { - get { return _current; } - set { SetValue(ref _current, value); } - } - - protected BasePlayer(IMessenger messenger, AudioDevices audioDevices) - : base(messenger) - { - } - - public abstract bool CanPlay(IMediaItem item); - - public abstract bool IsPlaying { get; } - - public abstract int Volume { get; set; } - - public abstract int VolumeMax { get; } - - public abstract int VolumeMin { get; } - - public abstract bool Play(IMediaItem mediaItem); - - public abstract void Pause(); - - public abstract void Stop(); - - public virtual bool CanStop() - { - return false; - } - - public virtual bool CanPause() - { - return false; - } - } -} diff --git a/src/Maple/ViewModels/MediaPlayer/MainMediaPlayer.cs b/src/Maple/ViewModels/MediaPlayer/MainMediaPlayer.cs deleted file mode 100644 index e5513ed..0000000 --- a/src/Maple/ViewModels/MediaPlayer/MainMediaPlayer.cs +++ /dev/null @@ -1,31 +0,0 @@ -using FluentValidation; -using Maple.Core; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple -{ - public class MainMediaPlayer : MediaPlayer - { - private const string _nameKey = nameof(Resources.MainMediaplayer); - - public MainMediaPlayer(ViewModelServiceContainer container, IMediaPlayer player, IValidator validator, AudioDevices devices, Playlist playlist, MediaPlayerModel model) - : base(container, player, validator, devices, playlist, model) - { - IsPrimary = model.IsPrimary; - - _manager.PropertyChanged += (o, e) => - { - if (e.PropertyName == nameof(ILocalizationService.CurrentLanguage)) - UpdateName(); - }; - - UpdateName(); - } - - private void UpdateName() - { - Name = _manager.Translate(_nameKey); - } - } -} diff --git a/src/Maple/ViewModels/MediaPlayer/MediaPlayer.cs b/src/Maple/ViewModels/MediaPlayer/MediaPlayer.cs deleted file mode 100644 index de531f3..0000000 --- a/src/Maple/ViewModels/MediaPlayer/MediaPlayer.cs +++ /dev/null @@ -1,436 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Windows.Input; -using FluentValidation; -using Maple.Core; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple -{ - [DebuggerDisplay("{Name}, {Sequence}")] - public class MediaPlayer : ValidableBaseDataViewModel, IDisposable, IChangeState, ISequence - { - protected readonly ILocalizationService _manager; - - public bool IsPlaying { get { return Player.IsPlaying; } } - - public bool IsNew => Model.IsNew; - public bool IsDeleted => Model.IsDeleted; - - private IMediaPlayer _player; - public IMediaPlayer Player - { - get { return _player; } - private set { SetValue(ref _player, value); } - } - - public ICommand PlayCommand { get; private set; } - public ICommand PauseCommand { get; private set; } - public ICommand NextCommand { get; private set; } - public ICommand PreviousCommand { get; private set; } - public ICommand StopCommand { get; private set; } - public ICommand RemoveRangeCommand { get; protected set; } - public ICommand RemoveCommand { get; protected set; } - public ICommand ClearCommand { get; protected set; } - - private ICommand _loadFromFileCommand; - public ICommand LoadFromFileCommand - { - get { return _loadFromFileCommand; } - private set { SetValue(ref _loadFromFileCommand, value); } - } - - private ICommand _loadFromFolderCommand; - public ICommand LoadFromFolderCommand - { - get { return _loadFromFolderCommand; } - private set { SetValue(ref _loadFromFolderCommand, value); } - } - - private ICommand _loadFromUrlCommand; - public ICommand LoadFromUrlCommand - { - get { return _loadFromUrlCommand; } - private set { SetValue(ref _loadFromUrlCommand, value); } - } - - private AudioDevices _audioDevices; - public AudioDevices AudioDevices - { - get { return _audioDevices; } - private set { SetValue(ref _audioDevices, value); } - } - - private Playlist _playlist; - public Playlist Playlist - { - get { return _playlist; } - set { SetValue(ref _playlist, value, OnChanging: OnPlaylistChanging, OnChanged: OnPlaylistChanged); } - } - - private int _sequence; - public int Sequence - { - get { return _sequence; } - set { SetValue(ref _sequence, value, OnChanged: () => Model.Sequence = value); } - } - - private string _name; - public string Name - { - get { return _name; } - set { SetValue(ref _name, value, OnChanged: () => Model.Name = value); } - } - - private bool _isPrimary; - public bool IsPrimary - { - get { return _isPrimary; } - protected set { SetValue(ref _isPrimary, value, OnChanged: () => Model.IsPrimary = value); } - } - - private string _createdBy; - public string CreatedBy - { - get { return _createdBy; } - set { SetValue(ref _createdBy, value, OnChanged: () => Model.CreatedBy = value); } - } - - private string _updatedBy; - public string UpdatedBy - { - get { return _updatedBy; } - set { SetValue(ref _updatedBy, value, OnChanged: () => Model.UpdatedBy = value); } - } - - private DateTime _updatedOn; - public DateTime UpdatedOn - { - get { return _updatedOn; } - set { SetValue(ref _updatedOn, value, OnChanged: () => Model.UpdatedOn = value); } - } - - private DateTime _createdOn; - public DateTime CreatedOn - { - get { return _updatedOn; } - set { SetValue(ref _updatedOn, value, OnChanged: () => Model.CreatedOn = value); } - } - - public MediaPlayer(ViewModelServiceContainer container, IMediaPlayer player, IValidator validator, AudioDevices devices, Playlist playlist, MediaPlayerModel model) - : base(model, validator, container.Messenger) - { - _manager = container.LocalizationService; - Player = player ?? throw new ArgumentNullException(nameof(player), $"{nameof(player)} {Resources.IsRequired}"); - - _name = model.Name; - _audioDevices = devices; - _sequence = model.Sequence; - - _createdBy = model.CreatedBy; - _createdOn = model.CreatedOn; - _updatedBy = model.UpdatedBy; - _updatedOn = model.UpdatedOn; - - if (AudioDevices.Items.Count > 0) - Player.AudioDevice = AudioDevices.Items.FirstOrDefault(p => p.Name == Model.DeviceName) ?? AudioDevices[0]; - - Playlist = playlist; - - InitializeSubscriptions(); - InitiliazeCommands(); - - Validate(); - } - - private void InitializeSubscriptions() - { - MessageTokens.Add(Messenger.Subscribe(Player_PlayingMediaItem, IsSenderEqualsPlayer)); - MessageTokens.Add(Messenger.Subscribe(MediaPlayer_CompletedMediaItem, IsSenderEqualsPlayer)); - MessageTokens.Add(Messenger.Subscribe>(Player_AudioDeviceChanging, IsSenderEqualsPlayer)); - MessageTokens.Add(Messenger.Subscribe>(Player_AudioDeviceChanged, IsSenderEqualsPlayer)); - } - - private void InitiliazeCommands() - { - PlayCommand = new RelayCommand(Play, CanPlay); - PreviousCommand = new RelayCommand(Previous, () => Playlist?.CanPrevious() == true && CanPrevious()); - NextCommand = new RelayCommand(Next, () => Playlist?.CanNext() == true && CanNext()); - PauseCommand = new RelayCommand(Pause, () => CanPause()); - StopCommand = new RelayCommand(Stop, () => CanStop()); - RemoveCommand = new RelayCommand(Remove, CanRemove); - ClearCommand = new RelayCommand(Clear, CanClear); - - UpdatePlaylistCommands(); - } - - public void Play(MediaItem mediaItem) - { - if (mediaItem == null) - throw new ArgumentNullException(nameof(mediaItem), $"{nameof(mediaItem)} {Resources.IsRequired}"); - - if (!Playlist.Items.Contains(mediaItem)) - throw new ArgumentException("Cant play an item thats not part of the playlist"); // TODO localize - - if (Player.Play(mediaItem)) - Messenger.Publish(new PlayingMediaItemMessage(this, mediaItem, Playlist.Id)); - } - - private bool IsSenderEqualsPlayer(object sender) - { - return ReferenceEquals(sender, Player); - } - - private void Player_AudioDeviceChanging(ViewModelSelectionChangingMessage e) - { - // TODO handle Player_AudioDeviceChanging - } - - private void Player_AudioDeviceChanged(ViewModelSelectionChangingMessage e) - { - if (!string.IsNullOrEmpty(e?.Content?.Name)) - Model.DeviceName = e.Content.Name; - } - - private void OnPlaylistChanging() - { - Stop(); - } - - private void OnPlaylistChanged() - { - Model.Playlist = Playlist.Model; - // TODO: maybe add optional endless playback - - OnPropertyChanged(nameof(Playlist.View)); - - UpdatePlaylistCommands(); - } - - private void UpdatePlaylistCommands() - { - if (Playlist != null) - { - LoadFromFileCommand = Playlist.LoadFromFileCommand; - LoadFromFolderCommand = Playlist.LoadFromFolderCommand; - LoadFromUrlCommand = Playlist.LoadFromUrlCommand; - } - } - - private void Player_PlayingMediaItem(PlayingMediaItemMessage e) - { - // TODO: sync state to other viewmodels - OnPropertyChanged(nameof(IsPlaying)); - } - - private void MediaPlayer_CompletedMediaItem(CompletedMediaItemMessage e) - { - OnPropertyChanged(nameof(IsPlaying)); - - Next(); - } - - /// - /// Clears this instance. - /// - public void Clear() - { - using (BusyStack.GetToken()) - Playlist.Clear(); - } - - /// - /// Determines whether this instance can clear. - /// - /// - /// true if this instance can clear; otherwise, false. - /// - public bool CanClear() - { - return !IsBusy && Playlist.Count > 0; - } - - /// - /// Adds the range. - /// - /// The media items. - public void AddRange(IEnumerable mediaItems) - { - using (BusyStack.GetToken()) - { - foreach (var item in mediaItems) - Playlist.Add(item); - } - } - - /// - /// Adds the specified media item. - /// - /// The media item. - public void Add(MediaItem mediaItem) - { - using (BusyStack.GetToken()) - { - if (Playlist.Items.Any()) - { - var maxIndex = Playlist.Items.Max(p => p.Sequence) + 1; - if (maxIndex < 0) - maxIndex = 0; - - mediaItem.Sequence = maxIndex; - } - else - mediaItem.Sequence = 0; - - Playlist.Add(mediaItem); - } - } - - /// - /// Removes the specified item. - /// - /// The item. - public void Remove(MediaItem item) - { - using (BusyStack.GetToken()) - Playlist.Remove(item); - } - - private bool CanRemove(MediaItem item) - { - using (BusyStack.GetToken()) - return Playlist.CanRemove(item); - } - - /// - /// Pauses this instance. - /// - public void Pause() - { - using (BusyStack.GetToken()) - Player.Pause(); - } - - /// - /// Stops this instance. - /// - public void Stop() - { - using (BusyStack.GetToken()) - Player.Stop(); - } - - /// - /// Previouses this instance. - /// - public void Previous() - { - using (BusyStack.GetToken()) - { - var item = Playlist.Previous(); - Play(item); - } - } - - /// - /// Nexts this instance. - /// - public void Next() - { - using (BusyStack.GetToken()) - { - var item = Playlist.Next(); - Play(item); - } - } - - /// - /// Determines whether this instance can next. - /// - /// - /// true if this instance can next; otherwise, false. - /// - public bool CanNext() - { - var item = Playlist.Next(); - return CanPlay(item); - } - - /// - /// Determines whether this instance can previous. - /// - /// - /// true if this instance can previous; otherwise, false. - /// - public bool CanPrevious() - { - var item = Playlist.Previous(); - return CanPlay(item); - } - - /// - /// Determines whether this instance can pause. - /// - /// - /// true if this instance can pause; otherwise, false. - /// - public bool CanPause() - { - return Player.CanPause(); - } - - /// - /// Determines whether this instance can stop. - /// - /// - /// true if this instance can stop; otherwise, false. - /// - public bool CanStop() - { - return Player.CanStop(); - } - - /// - /// Determines whether this instance can play the specified item. - /// - /// The item. - /// - /// true if this instance can play the specified item; otherwise, false. - /// - private bool CanPlay(MediaItem item) - { - return Player.CanPlay(item); - } - - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected override void Dispose(bool disposing) - { - if (Disposed) - return; - - if (IsPlaying) - Stop(); - - if (disposing) - { - if (Player != null) - { - Player?.Dispose(); - Player = null; - } - - base.Dispose(disposing); - // Free any other managed objects here. - } - - // Free any unmanaged objects here. - Disposed = true; - } - } -} diff --git a/src/Maple/ViewModels/MediaPlayer/MediaPlayers.cs b/src/Maple/ViewModels/MediaPlayer/MediaPlayers.cs deleted file mode 100644 index f482a5f..0000000 --- a/src/Maple/ViewModels/MediaPlayer/MediaPlayers.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using Maple.Core; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple -{ - public class MediaPlayers : BaseDataListViewModel, IMediaPlayersViewModel - { - private readonly Func _playerFactory; - private readonly AudioDevices _devices; - private readonly IDialogViewModel _dialog; - private readonly Func _repositoryFactory; - private readonly IMediaPlayerMapper _mediaPlayerMapper; - private readonly ILoggingNotifcationService _notificationService; - - /// - /// Initializes a new instance of the class. - /// - /// The manager. - /// The player factory. - /// The repo. - /// The devices. - /// The dialog. - public MediaPlayers(ViewModelServiceContainer container, - IMediaPlayerMapper mediaPlayerMapper, - Func playerFactory, - Func repositoryFactory, - AudioDevices devices, - IDialogViewModel dialog) - : base(container) - { - _playerFactory = playerFactory ?? throw new ArgumentNullException(nameof(playerFactory), $"{nameof(playerFactory)} {Resources.IsRequired}"); - _devices = devices ?? throw new ArgumentNullException(nameof(devices), $"{nameof(devices)} {Resources.IsRequired}"); - _dialog = dialog ?? throw new ArgumentNullException(nameof(dialog), $"{nameof(dialog)} {Resources.IsRequired}"); - _repositoryFactory = repositoryFactory ?? throw new ArgumentNullException(nameof(repositoryFactory), $"{nameof(repositoryFactory)} {Resources.IsRequired}"); - _mediaPlayerMapper = mediaPlayerMapper ?? throw new ArgumentNullException(nameof(mediaPlayerMapper), $"{nameof(mediaPlayerMapper)} {Resources.IsRequired}"); - - _notificationService = container.NotificationService; - } - - private void SaveInternal() - { - _log.Info($"{_translationService.Translate(nameof(Resources.Saving))} {_translationService.Translate(nameof(Resources.MediaPlayers))}"); - using (var context = _repositoryFactory()) - { - context.Save(this); - } - } - - public void Add() - { - var sequence = _sequenceProvider.Get(Items.Select(p => (ISequence)p).ToList()); - Add(_mediaPlayerMapper.GetNewMediaPlayer(sequence)); - } - - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected override void Dispose(bool disposing) - { - if (Disposed) - return; - - if (disposing) - { - foreach (var player in Items) - player?.Dispose(); - - // Free any other managed objects here. - } - - // Free any unmanaged objects here. - Disposed = true; - } - - public override void Save() - { - SaveInternal(); - } - - public override async Task LoadAsync() - { - _notificationService.Info($"{_translationService.Translate(nameof(Resources.Loading))} {_translationService.Translate(nameof(Resources.MediaPlayers))}"); - Clear(); - - using (var context = _repositoryFactory()) - { - var main = await context.GetMainMediaPlayerAsync().ConfigureAwait(true); - - Add(main); - SelectedItem = main; - - var others = await context.GetAllOptionalMediaPlayersAsync().ConfigureAwait(true); - AddRange(others); - } - - OnLoaded(); - } - } -} diff --git a/src/Maple/ViewModels/MediaPlayer/NAudio/IWavePlayerFactory.cs b/src/Maple/ViewModels/MediaPlayer/NAudio/IWavePlayerFactory.cs deleted file mode 100644 index 6df7095..0000000 --- a/src/Maple/ViewModels/MediaPlayer/NAudio/IWavePlayerFactory.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Maple.Domain; -using NAudio.Wave; - -namespace Maple -{ - public interface IWavePlayerFactory - { - IWavePlayer GetPlayer(ILoggingService log); - } -} \ No newline at end of file diff --git a/src/Maple/ViewModels/MediaPlayer/NAudio/NAudioMediaPlayer.cs b/src/Maple/ViewModels/MediaPlayer/NAudio/NAudioMediaPlayer.cs deleted file mode 100644 index 0c1710b..0000000 --- a/src/Maple/ViewModels/MediaPlayer/NAudio/NAudioMediaPlayer.cs +++ /dev/null @@ -1,159 +0,0 @@ -using System; -using Maple.Core; -using Maple.Domain; -using Maple.Localization.Properties; -using NAudio.Wave; - -namespace Maple -{ - public sealed class NAudioMediaPlayer : BasePlayer - { - private readonly MediaFoundationReader.MediaFoundationReaderSettings _settings; - - private IWavePlayer _player; - private WaveStream _reader; - private VolumeWaveProvider16 _volumeProvider; - - public override int VolumeMax => 1; - public override int VolumeMin => 0; - - private int _volume; - public override int Volume - { - get { return _volume; } - set { SetValue(ref _volume, value, OnChanged: () => SyncVolumeToVolumeProvider(value)); } - } - - public NAudioMediaPlayer(ILoggingService log, IMessenger messenger, AudioDevices audioDevices, IWavePlayerFactory factory) - : base(messenger, audioDevices) - { - _settings = new MediaFoundationReader.MediaFoundationReaderSettings - { - RepositionInRead = true, - SingleReaderObject = false, - RequestFloatOutput = false, - }; - - _player = factory.GetPlayer(log); - _player.PlaybackStopped += PlaybackStopped; - - Messenger.Subscribe(OnPlaybackStarted); - - OnPropertyChanged(nameof(VolumeMin)); - OnPropertyChanged(nameof(VolumeMax)); - } - - private void OnPlaybackStarted(PlayingMediaItemMessage e) - { - Current = e.Content; - } - - private void PlaybackStopped(object sender, StoppedEventArgs e) - { - Messenger.Publish(new CompletedMediaItemMessage(this, Current)); - Current = null; - - OnPropertyChanged(nameof(IsPlaying)); - } - - public override bool IsPlaying - { - get { return _player?.PlaybackState != null && _player.PlaybackState != NAudio.Wave.PlaybackState.Playing; } - } - - public override bool CanPlay(IMediaItem item) - { - return item != null && _player?.PlaybackState != null && _player.PlaybackState != NAudio.Wave.PlaybackState.Playing && item.MediaItemType.HasFlag(MediaItemType.LocalFile); - } - - public override bool CanPause() - { - return _player?.PlaybackState != null && _player.PlaybackState != NAudio.Wave.PlaybackState.Playing; - } - - public override bool CanStop() - { - return _player?.PlaybackState != null && _player.PlaybackState != NAudio.Wave.PlaybackState.Playing; - } - - public override void Pause() - { - if (_player == null) - throw new ArgumentNullException(nameof(_player), $"{nameof(_player)} {Resources.IsRequired}"); - - if (_player?.PlaybackState != NAudio.Wave.PlaybackState.Playing) - throw new InvalidOperationException("Can't pause playback of a file, thats not being played back"); // TODO localize - - _player.Pause(); - } - - public override bool Play(IMediaItem mediaItem) - { - if (_player?.PlaybackState == NAudio.Wave.PlaybackState.Playing) - throw new InvalidOperationException("Can't play a file, when already playing"); // TODO localize - - _reader = new MediaFoundationReader(mediaItem.Location, _settings); - - _volumeProvider = new VolumeWaveProvider16(_reader) - { - Volume = 0.5f - }; - _player.Init(_volumeProvider); - _player.Play(); - - return true; - } - - public override void Stop() - { - if (_player == null) - throw new ArgumentNullException(nameof(_player), $"{nameof(_player)} {Resources.IsRequired}"); - - if (_player?.PlaybackState != NAudio.Wave.PlaybackState.Playing) - return; - - _player.Stop(); - } - - private void SyncVolumeToVolumeProvider(int value) - { - if (_volumeProvider == null || value > 100 && value < 0) - return; - - _volumeProvider.Volume = value / 100; - } - - protected override void Dispose(bool disposing) - { - if (Disposed) - return; - - if (IsPlaying) - Stop(); - - if (disposing) - { - base.Dispose(disposing); - - if (_player != null) - { - _player.PlaybackStopped -= PlaybackStopped; - _player?.Dispose(); - _player = null; - } - - if (_reader != null) - { - _reader?.Close(); - _reader?.Dispose(); - _reader = null; - } - - // Free any other managed objects here. - } - - // Free any unmanaged objects here. - Disposed = true; - } - } -} diff --git a/src/Maple/ViewModels/MediaPlayer/NAudio/PlaybackDeviceFactory.cs b/src/Maple/ViewModels/MediaPlayer/NAudio/PlaybackDeviceFactory.cs deleted file mode 100644 index 6546fd2..0000000 --- a/src/Maple/ViewModels/MediaPlayer/NAudio/PlaybackDeviceFactory.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Collections.Generic; -using Maple.Domain; -using NAudio.Wave; - -namespace Maple -{ - public static class PlaybackDeviceFactory - { - public static IEnumerable GetAudioDevices(ILoggingService log) - { - for (var i = 0; i < WaveOut.DeviceCount; i++) - { - var cap = GetCapabilities(i, log); - if (Equals(cap, default(WaveOutCapabilities))) - break; - - yield return new AudioDevice - { - Channels = cap.Channels, - Name = cap.ProductName, - Sequence = i, - }; - } - - } - - private static WaveOutCapabilities GetCapabilities(int index, ILoggingService log) - { - try - { - return WaveOut.GetCapabilities(index); - } - catch (Exception ex) - { - log.Error(ex); - return default(WaveOutCapabilities); - } - } - } -} diff --git a/src/Maple/ViewModels/MediaPlayer/NAudio/WaveFormatFactory.cs b/src/Maple/ViewModels/MediaPlayer/NAudio/WaveFormatFactory.cs deleted file mode 100644 index 25e9062..0000000 --- a/src/Maple/ViewModels/MediaPlayer/NAudio/WaveFormatFactory.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.IO; -using NAudio.Wave; - -namespace Maple -{ - public static class WaveFormatFactory - { - public static WaveFormat GetWaveFormat(string fileName) - { - using (var reader = new WaveFileReader(fileName)) - { - return reader.WaveFormat; - } - } - - public static WaveFormat GetWaveFormat(Stream stream) - { - using (var reader = new WaveFileReader(stream)) - { - return reader.WaveFormat; - } - } - } -} diff --git a/src/Maple/ViewModels/MediaPlayer/NAudio/WavePlayerFactory.cs b/src/Maple/ViewModels/MediaPlayer/NAudio/WavePlayerFactory.cs deleted file mode 100644 index e372ca7..0000000 --- a/src/Maple/ViewModels/MediaPlayer/NAudio/WavePlayerFactory.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Maple.Domain; -using NAudio.Wave; - -namespace Maple -{ - public class WavePlayerFactory : IWavePlayerFactory - { - public IWavePlayer GetPlayer(ILoggingService log) - { - var player = default(WaveOutEvent); - try - { - player = new WaveOutEvent - { - DesiredLatency = 200, - Volume = 0.5f, - DeviceNumber = 0, - }; - } - catch (NAudio.MmException ex) - { - log.Error(ex); - // appveyeor does not have any audio devices i guess - } - - return player; - } - } -} diff --git a/src/Maple/ViewModels/Navigation/Scene.cs b/src/Maple/ViewModels/Navigation/Scene.cs deleted file mode 100644 index e095499..0000000 --- a/src/Maple/ViewModels/Navigation/Scene.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System; -using System.Windows; -using Maple.Core; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple -{ - /// - /// - /// - /// - /// - public class Scene : ObservableObject, ISequence - { - private readonly ILocalizationService _manager; - private readonly BusyStack _busyStack; - - private bool _isBusy; - /// - /// Indicates if there is an operation running. - /// Modified by adding to the property - /// - /// - /// true if this instance is busy; otherwise, false. - /// - public bool IsBusy - { - get { return _isBusy; } - private set { SetValue(ref _isBusy, value); } - } - - private FrameworkElement _content; - /// - /// Gets or sets the content. - /// - /// - /// The content. - /// - public FrameworkElement Content - { - get { return _content; } - set { SetValue(ref _content, value); } - } - - private string _key; - /// - /// Gets or sets the key. - /// - /// - /// The key. - /// - public string Key - { - get { return _key; } - set { SetValue(ref _key, value, OnChanged: UpdateDisplayName); } - } - - private string _displayName; - /// - /// Gets the display name. - /// - /// - /// The display name. - /// - public string DisplayName - { - get { return _displayName; } - private set { SetValue(ref _displayName, value); } - } - - private bool _isSelected; - /// - /// Gets or sets a value indicating whether this instance is selected. - /// - /// - /// true if this instance is selected; otherwise, false. - /// - public bool IsSelected - { - get { return _isSelected; } - set { SetValue(ref _isSelected, value); } - } - - public int _sequence; - /// - /// Gets or sets the sequence. - /// - /// - /// The sequence. - /// - public int Sequence - { - get { return _sequence; } - set { SetValue(ref _sequence, value); } - } - - /// - /// Initializes a new instance of the class. - /// - /// The manager. - public Scene(ILocalizationService manager) - { - _manager = manager ?? throw new ArgumentNullException(nameof(manager), $"{nameof(manager)} {Resources.IsRequired}"); - _manager.PropertyChanged += (o, e) => - { - if (e.PropertyName == nameof(_manager.CurrentLanguage)) - UpdateDisplayName(); - }; - - _busyStack = new BusyStack(); - _busyStack.OnChanged += (hasItems) => IsBusy = hasItems; - } - - private void UpdateDisplayName() - { - if (Key != null) - DisplayName = _manager.Translate(Key); - } - } -} diff --git a/src/Maple/ViewModels/Navigation/Scenes.cs b/src/Maple/ViewModels/Navigation/Scenes.cs deleted file mode 100644 index 2d3292b..0000000 --- a/src/Maple/ViewModels/Navigation/Scenes.cs +++ /dev/null @@ -1,208 +0,0 @@ -using System; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Windows.Controls; -using System.Windows.Input; -using Maple.Core; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple -{ - /// - /// ViewModel that stores and controls which UserControl(Page/View) whatever is displayed in the mainwindow of this app) - /// - /// - public class Scenes : BaseListViewModel - { - private readonly ILocalizationService _manager; - private readonly ILoggingService _log; - - private bool _isExpanded; - /// - /// Gets or sets a value indicating whether the control bound to this instance is expanded. - /// - /// - /// true if this instance is expanded; otherwise, false. - /// - /// - public bool IsExpanded - { - get { return _isExpanded; } - set { SetValue(ref _isExpanded, value); } - } - - /// - /// Gets the close expander command. - /// - /// - /// The close expander command. - /// - /// - public ICommand CloseExpanderCommand { get; private set; } - - /// - /// Gets the open color options command. - /// - /// - /// The open color options command. - /// - public ICommand OpenColorOptionsCommand { get; private set; } - /// - /// Gets the open media player command. - /// - /// - /// The open media player command. - /// - public ICommand OpenMediaPlayerCommand { get; private set; } - /// - /// Gets the open github page command. - /// - /// - /// The open github page command. - /// - public ICommand OpenGithubPageCommand { get; private set; } - - /// - /// Gets the open options page command. - /// - /// - /// The open options page command. - /// - /// - public ICommand OpenOptionsCommand { get; private set; } - - /// - /// Initializes a new instance of the class. - /// - /// The manager. - /// The log. - public Scenes(ILocalizationService manager, ILoggingService log, IMessenger messenger, FileSystemViewModel fileSystemViewModel) - : base(messenger) - { - _manager = manager ?? throw new ArgumentNullException(nameof(manager), Resources.IsRequired); - _log = log ?? throw new ArgumentNullException(nameof(log)); - - var content = new[] - { - new Scene(_manager) - { - Content = new MediaPlayerPage(_manager), - Key = nameof(Resources.Playback), - IsSelected = true, - Sequence = 100, - }, - - new Scene(_manager) - { - Content = new PlaylistsPage(_manager), - Key = nameof(Resources.Playlists), - IsSelected = false, - Sequence = 300, - }, - - new Scene(_manager) - { - Content = new ColorOptionsPage(_manager), - Key = nameof(Resources.Themes), - IsSelected = false, - Sequence = 500, - }, - - new Scene(_manager) - { - Content = new OptionsPage(_manager), - Key = nameof(Resources.Options), - IsSelected = false, - Sequence = 600, - }, - - new Scene(_manager) - { - Content = new MediaPlayersPage(_manager), - Key = nameof(Resources.Director), - IsSelected = false, - Sequence = 150, - }, - - // keeping this for debugging the FileBrowser - //new Scene(_manager) - //{ - // Content = new ContentPresenter() - // { - // Content = new FileBrowserContentDialogViewModel(fileSystemViewModel, new FileSystemBrowserOptions() - // { - // CanCancel=false, - // MultiSelection= true, - // Title="Test" - // }) - // }, - // Key = nameof(Resources.Director), - // IsSelected = true, - // Sequence = 700, - //}, - }; - - using (BusyStack.GetToken()) - { - AddRange(content); - - SelectedItem = this[0]; - - using (View.DeferRefresh()) - { - View.SortDescriptions.Add(new SortDescription(nameof(Scene.Sequence), ListSortDirection.Ascending)); - } - } - - InitializeCommands(); - } - - private void InitializeCommands() - { - OpenColorOptionsCommand = new RelayCommand(OpenColorOptionsView, CanOpenColorOptionsView); - OpenMediaPlayerCommand = new RelayCommand(OpenMediaPlayerView, CanOpenMediaPlayerView); - OpenOptionsCommand = new RelayCommand(OpenOptionsView, CanOpenOptionsView); - OpenGithubPageCommand = new RelayCommand(OpenGithubPage); - CloseExpanderCommand = new RelayCommand(() => IsExpanded = false, () => IsExpanded != false); - } - - private void OpenOptionsView() - { - SelectedItem = Items.First(p => p.Content.GetType() == typeof(OptionsPage)); - } - - private bool CanOpenOptionsView() - { - return Items?.Any(p => p.Content.GetType() == typeof(OptionsPage)) == true; - } - - private void OpenColorOptionsView() - { - SelectedItem = Items.First(p => p.Content.GetType() == typeof(ColorOptionsPage)); - } - - private bool CanOpenColorOptionsView() - { - return Items?.Any(p => p.Content.GetType() == typeof(ColorOptionsPage)) == true; - } - - private void OpenMediaPlayerView() - { - SelectedItem = Items.First(p => p.Content.GetType() == typeof(MediaPlayerPage)); - } - - private bool CanOpenMediaPlayerView() - { - return Items?.Any(p => p.Content.GetType() == typeof(MediaPlayerPage)) == true; - } - - private void OpenGithubPage() - { - using (Process.Start(_manager.Translate(nameof(Resources.GithubProjectLink)))) - { - } - } - } -} diff --git a/src/Maple/ViewModels/Playlists/CreatePlaylist.cs b/src/Maple/ViewModels/Playlists/CreatePlaylist.cs deleted file mode 100644 index 6fff809..0000000 --- a/src/Maple/ViewModels/Playlists/CreatePlaylist.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System.Threading.Tasks; -using System.Windows.Input; -using Maple.Core; -using Maple.Youtube; - -namespace Maple -{ - /// - /// viewmodel for creating playlists from a input string (path/url) - /// - /// - public class CreatePlaylist : BaseListViewModel - { - private readonly IYoutubeUrlParser _dataParsingService; - private readonly IPlaylistMapper _mapper; - - private string _source; - /// - /// Gets or sets the source. - /// - /// - /// The source. - /// - public string Source - { - get { return _source; } - set { SetValue(ref _source, value); } - } - - private UrlParseResult _result; - /// - /// Gets the result. - /// - /// - /// The result. - /// - public UrlParseResult Result - { - get { return _result; } - private set { SetValue(ref _result, value); } - } - - /// - /// Gets the parse command. - /// - /// - /// The parse command. - /// - public ICommand ParseCommand { get; private set; } - - /// - /// Initializes a new instance of the class. - /// - /// The data parsing service. - /// The mapper. - public CreatePlaylist(IYoutubeUrlParser dataParsingService, IPlaylistMapper mapper, IMessenger messenger) - : base(messenger) - { - _dataParsingService = dataParsingService; - _mapper = mapper; - - InitializeCommands(); - } - - private void InitializeCommands() - { - ParseCommand = AsyncCommand.Create(Parse, CanParse); - } - - private async Task Parse() - { - using (BusyStack.GetToken()) - { - Result = await _dataParsingService.Parse(Source, ParseResultType.Playlists) - .ConfigureAwait(true); - - if (Result.Count > 0 && Result.Playlists?.Count > 0) - AddRange(_mapper.GetMany(Result.Playlists)); - } - } - - private bool CanParse() - { - return !string.IsNullOrWhiteSpace(Source); - } - } -} diff --git a/src/Maple/ViewModels/Playlists/Playlist.cs b/src/Maple/ViewModels/Playlists/Playlist.cs deleted file mode 100644 index baa7bc1..0000000 --- a/src/Maple/ViewModels/Playlists/Playlist.cs +++ /dev/null @@ -1,580 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Data; -using System.Windows.Input; -using FluentValidation; -using Maple.Core; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple -{ - [DebuggerDisplay("{Title}, {Sequence}")] - public class Playlist : ValidableBaseDataViewModel, IIsSelected, ISequence, IIdentifier, IChangeState - { - private readonly IMediaItemMapper _mediaItemMapper; - private readonly ISequenceService _sequenceProvider; - private readonly ILocalizationService _translator; - private readonly IDialogViewModel _dialogViewModel; - private readonly object _itemsLock; - private readonly Stack _history; - - public bool IsNew => Model.IsNew; - public bool IsDeleted => Model.IsDeleted; - public int Count => Items?.Count ?? 0; - - public IAsyncCommand LoadFromFileCommand { get; private set; } - public IAsyncCommand LoadFromFolderCommand { get; private set; } - public IAsyncCommand LoadFromUrlCommand { get; private set; } - public ICommand RemoveRangeCommand { get; protected set; } - public ICommand RemoveCommand { get; protected set; } - public ICommand ClearCommand { get; protected set; } - - public int Id - { - get { return Model.Id; } - } - - public string CreatedBy - { - get { return Model.CreatedBy; } - } - - public string UpdatedBy - { - get { return Model.UpdatedBy; } - } - - public DateTime UpdatedOn - { - get { return Model.UpdatedOn; } - } - - public DateTime CreatedOn - { - get { return Model.CreatedOn; } - } - - public MediaItem this[int index] - { - get { return _items[index]; } - } - - private ICollectionView _view; - public ICollectionView View - { - get { return _view; } - protected set { SetValue(ref _view, value); } - } - - private IRangeObservableCollection _items; - [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public IReadOnlyCollection Items - { - get { return (IReadOnlyCollection)_items; } - private set { SetValue(ref _items, (IRangeObservableCollection)value); } - } - - private MediaItem _selectedItem; - /// - /// is when a IMediaPlayer picks a from this - /// - /// - /// The current item. - /// - public MediaItem SelectedItem - { - get { return _selectedItem; } - set - { - SetValue(ref _selectedItem, value, - OnChanging: () => Messenger.Publish(new ViewModelSelectionChangingMessage(Items, _selectedItem)), - OnChanged: () => Messenger.Publish(new ViewModelSelectionChangedMessage(Items, value))); - } - } - - private int _sequence; - public int Sequence - { - get { return _sequence; } - set { SetValue(ref _sequence, value, OnChanged: () => Model.Sequence = value); } - } - - private PrivacyStatus _privacyStatus; - /// - /// Youtube Property - /// - /// - /// The privacy status. - /// - public PrivacyStatus PrivacyStatus - { - get { return _privacyStatus; } - private set { SetValue(ref _privacyStatus, value, OnChanged: () => Model.PrivacyStatus = (int)value); } - } - - private bool _isSelected; - /// - /// if this list is part of a ui bound collection and selected this should be true - /// - /// - /// true if this instance is selected; otherwise, false. - /// - public bool IsSelected - { - get { return _isSelected; } - set { SetValue(ref _isSelected, value); } - } - - private bool _isShuffeling; - /// - /// indicates whether the next item is selected randomly from the list of items on a call of Next() - /// - /// - /// true if this instance is shuffeling; otherwise, false. - /// - public bool IsShuffeling - { - get { return _isShuffeling; } - set { SetValue(ref _isShuffeling, value, OnChanged: () => Model.IsShuffeling = value); } - } - - private string _title; - public string Title - { - get { return _title; } - set { SetValue(ref _title, value, OnChanged: () => Model.Title = value); } - } - - private string _description; - public string Description - { - get { return _description; } - set { SetValue(ref _description, value, OnChanged: () => Model.Description = value); } - } - - private RepeatMode _repeatMode; - public RepeatMode RepeatMode - { - get { return _repeatMode; } - set { SetValue(ref _repeatMode, value, OnChanged: () => Model.RepeatMode = (int)value); } - } - - private IRangeObservableCollection _repeatModes; - public IReadOnlyCollection RepeatModes - { - get { return (IReadOnlyCollection)_repeatModes; } - private set { SetValue(ref _repeatModes, (IRangeObservableCollection)value); } - } - - public Playlist(ViewModelServiceContainer container, IValidator validator, IDialogViewModel dialogViewModel, IMediaItemMapper mediaItemMapper, PlaylistModel model) - : base(model, validator, container?.Messenger) - { - if (container == null) - throw new ArgumentNullException(nameof(container), $"{nameof(container)} {Resources.IsRequired}"); - - SkipChangeTracking = true; - using (BusyStack.GetToken()) - { - _itemsLock = new object(); - - _mediaItemMapper = mediaItemMapper ?? throw new ArgumentNullException(nameof(mediaItemMapper), $"{nameof(mediaItemMapper)} {Resources.IsRequired}"); - _dialogViewModel = dialogViewModel ?? throw new ArgumentNullException(nameof(dialogViewModel), $"{nameof(dialogViewModel)} {Resources.IsRequired}"); - _sequenceProvider = container.SequenceService; - - _translator = container.LocalizationService; - _title = model.Title; - _description = model.Description; - _repeatMode = (RepeatMode)model.RepeatMode; - _isShuffeling = model.IsShuffeling; - _sequence = model.Sequence; - - RepeatModes = new RangeObservableCollection(Enum.GetValues(typeof(RepeatMode)).Cast().ToList()); - _history = new Stack(); - - Items = new RangeObservableCollection(); - _items.CollectionChanged += (o, e) => OnPropertyChanged(nameof(Count)); - - BindingOperations.EnableCollectionSynchronization(Items, _itemsLock); - View = CollectionViewSource.GetDefaultView(Items); // TODO add sorting by sequence - OnPropertyChanged(nameof(Count)); - - LoadFromFileCommand = AsyncCommand.Create(LoadFromFile, () => CanLoadFromFile()); - LoadFromFolderCommand = AsyncCommand.Create(LoadFromFolder, () => CanLoadFromFolder()); - LoadFromUrlCommand = AsyncCommand.Create(LoadFromUrl, () => CanLoadFromUrl()); - - RemoveCommand = new RelayCommand(Remove, CanRemove); - RemoveRangeCommand = new RelayCommand(RemoveRange, CanRemoveRange); - ClearCommand = new RelayCommand(() => Clear(), CanClear); - - AddRange(_mediaItemMapper.GetMany(model.MediaItems)); - - MessageTokens.Add(Messenger.Subscribe(OnPlaybackItemChanged, m => m.PlaylistId == Id && _items.Contains(m.Content))); - - Validate(); - } - SkipChangeTracking = false; - } - - private void OnPlaybackItemChanged(PlayingMediaItemMessage message) - { - _history.Push(message.Content.Sequence); - } - - private async Task LoadFromUrl(CancellationToken token) - { - using (BusyStack.GetToken()) - { - var items = await _dialogViewModel.ShowUrlParseDialog(token).ConfigureAwait(true); - AddRange(items); - } - } - - private bool CanLoadFromUrl() - { - return !IsBusy; - } - - private async Task LoadFromFolder(CancellationToken token) - { - using (BusyStack.GetToken()) - { - var options = new FileSystemFolderBrowserOptions() - { - IncludeSubFolders = false, - CanCancel = true, - MultiSelection = false, - Title = _translator.Translate(nameof(Resources.SelectFolder)), - }; - - (var Result, var MediaItems) = await _dialogViewModel.ShowMediaItemFolderSelectionDialog(options, token).ConfigureAwait(true); - if (Result) - AddRange(MediaItems); - } - } - - private bool CanLoadFromFolder() - { - return !IsBusy; - } - - private async Task LoadFromFile(CancellationToken token) - { - using (BusyStack.GetToken()) - { - var options = new FileSystemBrowserOptions() - { - CanCancel = true, - MultiSelection = false, - Title = _translator.Translate(nameof(Resources.SelectFiles)), - }; - - (var Result, var MediaItems) = await _dialogViewModel.ShowMediaItemSelectionDialog(options, token).ConfigureAwait(true); - if (Result) - AddRange(MediaItems); - } - } - - private bool CanLoadFromFile() - { - return !IsBusy; - } - - public virtual void Clear() - { - _history.Clear(); - SelectedItem = null; - RemoveRange(Items.AsEnumerable()); - } - - private bool CanClear() - { - return Items?.Any() == true; - } - - public virtual void Add(MediaItem item) - { - if (item == null) - throw new ArgumentNullException(nameof(item), $"{nameof(item)} {Resources.IsRequired}"); - - using (BusyStack.GetToken()) - { - var sequence = _sequenceProvider.Get(Items.Select(p => (ISequence)p).ToList()); - item.Sequence = sequence; - - AddInternal(item); - - if (SelectedItem == null) - SelectedItem = Items.First(); - } - } - - private void AddInternal(MediaItem item) - { - item.Playlist = this; - _items.Add(item); - - if (!Model.MediaItems.Contains(item.Model)) - Model.MediaItems.Add(item.Model); - } - - public virtual void AddRange(IEnumerable items) - { - if (items == null) - throw new ArgumentNullException(nameof(items), $"{nameof(items)} {Resources.IsRequired}"); - - using (BusyStack.GetToken()) - { - var added = false; - var sequence = 0; - var collection = items.ToList(); - var item = default(MediaItem); - - for (var i = 0; i < collection.Count; i++) - { - if (i == 0) - sequence = _sequenceProvider.Get(Items.Select(p => (ISequence)p).ToList()); - - item = collection[i]; - - if (item == null) - throw new ArgumentNullException(nameof(item), $"{nameof(item)} {Resources.IsRequired}"); - - item.Sequence = sequence; - AddInternal(item); - sequence++; - - added = true; - } - - if (SelectedItem == null && (added || Items.Count > 0)) - SelectedItem = Items.First(); - } - } - - private void Remove(object item) - { - Remove(item as MediaItem); - } - - public virtual void Remove(MediaItem item) - { - if (item == null) - throw new ArgumentNullException(nameof(item), $"{nameof(item)} {Resources.IsRequired}"); - - using (BusyStack.GetToken()) - { - while (Items.Contains(item)) - RemoveInternal(item); - } - } - - private void RemoveInternal(MediaItem item) - { - if (SelectedItem == item) - SelectedItem = Next(); - - _items.Remove(item); - item.Model.IsDeleted = true; - } - - public virtual void RemoveRange(IEnumerable items) - { - if (items == null) - throw new ArgumentNullException(nameof(items), $"{nameof(items)} {Resources.IsRequired}"); - - using (BusyStack.GetToken()) - RemoveRangeInternal(items.ToList()); - } - - private void RemoveRange(IList items) - { - if (items == null) - throw new ArgumentNullException(nameof(items), $"{nameof(items)} {Resources.IsRequired}"); - - using (BusyStack.GetToken()) - RemoveRangeInternal(items.Cast().ToList()); - } - - private void RemoveRangeInternal(IEnumerable items) - { - foreach (var item in items) - Remove(item); - } - - public virtual bool CanRemove(object item) - { - if (Items == null || Items.Count == 0) - return false; - - var mediaItem = item as MediaItem; - if (mediaItem == null) - return false; - - return Items.Contains(mediaItem) && !IsBusy; - } - - protected virtual bool CanRemoveRange(IEnumerable items) - { - return CanClear() && items != null && items.Any(p => Items.Contains(p)); - } - - protected virtual bool CanRemoveRange(IList items) - { - return items == null ? false : CanRemoveRange(items.Cast()); - } - - /// - /// Returns the next MediaItem from the Items collection according to their respective sequence and the current RepeatMode - /// - /// - public virtual MediaItem Next() - { - using (BusyStack.GetToken()) - { - if (Items != null && Items.Any()) - { - switch (RepeatMode) - { - case RepeatMode.All: - return IsShuffeling ? NextShuffle() : NextRepeatAll(); - - case RepeatMode.None: - return IsShuffeling ? NextShuffle() : NextRepeatNone(); - - case RepeatMode.Single: return NextRepeatSingle(); - - default: - throw new NotImplementedException(nameof(RepeatMode)); - } - } - - return null; - } - } - - private MediaItem NextRepeatNone() - { - var currentIndex = 0; - if (SelectedItem?.Sequence != null) - currentIndex = SelectedItem?.Sequence ?? 0; - - if (Items.Count > 1) - { - var nextPossibleItems = Items.Where(p => p.Sequence > currentIndex); - - if (nextPossibleItems?.Any() == true) // try to find items after the current one - { - Items.ToList().ForEach(p => p.IsSelected = false); - var foundItem = nextPossibleItems.Where(q => q.Sequence == nextPossibleItems.Select(p => p.Sequence).Min()).First(); - foundItem.IsSelected = true; - return foundItem; - } - - return null; - // we dont repeat, so there is nothing to do here - } - else - return NextRepeatSingle(); - } - - private MediaItem NextRepeatSingle() - { - if (RepeatMode != RepeatMode.None) - return SelectedItem; - else - return null; - } - - private MediaItem NextRepeatAll() - { - var currentIndex = 0; - if (SelectedItem?.Sequence != null) - currentIndex = SelectedItem?.Sequence ?? 0; - - if (Items.Count > 1) - { - var nextPossibleItems = Items.Where(p => p.Sequence > currentIndex); - - if (nextPossibleItems.Any()) // try to find items after the current one - { - Items.ToList().ForEach(p => p.IsSelected = false); - var foundItem = nextPossibleItems.Where(q => q.Sequence == nextPossibleItems.Select(p => p.Sequence).Min()).First(); - foundItem.IsSelected = true; - return foundItem; - } - else // if there are none, use the first item in the list - { - Items.ToList().ForEach(p => p.IsSelected = false); - var foundItem = Items.First(); - foundItem.IsSelected = true; - return foundItem; - } - } - else - return NextRepeatSingle(); - } - - private MediaItem NextShuffle() - { - if (Items.Count > 1) - { - var nextItems = Items.Where(p => p.Sequence != SelectedItem?.Sequence); // get all items besides the current one - Items.ToList().ForEach(p => p.IsSelected = false); - var foundItem = nextItems.Random(); - foundItem.IsSelected = true; - return foundItem; - } - else - return NextRepeatSingle(); - } - - public virtual MediaItem Previous() - { - using (BusyStack.GetToken()) - { - Items.ToList().ForEach(p => p.IsSelected = false); // deselect all items in the list - - if (_history?.Any() == true) - { - while (_history.Any()) - { - var previous = _history.Pop(); - - //if (previous == SelectedItem?.Sequence) // the most recent item in the history, is the just played item, so we wanna skip that - // continue; - - if (previous > -1) - { - var previousItems = Items.Where(p => p.Sequence == previous); // try to get the last played item - if (previousItems.Any()) - { - var foundItem = previousItems.First(); - foundItem.IsSelected = true; - - return foundItem; - } - } - } - } - return null; - } - } - - public bool CanNext() - { - return Items != null && Items.Any(); - } - - public bool CanPrevious() - { - return _history != null && _history.Any(); - } - } -} diff --git a/src/Maple/ViewModels/Playlists/Playlists.cs b/src/Maple/ViewModels/Playlists/Playlists.cs deleted file mode 100644 index 5f425ea..0000000 --- a/src/Maple/ViewModels/Playlists/Playlists.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using Maple.Core; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple -{ - public class Playlists : BaseDataListViewModel, ISaveableViewModel, IPlaylistsViewModel - { - private readonly Func _repositoryFactory; - private readonly IPlaylistMapper _playlistMapper; - - public Playlists(ViewModelServiceContainer container, IPlaylistMapper playlistMapper, Func repositoryFactory) - : base(container) - { - _repositoryFactory = repositoryFactory ?? throw new ArgumentNullException(nameof(repositoryFactory), $"{nameof(repositoryFactory)} {Resources.IsRequired}"); - _playlistMapper = playlistMapper ?? throw new ArgumentNullException(nameof(playlistMapper), $"{nameof(playlistMapper)} {Resources.IsRequired}"); - - AddCommand = new RelayCommand(Add, CanAdd); - } - - private void SaveInternal() - { - _log.Info($"{_translationService.Translate(nameof(Resources.Saving))} {_translationService.Translate(nameof(Resources.Playlists))}"); - using (var context = _repositoryFactory()) - { - context.Save(this); - } - } - - public void Add() - { - Add(_playlistMapper.GetNewPlaylist()); - } - - public bool CanAdd() - { - return Items != null; - } - - public override void Save() - { - SaveInternal(); - } - - public override async Task LoadAsync() - { - _log.Info($"{_translationService.Translate(nameof(Resources.Loading))} {_translationService.Translate(nameof(Resources.Playlists))}"); - Clear(); - - using (var context = _repositoryFactory()) - { - var result = await context.GetPlaylistsAsync().ConfigureAwait(true); - AddRange(result); - } - - SelectedItem = Items.FirstOrDefault(); - OnLoaded(); - } - } -} diff --git a/src/Maple/ViewModels/Settings/Culture.cs b/src/Maple/ViewModels/Settings/Culture.cs deleted file mode 100644 index 9b502f0..0000000 --- a/src/Maple/ViewModels/Settings/Culture.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Globalization; -using Maple.Core; - -namespace Maple -{ - public class Culture : BaseViewModel - { - public string DisplayName => Model.DisplayName; - - public Culture(CultureInfo info, IMessenger messenger) - : base(info, messenger) - { - } - } -} diff --git a/src/Maple/ViewModels/Settings/Cultures.cs b/src/Maple/ViewModels/Settings/Cultures.cs deleted file mode 100644 index b48b499..0000000 --- a/src/Maple/ViewModels/Settings/Cultures.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using System.Windows.Input; -using Maple.Core; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple -{ - public class Cultures : BaseListViewModel, ICultureViewModel - { - private readonly ILocalizationService _manager; - private readonly ILoggingService _log; - - public ICommand RefreshCommand => AsyncCommand.Create(LoadAsync); - public ICommand LoadCommand => AsyncCommand.Create(LoadAsync, () => !IsLoaded); - public ICommand SaveCommand => new RelayCommand(Save); - - public Cultures(ViewModelServiceContainer container) - : base(container.Messenger) - { - _log = container.Log; - _manager = container.LocalizationService; - - MessageTokens.Add(Messenger.Subscribe>(UpdateCulture)); - } - - private void SyncCulture() - { - _manager.CurrentLanguage = SelectedItem.Model; - } - - public void Save() - { - _log.Info($"{Resources.Saving} {Resources.Options}"); - _manager.Save(); - } - - public Task SaveAsync() - { - return Task.Run(() => - { - _log.Info($"{Resources.Saving} {Resources.Options}"); - _manager.Save(); - - }); - } - - public async Task LoadAsync() - { - _log.Info($"{Resources.Loading} {Resources.Options}"); - await _manager.LoadAsync().ConfigureAwait(true); - - Initialise(); - - IsLoaded = true; - Messenger.Publish(new LoadedMessage(this, this)); - } - - private void Initialise() - { - AddRange(_manager.Languages.Select(p => new Culture(p, Messenger)).ToList()); - SelectedItem = Items.FirstOrDefault(p => p.Model.LCID == Core.Properties.Settings.Default.StartUpCulture.LCID) ?? Items.First(p => p.Model.TwoLetterISOLanguageName == "en"); - } - - private void UpdateCulture(ViewModelSelectionChangedMessage obj) - { - if (obj.Content?.Model != null) - _manager.CurrentLanguage = obj.Content.Model; - } - } -} diff --git a/src/Maple/ViewModels/Settings/OptionsViewModel.cs b/src/Maple/ViewModels/Settings/OptionsViewModel.cs deleted file mode 100644 index 14d51f7..0000000 --- a/src/Maple/ViewModels/Settings/OptionsViewModel.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using Maple.Core; -using Maple.Localization.Properties; - -namespace Maple -{ - public class OptionsViewModel : ObservableObject - { - private ICultureViewModel _cultureViewModel; - public ICultureViewModel CultureViewModel - { - get { return _cultureViewModel; } - set { SetValue(ref _cultureViewModel, value); } - } - - private IUIColorsViewModel _uiColorsViewModel; - public IUIColorsViewModel UIColorsViewModel - { - get { return _uiColorsViewModel; } - set { SetValue(ref _uiColorsViewModel, value); } - } - - public OptionsViewModel(IUIColorsViewModel colors, ICultureViewModel culture) - { - UIColorsViewModel = colors ?? throw new ArgumentNullException(nameof(colors), $"{nameof(colors)} {Resources.IsRequired}"); - CultureViewModel = culture ?? throw new ArgumentNullException(nameof(culture), $"{nameof(culture)} {Resources.IsRequired}"); - } - } -} diff --git a/src/Maple/ViewModels/Settings/UIColorsViewModel.cs b/src/Maple/ViewModels/Settings/UIColorsViewModel.cs deleted file mode 100644 index c6c0760..0000000 --- a/src/Maple/ViewModels/Settings/UIColorsViewModel.cs +++ /dev/null @@ -1,211 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using System.Windows.Input; -using Maple.Core; -using Maple.Domain; -using Maple.Localization.Properties; -using MaterialDesignColors; -using MaterialDesignThemes.Wpf; - -namespace Maple -{ - /// - /// - /// - /// - /// - /// - public class UIColorsViewModel : ObservableObject, IUIColorsViewModel - { - private readonly ILoggingService _log; - private readonly IMessenger _messenger; - - private static bool _isDark; - private static string _accent; - private static string _swatch; - - private static PaletteHelper _paletteHelper = new PaletteHelper(); - - private bool _isLoaded; - /// - /// Gets a value indicating whether this instance is loaded. - /// - /// - /// true if this instance is loaded; otherwise, false. - /// - public bool IsLoaded - { - get { return _isLoaded; } - private set { SetValue(ref _isLoaded, value); } - } - - private ICommand _toggleBaseCommand; - /// - /// Gets the toggle base command. - /// - /// - /// The toggle base command. - /// - public ICommand ToggleBaseCommand - { - get { return _toggleBaseCommand; } - private set { SetValue(ref _toggleBaseCommand, value); } - } - - private ICommand _applyPrimaryCommand; - /// - /// Gets the apply primary command. - /// - /// - /// The apply primary command. - /// - public ICommand ApplyPrimaryCommand - { - get { return _applyPrimaryCommand; } - private set { SetValue(ref _applyPrimaryCommand, value); } - } - - private ICommand _applyAccentCommand; - /// - /// Gets the apply accent command. - /// - /// - /// The apply accent command. - /// - public ICommand ApplyAccentCommand - { - get { return _applyAccentCommand; } - private set { SetValue(ref _applyAccentCommand, value); } - } - - /// - /// Gets the refresh command. - /// - /// - /// The refresh command. - /// - public ICommand RefreshCommand => new RelayCommand(Load); - /// - /// Gets the load command. - /// - /// - /// The load command. - /// - public ICommand LoadCommand => new RelayCommand(Load, () => !IsLoaded); - /// - /// Gets the save command. - /// - /// - /// The save command. - /// - public ICommand SaveCommand => new RelayCommand(Save); - - /// - /// Gets the swatches. - /// - /// - /// The swatches. - /// - public static IEnumerable Swatches => new SwatchesProvider().Swatches; - - /// - /// Initializes a new instance of the class. - /// - public UIColorsViewModel(ViewModelServiceContainer container) - { - _log = container.Log; - _messenger = container.Messenger; - - OnPropertyChanged(nameof(Swatches)); - InitializeCommands(); - } - - private void InitializeCommands() - { - ToggleBaseCommand = new RelayCommand(() => ApplyBase(this, !_isDark)); - ApplyPrimaryCommand = new RelayCommand(o => ApplyPrimary(this, o)); - ApplyAccentCommand = new RelayCommand(o => ApplyAccent(this, o)); - } - - private static void ApplyBase(IUIColorsViewModel vm, bool isDark = false) - { - _paletteHelper.SetLightDark(isDark); - _isDark = isDark; - } - - private static void ApplyPrimary(IUIColorsViewModel vm, Swatch swatch) - { - if (swatch == null) - return; - - var oldPalette = _paletteHelper.QueryPalette(); - _paletteHelper.ReplacePrimaryColor(swatch); - var newPalette = _paletteHelper.QueryPalette(); - - if (newPalette.PrimarySwatch.Name != oldPalette.PrimarySwatch.Name) - vm.OnPrimaryColorChanged(new UiPrimaryColorChangedMessage(vm, newPalette.PrimarySwatch.ExemplarHue.Color)); - - _swatch = swatch.Name; - } - - private static void ApplyAccent(IUIColorsViewModel vm, Swatch swatch) - { - if (swatch == null) - return; - - _paletteHelper.ReplaceAccentColor(swatch); - _accent = swatch.Name; - } - - public void OnPrimaryColorChanged(UiPrimaryColorChangedMessage args) - { - _messenger.Publish(args); - } - - /// - /// Saves this instance. - /// - public void Save() - { - _log.Info($"{Resources.Saving} {Resources.Themes}"); - - Properties.Settings.Default.AccentName = _accent; - Properties.Settings.Default.SwatchName = _swatch; - Properties.Settings.Default.UseDarkTheme = _isDark; - - Properties.Settings.Default.Save(); - } - - /// - /// Loads this instance. - /// - public void Load() - { - _log.Info($"{Resources.Loading} {Resources.Themes}"); - - var swatchName = Properties.Settings.Default.SwatchName; - var swatch = Swatches.FirstOrDefault(p => p.Name == swatchName); - - var accentName = Properties.Settings.Default.AccentName; - var accent = Swatches.FirstOrDefault(p => p.Name == accentName); - - ApplyPrimary(this, swatch); - ApplyAccent(this, accent); - ApplyBase(this, Properties.Settings.Default.UseDarkTheme); - - _messenger.Publish(new LoadedMessage(this, this)); - } - - public Task SaveAsync() - { - return Task.Run(() => Save()); - } - - public Task LoadAsync() - { - Load(); - return Task.CompletedTask; - } - } -} diff --git a/src/Maple/ViewModels/ShellViewModel.cs b/src/Maple/ViewModels/ShellViewModel.cs deleted file mode 100644 index 1da8769..0000000 --- a/src/Maple/ViewModels/ShellViewModel.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System; -using Maple.Core; -using Maple.Localization.Properties; - -namespace Maple -{ - /// - /// - /// - /// - public class ShellViewModel : ObservableObject - { - private StatusbarViewModel _statusbarViewModel; - /// - /// Gets the statusbar view model. - /// - /// - /// The statusbar view model. - /// - public StatusbarViewModel StatusbarViewModel - { - get { return _statusbarViewModel; } - private set { SetValue(ref _statusbarViewModel, value); } - } - - private Scenes _scenes; - /// - /// Gets the scenes. - /// - /// - /// The scenes. - /// - public Scenes Scenes - { - get { return _scenes; } - private set { SetValue(ref _scenes, value); } - } - - private ILocalizationService _translationManager; - /// - /// Gets the translation manager. - /// - /// - /// The translation manager. - /// - public ILocalizationService TranslationManager - { - get { return _translationManager; } - private set { SetValue(ref _translationManager, value); } - } - - private IDialogViewModel _dialogViewModel; - /// - /// Gets the dialog view model. - /// - /// - /// The dialog view model. - /// - public IDialogViewModel DialogViewModel - { - get { return _dialogViewModel; } - private set { SetValue(ref _dialogViewModel, value); } - } - - private IPlaylistsViewModel _playlists; - /// - /// Gets the playlists. - /// - /// - /// The playlists. - /// - public IPlaylistsViewModel Playlists - { - get { return _playlists; } - private set { SetValue(ref _playlists, value); } - } - - private IMediaPlayersViewModel _mediaPlayers; - /// - /// Gets the media players. - /// - /// - /// The media players. - /// - public IMediaPlayersViewModel MediaPlayers - { - get { return _mediaPlayers; } - private set { SetValue(ref _mediaPlayers, value); } - } - - private OptionsViewModel _optionsViewModel; - /// - /// Gets the options view model. - /// - /// - /// The options view model. - /// - public OptionsViewModel OptionsViewModel - { - get { return _optionsViewModel; } - private set { SetValue(ref _optionsViewModel, value); } - } - - /// - /// Initializes a new instance of the class. - /// - /// The translation manager. - /// The scenes. - /// The status bar view model. - /// The dialog view model. - /// The playlists. - /// The media players. - /// The UI colors view model. - /// The options view model. - public ShellViewModel(ILocalizationService translationManager, - Scenes scenes, - StatusbarViewModel statusBarViewModel, - IDialogViewModel dialogViewModel, - IPlaylistsViewModel playlists, - IMediaPlayersViewModel mediaPlayers, - OptionsViewModel optionsViewModel) - { - TranslationManager = translationManager ?? throw new ArgumentNullException(nameof(translationManager), $"{nameof(translationManager)} {Resources.IsRequired}"); - Scenes = scenes ?? throw new ArgumentNullException(nameof(scenes), $"{nameof(scenes)} {Resources.IsRequired}"); - StatusbarViewModel = statusBarViewModel ?? throw new ArgumentNullException(nameof(statusBarViewModel), $"{nameof(statusBarViewModel)} {Resources.IsRequired}"); - DialogViewModel = dialogViewModel ?? throw new ArgumentNullException(nameof(dialogViewModel), $"{nameof(dialogViewModel)} {Resources.IsRequired}"); - Playlists = playlists ?? throw new ArgumentNullException(nameof(playlists), $"{nameof(playlists)} {Resources.IsRequired}"); - MediaPlayers = mediaPlayers ?? throw new ArgumentNullException(nameof(mediaPlayers), $"{nameof(mediaPlayers)} {Resources.IsRequired}"); - OptionsViewModel = optionsViewModel ?? throw new ArgumentNullException(nameof(optionsViewModel), $"{nameof(optionsViewModel)} {Resources.IsRequired}"); - } - } -} diff --git a/src/Maple/ViewModels/StatusbarViewModel.cs b/src/Maple/ViewModels/StatusbarViewModel.cs deleted file mode 100644 index f91b8bc..0000000 --- a/src/Maple/ViewModels/StatusbarViewModel.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; -using Maple.Core; -using Maple.Domain; -using Maple.Localization.Properties; - -namespace Maple -{ - public class StatusbarViewModel : ViewModel - { - private string _version; - /// - /// Gets the version. - /// - /// - /// The version. - /// - public string Version - { - get { return _version; } - private set { SetValue(ref _version, value); } - } - - private string _language; - /// - /// Gets the language. - /// - /// - /// The language. - /// - public string Language - { - get { return _language; } - private set { SetValue(ref _language, value); } - } - - private MainMediaPlayer _mainMediaPlayer; - /// - /// Gets the main media player. - /// - /// - /// The main media player. - /// - public MainMediaPlayer MainMediaPlayer - { - get { return _mainMediaPlayer; } - private set { SetValue(ref _mainMediaPlayer, value); } - } - - /// - /// Initializes a new instance of the class. - /// - /// The manager. - /// The media players. - public StatusbarViewModel(IVersionService version, IMessenger messenger) - : base(messenger) - { - if (version == null) - throw new ArgumentNullException(nameof(version), $"{nameof(version)} {Resources.IsRequired}"); - - Version = version.Get(); - - MessageTokens.Add(Messenger.Subscribe>(UpdateLanguage)); - MessageTokens.Add(Messenger.Subscribe>(UpdateMediaPlayer)); - } - - private void UpdateLanguage(ViewModelSelectionChangedMessage message) - { - Language = $"({message.Content.Model.TwoLetterISOLanguageName})"; - } - - private void UpdateMediaPlayer(ViewModelSelectionChangedMessage message) - { - MainMediaPlayer = message.Content as MainMediaPlayer; - } - - // TODO add message queue and notify user about important notifications - } -} diff --git a/src/Maple/logo.ico b/src/Maple/logo.ico new file mode 100644 index 0000000..9dea666 Binary files /dev/null and b/src/Maple/logo.ico differ diff --git a/src/Resources/Images/2017-04-22-23-26-20.gif b/src/Resources/Images/2017-04-22-23-26-20.gif deleted file mode 100644 index 1d36274..0000000 Binary files a/src/Resources/Images/2017-04-22-23-26-20.gif and /dev/null differ diff --git a/src/Resources/SharedAssemblyInfo.cs b/src/Resources/SharedAssemblyInfo.cs index 4c15a37..23ba29d 100644 --- a/src/Resources/SharedAssemblyInfo.cs +++ b/src/Resources/SharedAssemblyInfo.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by Cake. // @@ -6,12 +6,12 @@ using System.Reflection; using System.Runtime.InteropServices; -[assembly: AssemblyCompany("")] +[assembly: AssemblyCompany("SoftThorn")] [assembly: AssemblyProduct("Maple")] [assembly: AssemblyVersion("0.0.1")] [assembly: AssemblyFileVersion("0.0.1")] [assembly: AssemblyInformationalVersion("0.0.0.1")] -[assembly: AssemblyCopyright("© 2017 Insire")] +[assembly: AssemblyCopyright("© 2020 Insire")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)]