From 032ec0e4848ccd3899651e13f16a0737ef37cbf8 Mon Sep 17 00:00:00 2001 From: Peter Vietense Date: Sun, 5 May 2019 14:43:55 +0200 Subject: [PATCH] updated implementation migrated EF to EF core added missing mappings from model to viewmodel dependency shuffle fixed sqlite not being loaded because of missing dll moved log files removed EF references from app.config added missing log project to source control fixed missing icon moved seeding to viewmodels, fixed relations added error handling to youtube api for missing credentials disabled updates for debug configuration bugfix MediaItem added local file support bugfix mediaplayer fixed audiovolume slider updated nuget packages fixed playing and resuming button working on saving state updated nuget package updated nuget package updated nuget package updated nuget packages --- .editorconfig | 1 + .gitignore | 2 + Maple.sln | 20 +- src/Maple.Core/Commands/AsyncCommandBase.cs | 1 + .../Commands/Obsolete/AsyncRelayCommand.cs | 1 + src/Maple.Core/Commands/RelayCommand.cs | 1 + src/Maple.Core/DiagnosticReport.cs | 499 ------------- src/Maple.Core/DiagnosticReportType.cs | 48 -- src/Maple.Core/DynamicDictionary.cs | 219 ------ src/Maple.Core/Ensure.cs | 241 ------- .../EventAggregator/MapleMessenger.cs | 1 + .../CancellableGenericMapleMessage.cs | 1 + .../Messages/MapleMessageBase.cs | 4 +- .../StrongMapleMessageSubscription.cs | 1 + .../WeakMapleMessageSubscription.cs | 1 + .../Extensions/AssemblyExtensions.cs | 131 ---- src/Maple.Core/Extensions/EventExtension.cs | 8 - .../Extensions/GenericExtensions.cs | 241 ------- src/Maple.Core/Extensions/LinqExtensions.cs | 28 +- src/Maple.Core/Extensions/SequenceType.cs | 186 ----- src/Maple.Core/Extensions/StringExtensions.cs | 675 ------------------ src/Maple.Core/Extensions/TypeExtensions.cs | 469 ------------ src/Maple.Core/Helpers/ApplicationHelper.cs | 62 -- src/Maple.Core/Helpers/NetworkHelper.cs | 84 --- src/Maple.Core/Helpers/ProcessHelper.cs | 117 --- src/Maple.Core/IO/Base/MapleFileSystemBase.cs | 7 +- .../IO/Base/MapleFileSystemContainerBase.cs | 1 + src/Maple.Core/IO/FileSystemViewModel.cs | 1 + .../IO/Interfaces/IFileSystemFile.cs | 1 - .../IO/Interfaces/IFileSystemInfo.cs | 6 + src/Maple.Core/IO/MapleDirectory.cs | 1 + src/Maple.Core/IO/MapleDrive.cs | 28 +- src/Maple.Core/IO/MapleFile.cs | 30 - .../IO/Util/FileSystemExtensions.cs | 1 + .../IO/Util/SelectedTreeViewItemBehavior.cs | 24 - .../Interfaces/IConfigurableWindowSettings.cs | 3 - .../Interfaces/IIocFrameworkElement.cs | 9 - .../Interfaces/ILoadableViewModel.cs | 11 +- .../Interfaces/ILocalizationService.cs | 25 +- src/Maple.Core/Maple.Core.csproj | 201 +----- .../Messages/PlayingMediaItemMessage.cs | 1 + src/Maple.Core/Observables/BusyStack.cs | 73 +- src/Maple.Core/Observables/BusyToken.cs | 58 +- src/Maple.Core/Observables/ChangeTracker.cs | 1 + .../Observables/NotifyTaskCompletion.cs | 1 + .../Observables/RangeObservableCollection.cs | 5 +- .../ViewModels/BaseDataListViewModel.cs | 46 +- .../ViewModels/BaseDataViewModel.cs | 1 + .../ViewModels/BaseListViewModel.cs | 62 +- .../ViewModels/ValidableBaseDataViewModel.cs | 2 + .../Observables/ViewModels/ViewModel.cs | 5 +- src/Maple.Core/ProcessExecutionResult.cs | 79 -- .../Services/Localization/LocalizationDTO.cs | 2 +- .../Localization/LocalizationService.cs | 21 +- .../Providers/ResxTranslationProvider.cs | 1 + .../Services/MrlExtractionService.cs | 1 + src/Maple.Core/Services/SequenceService.cs | 3 +- .../Services/ViewModelServiceContainer.cs | 1 + src/Maple.Core/StringBuilderCache.cs | 48 -- src/Maple.Core/app.config | 27 +- src/Maple.Data/App.config | 52 -- src/Maple.Data/Constants.cs | 7 + .../Configurations/MediaItemConfiguration.cs | 41 ++ .../MediaPlayerConfiguration.cs | 40 ++ .../DB/Configurations/OptionConfiguration.cs | 31 + .../Configurations/PlaylistConfiguration.cs | 40 ++ .../DB/CreateSeedDatabaseIfNotExists.cs | 285 -------- src/Maple.Data/DB/MapleUnitOfWork.cs | 34 + src/Maple.Data/DB/ModelConfiguration.cs | 28 - src/Maple.Data/DB/PlaylistContext.cs | 50 +- .../DB/Repository/Base/ReadOnlyRepository.cs | 86 +++ .../DB/Repository/Base/Repository.cs | 42 ++ .../DB/Repository/Base/UnitOfWork.cs | 23 + .../DB/Repository/MediaItemRepository.cs | 28 + .../DB/Repository/MediaPlayerRepository.cs | 27 + .../DB/Repository/PlaylistRepository.cs | 19 + src/Maple.Data/DesignTimeDbContextFactory.cs | 21 + src/Maple.Data/Maple.Data.csproj | 118 +-- .../20190505105243_Initial.Designer.cs | 208 ++++++ .../Migrations/20190505105243_Initial.cs | 138 ++++ .../PlaylistContextModelSnapshot.cs | 206 ++++++ .../Repository/Base/IMediaItemRepository.cs | 10 - .../Repository/Base/IMediaPlayerRepository.cs | 12 - .../Repository/Base/IPlaylistRepository.cs | 8 - .../Base/MaplePlaylistRepository.cs | 95 --- .../Repository/MediaItemRepository.cs | 29 - .../Repository/MediaPlayerRepository.cs | 53 -- .../Repository/PlaylistRepository.cs | 20 - src/Maple.Domain/Interfaces/IAudioDevice.cs | 2 +- .../Interfaces/IBaseListViewModel.cs | 40 ++ src/Maple.Domain/Interfaces/IBaseObject.cs | 5 +- src/Maple.Domain/Interfaces/IChangeState.cs | 1 + src/Maple.Domain/Interfaces/IEntity.cs | 7 + .../Interfaces/ILoggingNotifcationService.cs | 5 +- .../Interfaces/ILoggingService.cs | 4 + .../Interfaces/IMapleRepository.cs | 13 - .../Interfaces/IMediaItemRepository.cs | 12 + src/Maple.Domain/Interfaces/IMediaPlayer.cs | 7 + .../Interfaces/IMediaPlayerRepository.cs | 12 + .../Interfaces/IPlaylistRepository.cs | 10 + .../Interfaces/IRangeObservableCollection.cs | 4 +- .../Interfaces/IReadOnlyRepository.cs | 19 + src/Maple.Domain/Interfaces/IRefreshable.cs | 5 +- src/Maple.Domain/Interfaces/IRepository.cs | 12 + src/Maple.Domain/Interfaces/IUnitOfWork.cs | 14 + .../Interfaces/IVersionService.cs | 2 +- src/Maple.Domain/Maple.Domain.csproj | 83 +-- src/Maple.Domain/Models/Base/BaseObject.cs | 18 +- src/Maple.Domain/Models/MediaItemModel.cs | 14 +- src/Maple.Domain/Models/MediaPlayerModel.cs | 14 +- src/Maple.Domain/Models/OptionModel.cs | 7 +- src/Maple.Domain/Models/PlaylistModel.cs | 15 +- src/Maple.Domain/Models/RawModel.cs | 7 - src/Maple.Domain/Properties/AssemblyInfo.cs | 3 +- src/Maple.Icons/Maple.Icons.csproj | 22 + .../MaplePackIcon.cs} | 22 +- .../Maple.Localization.csproj | 71 +- .../Properties/Resources.Designer.cs | 2 +- .../Properties/Resources.resx | 5 +- .../DetailLoggingService.cs | 25 +- src/Maple.Log/Extensions.cs | 14 + src/Maple.Log/Log4NetLogger.cs | 99 +++ src/Maple.Log/Log4NetProvider.cs | 33 + .../Services => Maple.Log}/LoggingService.cs | 41 +- src/Maple.Log/Maple.Log.csproj | 18 + .../DependencyInjectionFactoryTests.cs | 9 +- src/Maple.Test/DiagnosticReportTests.cs | 269 ------- src/Maple.Test/DynamicDictionaryTests.cs | 267 ------- .../EnsuringCollectionNotNullOrEmptyTest.cs | 47 -- src/Maple.Test/Ensure/EnsuringEqualTests.cs | 100 --- src/Maple.Test/Ensure/EnsuringExistsTests.cs | 56 -- .../Ensure/EnsuringNotEqualTests.cs | 100 --- src/Maple.Test/Ensure/EnsuringNotNullTests.cs | 48 -- src/Maple.Test/Ensure/EnsuringNotTests.cs | 48 -- src/Maple.Test/Ensure/EnsuringThatTests.cs | 48 -- src/Maple.Test/Maple.Test.csproj | 32 +- src/Maple.Test/MapleMessengerTests.cs | 8 +- src/Maple.Test/StringBuilderCacheTests.cs | 60 -- .../TestUtils/ContainerContextExtensions.cs | 14 +- .../MediaItemModelContextModelExtensions.cs | 2 + .../PlaylistModelContextExtensions.cs | 2 + ...CheckingATypeForDefaultConstructorTests.cs | 137 ---- .../CheckingATypeImplementsTests.cs | 47 -- .../CheckingATypeIsSimpleTests.cs | 55 -- .../CheckingIfTypeIsASequenceTests.cs | 375 ---------- .../TypeExtension/CheckingTypeCodesTests.cs | 35 - .../TypeExtension/CheckingTypeIsNumeric.cs | 32 - src/Maple.Test/TypeExtension/Context.cs | 61 -- ...tingAllInstancePropertiesWithAttributes.cs | 42 -- .../GettingAllPropertiesWithAttributes.cs | 46 -- .../GettingArgumentTypeOfGenericTypeTests.cs | 174 ----- .../GettingParentPropertiesWithAttributes.cs | 44 -- .../TypeExtension/GettingPropertiesTests.cs | 43 -- .../ViewModels/Playlists/PlaylistTests.cs | 15 +- .../ViewModels/Playlists/PlaylistsTests.cs | 18 +- src/Maple.Test/app.config | 7 +- src/Maple.Youtube/IYoutubeApi.cs | 9 +- src/Maple.Youtube/Maple.Youtube.csproj | 4 +- src/Maple.Youtube/Utility/UrlParseResult.cs | 2 + src/Maple.Youtube/YoutubeApi.cs | 55 +- src/Maple.Youtube/YoutubeUrlParser.cs | 1 + src/Maple.Youtube/app.config | 41 +- src/Maple/App.config | 108 ++- src/Maple/App.xaml | 3 +- src/Maple/App.xaml.cs | 46 +- src/Maple/FodyWeavers.xml | 2 +- src/Maple/Interfaces/IMediaItemMapper.cs | 1 + src/Maple/Interfaces/IMediaPlayerMapper.cs | 3 +- src/Maple/Interfaces/IMediaRepository.cs | 29 - src/Maple/Maple.csproj | 50 +- src/Maple/Properties/AssemblyInfo.cs | 4 +- src/Maple/Resources/Style.xaml | 35 +- .../Services/LogNotifcationService.cs | 5 +- src/Maple/Services/MediaRepository.cs | 208 ------ src/Maple/Services/SquirrelLogger.cs | 5 + src/Maple/Services/VersionService.cs | 1 + src/Maple/Shell.xaml | 23 +- src/Maple/Shell.xaml.cs | 1 + src/Maple/SplashScreen.xaml | 1 - src/Maple/SplashScreen.xaml.cs | 1 + src/Maple/UI/Base/ConfigurableWindow.cs | 10 +- .../UI/Base/ConfigurableWindowSettings.cs | 5 +- src/Maple/UI/Base/IoCWindow.cs | 4 +- src/Maple/UI/Base/IocUserControl.cs | 1 + ...FileSystemBrowserDetailTemplateSelector.cs | 1 + src/Maple/UI/IoCResourceDictionary.cs | 1 + src/Maple/UI/ListBox.cs | 2 +- .../UI/MarkupExtensions/CaseConverter.cs | 3 + .../MarkupExtensions/MathMultipleConverter.cs | 10 +- .../RadioButtonCheckedConverter.cs | 4 - .../MarkupExtensions/TranslationExtension.cs | 1 + src/Maple/UI/ShellSettings.cs | 8 +- .../UI/UserControls/MediaPlayerPage.xaml | 8 +- .../Options/ColorOptionsPage.xaml | 2 - .../UI/UserControls/Options/OptionsPage.xaml | 1 - .../Playlist/NewPlaylistPage.xaml | 1 - .../UserControls/Playlist/PlaylistsPage.xaml | 12 +- src/Maple/Utils/DependencyInjectionFactory.cs | 22 +- src/Maple/Utils/Mappers/Base/BaseMapper.cs | 3 + src/Maple/Utils/Mappers/MapperExtensions.cs | 12 +- src/Maple/Utils/Mappers/MediaItemMapper.cs | 2 + src/Maple/Utils/Mappers/MediaPlayerMapper.cs | 3 + src/Maple/Utils/Mappers/PlaylistMapper.cs | 3 + .../Utils/Validation/Base/BaseValidator.cs | 2 + .../Utils/Validation/MediaItemValidator.cs | 1 + .../Utils/Validation/MediaPlayerValidator.cs | 6 +- .../Utils/Validation/PlaylistValidator.cs | 10 +- .../Utils/Validation/PlaylistsValidator.cs | 9 +- .../Dialogs/Base/DialogBaseViewModel.cs | 1 + .../Dialogs/Base/IDialogViewModel.cs | 10 +- .../ExceptionContentDialogViewModel.cs | 1 + .../IO/FileBrowserContentDialogViewModel.cs | 3 +- .../IO/FolderBrowserContentDialogViewModel.cs | 3 +- .../ViewModels/Dialogs/DialogViewModel.cs | 37 +- .../Interfaces/ICultureViewModel.cs | 2 +- .../Interfaces/IMediaItemsViewModel.cs | 8 +- .../Interfaces/IMediaPlayersViewModel.cs | 7 +- .../Interfaces/IPlaylistsViewModel.cs | 10 +- .../Interfaces/ISplashScreenViewModel.cs | 2 +- .../Interfaces/IUIColorsViewModel.cs | 3 +- .../ViewModels/MediaItems/CreateMediaItem.cs | 18 +- src/Maple/ViewModels/MediaItems/MediaItem.cs | 32 +- src/Maple/ViewModels/MediaItems/MediaItems.cs | 31 +- .../ViewModels/MediaPlayer/AudioDevice.cs | 3 +- .../ViewModels/MediaPlayer/AudioDevices.cs | 5 +- .../ViewModels/MediaPlayer/Base/BasePlayer.cs | 4 +- .../ViewModels/MediaPlayer/MainMediaPlayer.cs | 1 + .../ViewModels/MediaPlayer/MediaPlayer.cs | 19 +- .../ViewModels/MediaPlayer/MediaPlayers.cs | 92 ++- .../MediaPlayer/NAudio/IWavePlayerFactory.cs | 3 +- .../MediaPlayer/NAudio/NAudioMediaPlayer.cs | 46 +- .../NAudio/PlaybackDeviceFactory.cs | 3 +- .../MediaPlayer/NAudio/WaveFormatFactory.cs | 1 + .../MediaPlayer/NAudio/WavePlayerFactory.cs | 1 + src/Maple/ViewModels/Navigation/Scene.cs | 9 +- src/Maple/ViewModels/Navigation/Scenes.cs | 4 +- .../ViewModels/Playlists/CreatePlaylist.cs | 1 + src/Maple/ViewModels/Playlists/Playlist.cs | 2 + src/Maple/ViewModels/Playlists/Playlists.cs | 40 +- src/Maple/ViewModels/Settings/Culture.cs | 1 + src/Maple/ViewModels/Settings/Cultures.cs | 25 +- .../ViewModels/Settings/OptionsViewModel.cs | 1 + .../ViewModels/Settings/UIColorsViewModel.cs | 95 +-- src/Maple/ViewModels/ShellViewModel.cs | 58 +- src/Maple/ViewModels/SplashScreenViewModel.cs | 1 + src/Maple/ViewModels/StatusbarViewModel.cs | 1 + 246 files changed, 2235 insertions(+), 7642 deletions(-) delete mode 100644 src/Maple.Core/DiagnosticReport.cs delete mode 100644 src/Maple.Core/DiagnosticReportType.cs delete mode 100644 src/Maple.Core/DynamicDictionary.cs delete mode 100644 src/Maple.Core/Ensure.cs delete mode 100644 src/Maple.Core/Extensions/AssemblyExtensions.cs delete mode 100644 src/Maple.Core/Extensions/GenericExtensions.cs delete mode 100644 src/Maple.Core/Extensions/SequenceType.cs delete mode 100644 src/Maple.Core/Extensions/StringExtensions.cs delete mode 100644 src/Maple.Core/Extensions/TypeExtensions.cs delete mode 100644 src/Maple.Core/Helpers/ApplicationHelper.cs delete mode 100644 src/Maple.Core/Helpers/NetworkHelper.cs delete mode 100644 src/Maple.Core/Helpers/ProcessHelper.cs delete mode 100644 src/Maple.Core/ProcessExecutionResult.cs delete mode 100644 src/Maple.Core/StringBuilderCache.cs delete mode 100644 src/Maple.Data/App.config create mode 100644 src/Maple.Data/Constants.cs create mode 100644 src/Maple.Data/DB/Configurations/MediaItemConfiguration.cs create mode 100644 src/Maple.Data/DB/Configurations/MediaPlayerConfiguration.cs create mode 100644 src/Maple.Data/DB/Configurations/OptionConfiguration.cs create mode 100644 src/Maple.Data/DB/Configurations/PlaylistConfiguration.cs delete mode 100644 src/Maple.Data/DB/CreateSeedDatabaseIfNotExists.cs create mode 100644 src/Maple.Data/DB/MapleUnitOfWork.cs delete mode 100644 src/Maple.Data/DB/ModelConfiguration.cs create mode 100644 src/Maple.Data/DB/Repository/Base/ReadOnlyRepository.cs create mode 100644 src/Maple.Data/DB/Repository/Base/Repository.cs create mode 100644 src/Maple.Data/DB/Repository/Base/UnitOfWork.cs create mode 100644 src/Maple.Data/DB/Repository/MediaItemRepository.cs create mode 100644 src/Maple.Data/DB/Repository/MediaPlayerRepository.cs create mode 100644 src/Maple.Data/DB/Repository/PlaylistRepository.cs create mode 100644 src/Maple.Data/DesignTimeDbContextFactory.cs create mode 100644 src/Maple.Data/Migrations/20190505105243_Initial.Designer.cs create mode 100644 src/Maple.Data/Migrations/20190505105243_Initial.cs create mode 100644 src/Maple.Data/Migrations/PlaylistContextModelSnapshot.cs delete mode 100644 src/Maple.Data/Repository/Base/IMediaItemRepository.cs delete mode 100644 src/Maple.Data/Repository/Base/IMediaPlayerRepository.cs delete mode 100644 src/Maple.Data/Repository/Base/IPlaylistRepository.cs delete mode 100644 src/Maple.Data/Repository/Base/MaplePlaylistRepository.cs delete mode 100644 src/Maple.Data/Repository/MediaItemRepository.cs delete mode 100644 src/Maple.Data/Repository/MediaPlayerRepository.cs delete mode 100644 src/Maple.Data/Repository/PlaylistRepository.cs create mode 100644 src/Maple.Domain/Interfaces/IBaseListViewModel.cs create mode 100644 src/Maple.Domain/Interfaces/IEntity.cs delete mode 100644 src/Maple.Domain/Interfaces/IMapleRepository.cs create mode 100644 src/Maple.Domain/Interfaces/IMediaItemRepository.cs create mode 100644 src/Maple.Domain/Interfaces/IMediaPlayerRepository.cs create mode 100644 src/Maple.Domain/Interfaces/IPlaylistRepository.cs create mode 100644 src/Maple.Domain/Interfaces/IReadOnlyRepository.cs create mode 100644 src/Maple.Domain/Interfaces/IRepository.cs create mode 100644 src/Maple.Domain/Interfaces/IUnitOfWork.cs delete mode 100644 src/Maple.Domain/Models/RawModel.cs create mode 100644 src/Maple.Icons/Maple.Icons.csproj rename src/{Maple/UI/PackIcon.cs => Maple.Icons/MaplePackIcon.cs} (94%) rename src/{Maple.Core/Services => Maple.Log}/DetailLoggingService.cs (65%) create mode 100644 src/Maple.Log/Extensions.cs create mode 100644 src/Maple.Log/Log4NetLogger.cs create mode 100644 src/Maple.Log/Log4NetProvider.cs rename src/{Maple.Core/Services => Maple.Log}/LoggingService.cs (54%) create mode 100644 src/Maple.Log/Maple.Log.csproj delete mode 100644 src/Maple.Test/DiagnosticReportTests.cs delete mode 100644 src/Maple.Test/DynamicDictionaryTests.cs delete mode 100644 src/Maple.Test/Ensure/EnsuringCollectionNotNullOrEmptyTest.cs delete mode 100644 src/Maple.Test/Ensure/EnsuringEqualTests.cs delete mode 100644 src/Maple.Test/Ensure/EnsuringExistsTests.cs delete mode 100644 src/Maple.Test/Ensure/EnsuringNotEqualTests.cs delete mode 100644 src/Maple.Test/Ensure/EnsuringNotNullTests.cs delete mode 100644 src/Maple.Test/Ensure/EnsuringNotTests.cs delete mode 100644 src/Maple.Test/Ensure/EnsuringThatTests.cs delete mode 100644 src/Maple.Test/StringBuilderCacheTests.cs delete mode 100644 src/Maple.Test/TypeExtension/CheckingATypeForDefaultConstructorTests.cs delete mode 100644 src/Maple.Test/TypeExtension/CheckingATypeImplementsTests.cs delete mode 100644 src/Maple.Test/TypeExtension/CheckingATypeIsSimpleTests.cs delete mode 100644 src/Maple.Test/TypeExtension/CheckingIfTypeIsASequenceTests.cs delete mode 100644 src/Maple.Test/TypeExtension/CheckingTypeCodesTests.cs delete mode 100644 src/Maple.Test/TypeExtension/CheckingTypeIsNumeric.cs delete mode 100644 src/Maple.Test/TypeExtension/Context.cs delete mode 100644 src/Maple.Test/TypeExtension/GettingAllInstancePropertiesWithAttributes.cs delete mode 100644 src/Maple.Test/TypeExtension/GettingAllPropertiesWithAttributes.cs delete mode 100644 src/Maple.Test/TypeExtension/GettingArgumentTypeOfGenericTypeTests.cs delete mode 100644 src/Maple.Test/TypeExtension/GettingParentPropertiesWithAttributes.cs delete mode 100644 src/Maple.Test/TypeExtension/GettingPropertiesTests.cs delete mode 100644 src/Maple/Interfaces/IMediaRepository.cs rename src/{Maple.Core => Maple}/Services/LogNotifcationService.cs (90%) delete mode 100644 src/Maple/Services/MediaRepository.cs diff --git a/.editorconfig b/.editorconfig index 2e7f584..6dd31d9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,6 +10,7 @@ end_of_line = crlf # Dotnet code style settings: [*.{cs,vb}] +charset = utf-8 # Sort using and Import directives with System.* appearing first dotnet_sort_system_directives_first = true # Avoid "this." and "Me." if not necessary diff --git a/.gitignore b/.gitignore index 4458e3f..5db7c4f 100644 --- a/.gitignore +++ b/.gitignore @@ -226,3 +226,5 @@ ModelManifest.xml # Merge *.orig + +!Maple.Log \ No newline at end of file diff --git a/Maple.sln b/Maple.sln index a9926ba..1575b23 100644 --- a/Maple.sln +++ b/Maple.sln @@ -14,11 +14,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "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}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "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}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "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}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "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 @@ -31,7 +31,11 @@ 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 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Maple.Log", "src\Maple.Log\Maple.Log.csproj", "{8C3E9110-FFB8-4656-9A19-B763C0868278}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Maple.Icons", "src\Maple.Icons\Maple.Icons.csproj", "{1570D024-DDE5-4BBA-BC01-F47D47535B53}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -67,6 +71,14 @@ Global {9D7D05A6-8271-4836-A7BB-5B2ABECCBD81}.Debug|Any CPU.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 + {8C3E9110-FFB8-4656-9A19-B763C0868278}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8C3E9110-FFB8-4656-9A19-B763C0868278}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C3E9110-FFB8-4656-9A19-B763C0868278}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8C3E9110-FFB8-4656-9A19-B763C0868278}.Release|Any CPU.Build.0 = Release|Any CPU + {1570D024-DDE5-4BBA-BC01-F47D47535B53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1570D024-DDE5-4BBA-BC01-F47D47535B53}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1570D024-DDE5-4BBA-BC01-F47D47535B53}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1570D024-DDE5-4BBA-BC01-F47D47535B53}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Maple.Core/Commands/AsyncCommandBase.cs b/src/Maple.Core/Commands/AsyncCommandBase.cs index 7fb6fa4..16de039 100644 --- a/src/Maple.Core/Commands/AsyncCommandBase.cs +++ b/src/Maple.Core/Commands/AsyncCommandBase.cs @@ -7,6 +7,7 @@ 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) diff --git a/src/Maple.Core/Commands/Obsolete/AsyncRelayCommand.cs b/src/Maple.Core/Commands/Obsolete/AsyncRelayCommand.cs index a25020b..b50178d 100644 --- a/src/Maple.Core/Commands/Obsolete/AsyncRelayCommand.cs +++ b/src/Maple.Core/Commands/Obsolete/AsyncRelayCommand.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Threading.Tasks; using System.Windows.Input; + using Maple.Localization.Properties; namespace Maple.Core diff --git a/src/Maple.Core/Commands/RelayCommand.cs b/src/Maple.Core/Commands/RelayCommand.cs index f5e5b5d..0febc23 100644 --- a/src/Maple.Core/Commands/RelayCommand.cs +++ b/src/Maple.Core/Commands/RelayCommand.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using System.Windows.Input; + using Maple.Localization.Properties; namespace Maple.Core 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/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/MapleMessenger.cs b/src/Maple.Core/EventAggregator/MapleMessenger.cs index c00fd6c..4c78f55 100644 --- a/src/Maple.Core/EventAggregator/MapleMessenger.cs +++ b/src/Maple.Core/EventAggregator/MapleMessenger.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; + using Maple.Domain; using Maple.Localization.Properties; diff --git a/src/Maple.Core/EventAggregator/Messages/CancellableGenericMapleMessage.cs b/src/Maple.Core/EventAggregator/Messages/CancellableGenericMapleMessage.cs index e93d7b9..5d6a4d7 100644 --- a/src/Maple.Core/EventAggregator/Messages/CancellableGenericMapleMessage.cs +++ b/src/Maple.Core/EventAggregator/Messages/CancellableGenericMapleMessage.cs @@ -1,4 +1,5 @@ using System; + using Maple.Localization.Properties; namespace Maple.Core diff --git a/src/Maple.Core/EventAggregator/Messages/MapleMessageBase.cs b/src/Maple.Core/EventAggregator/Messages/MapleMessageBase.cs index b043fef..17a76e8 100644 --- a/src/Maple.Core/EventAggregator/Messages/MapleMessageBase.cs +++ b/src/Maple.Core/EventAggregator/Messages/MapleMessageBase.cs @@ -1,4 +1,5 @@ using System; + using Maple.Localization.Properties; namespace Maple.Core @@ -12,7 +13,8 @@ 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; + private readonly WeakReference _sender; + public object Sender { get diff --git a/src/Maple.Core/EventAggregator/Subscriptions/StrongMapleMessageSubscription.cs b/src/Maple.Core/EventAggregator/Subscriptions/StrongMapleMessageSubscription.cs index d8583bf..1f0e419 100644 --- a/src/Maple.Core/EventAggregator/Subscriptions/StrongMapleMessageSubscription.cs +++ b/src/Maple.Core/EventAggregator/Subscriptions/StrongMapleMessageSubscription.cs @@ -1,4 +1,5 @@ using System; + using Maple.Domain; using Maple.Localization.Properties; diff --git a/src/Maple.Core/EventAggregator/Subscriptions/WeakMapleMessageSubscription.cs b/src/Maple.Core/EventAggregator/Subscriptions/WeakMapleMessageSubscription.cs index 316d7b5..e6f94f8 100644 --- a/src/Maple.Core/EventAggregator/Subscriptions/WeakMapleMessageSubscription.cs +++ b/src/Maple.Core/EventAggregator/Subscriptions/WeakMapleMessageSubscription.cs @@ -1,4 +1,5 @@ using System; + using Maple.Domain; using Maple.Localization.Properties; 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 index fc1f532..f844744 100644 --- a/src/Maple.Core/Extensions/EventExtension.cs +++ b/src/Maple.Core/Extensions/EventExtension.cs @@ -2,16 +2,8 @@ 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 index b223f7f..f77dca1 100644 --- a/src/Maple.Core/Extensions/LinqExtensions.cs +++ b/src/Maple.Core/Extensions/LinqExtensions.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Maple.Domain; using Maple.Localization.Properties; @@ -20,7 +22,6 @@ 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(); @@ -121,5 +122,30 @@ public static void ForEach(this IRangeObservableCollection bas foreach (var item in baseCollection) action(item); } + + public static Task ForEachAsync(this IEnumerable source, Func funcBody) + { + return source.ForEachAsync(funcBody, 4); + } + + public static Task ForEachAsync(this IEnumerable source, Func funcBody, int maxDoP) + { + async Task AwaitPartition(IEnumerator partition) + { + using (partition) + { + while (partition.MoveNext()) + { + await funcBody(partition.Current).ConfigureAwait(false); + } + } + } + + return Task.WhenAll( + Partitioner + .Create(source) + .GetPartitions(maxDoP) + .Select(AwaitPartition)); + } } } 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 index 712e670..cc0c232 100644 --- a/src/Maple.Core/IO/Base/MapleFileSystemBase.cs +++ b/src/Maple.Core/IO/Base/MapleFileSystemBase.cs @@ -1,5 +1,6 @@ using System; using System.Windows.Input; + using Maple.Localization.Properties; namespace Maple.Core @@ -27,7 +28,7 @@ public static bool SearchFilter(object obj) if (string.IsNullOrWhiteSpace(info.Filter)) return true; - return info.Name.ToLowerInvariant().Contains(info.Filter.ToLowerInvariant()); + return info.Name.IndexOf(info.Filter, StringComparison.InvariantCultureIgnoreCase) >= 0; } public ICommand LoadCommand { get; protected set; } @@ -166,9 +167,13 @@ public void Load() } 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() diff --git a/src/Maple.Core/IO/Base/MapleFileSystemContainerBase.cs b/src/Maple.Core/IO/Base/MapleFileSystemContainerBase.cs index 2bb15a3..fd1dfee 100644 --- a/src/Maple.Core/IO/Base/MapleFileSystemContainerBase.cs +++ b/src/Maple.Core/IO/Base/MapleFileSystemContainerBase.cs @@ -2,6 +2,7 @@ using System.ComponentModel; using System.Linq; using System.Windows.Data; + using Maple.Domain; using Maple.Localization.Properties; diff --git a/src/Maple.Core/IO/FileSystemViewModel.cs b/src/Maple.Core/IO/FileSystemViewModel.cs index eea2689..0522695 100644 --- a/src/Maple.Core/IO/FileSystemViewModel.cs +++ b/src/Maple.Core/IO/FileSystemViewModel.cs @@ -2,6 +2,7 @@ using System.IO; using System.Linq; using System.Windows.Input; + using Maple.Domain; namespace Maple.Core diff --git a/src/Maple.Core/IO/Interfaces/IFileSystemFile.cs b/src/Maple.Core/IO/Interfaces/IFileSystemFile.cs index 6c0b687..0da7c2d 100644 --- a/src/Maple.Core/IO/Interfaces/IFileSystemFile.cs +++ b/src/Maple.Core/IO/Interfaces/IFileSystemFile.cs @@ -2,6 +2,5 @@ { public interface IFileSystemFile : IFileSystemInfo { - } } diff --git a/src/Maple.Core/IO/Interfaces/IFileSystemInfo.cs b/src/Maple.Core/IO/Interfaces/IFileSystemInfo.cs index 4cd8d98..148e2a5 100644 --- a/src/Maple.Core/IO/Interfaces/IFileSystemInfo.cs +++ b/src/Maple.Core/IO/Interfaces/IFileSystemInfo.cs @@ -9,14 +9,17 @@ 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 /// @@ -41,10 +44,12 @@ public interface IFileSystemInfo : INotifyPropertyChanged /// 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 /// @@ -52,6 +57,7 @@ public interface IFileSystemInfo : INotifyPropertyChanged void OnFilterChanged(string filter); void Delete(); + bool CanDelete(); } } diff --git a/src/Maple.Core/IO/MapleDirectory.cs b/src/Maple.Core/IO/MapleDirectory.cs index 75a5023..97e9d71 100644 --- a/src/Maple.Core/IO/MapleDirectory.cs +++ b/src/Maple.Core/IO/MapleDirectory.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using System.IO; + using Maple.Domain; namespace Maple.Core diff --git a/src/Maple.Core/IO/MapleDrive.cs b/src/Maple.Core/IO/MapleDrive.cs index e53b299..cadebd7 100644 --- a/src/Maple.Core/IO/MapleDrive.cs +++ b/src/Maple.Core/IO/MapleDrive.cs @@ -1,24 +1,13 @@ 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) { @@ -29,29 +18,14 @@ public MapleDrive(DriveInfo info, IDepth depth, IMessenger messenger, ILoggingSe } } - /// - /// 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 index 76196fb..4e2f26a 100644 --- a/src/Maple.Core/IO/MapleFile.cs +++ b/src/Maple.Core/IO/MapleFile.cs @@ -3,12 +3,6 @@ namespace Maple.Core { - /// - /// - /// - /// - /// - /// [DebuggerDisplay("File: {Name} IsContainer: {IsContainer}")] public class MapleFile : MapleFileSystemBase, IFileSystemFile { @@ -25,10 +19,6 @@ public MapleFile(FileInfo info, IDepth depth, IFileSystemDirectory parent, IMess } } - /// - /// Refreshes this instance. - /// - /// public override void Refresh() { using (BusyStack.GetToken()) @@ -37,20 +27,11 @@ public override void Refresh() } } - /// - /// 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); @@ -59,23 +40,12 @@ public override void LoadMetaData() 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/FileSystemExtensions.cs b/src/Maple.Core/IO/Util/FileSystemExtensions.cs index cc85827..77e5dd0 100644 --- a/src/Maple.Core/IO/Util/FileSystemExtensions.cs +++ b/src/Maple.Core/IO/Util/FileSystemExtensions.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Security.AccessControl; using System.Security.Permissions; + using Maple.Domain; namespace Maple.Core diff --git a/src/Maple.Core/IO/Util/SelectedTreeViewItemBehavior.cs b/src/Maple.Core/IO/Util/SelectedTreeViewItemBehavior.cs index af7d48c..44bc142 100644 --- a/src/Maple.Core/IO/Util/SelectedTreeViewItemBehavior.cs +++ b/src/Maple.Core/IO/Util/SelectedTreeViewItemBehavior.cs @@ -4,30 +4,14 @@ 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), @@ -41,10 +25,6 @@ private static void OnSelectedItemChanged(DependencyObject sender, DependencyPro item?.SetValue(TreeViewItem.IsSelectedProperty, true); } - /// - /// Called when [attached]. - /// - /// protected override void OnAttached() { base.OnAttached(); @@ -52,10 +32,6 @@ protected override void OnAttached() AssociatedObject.SelectedItemChanged += OnTreeViewSelectedItemChanged; } - /// - /// Called when [detaching]. - /// - /// protected override void OnDetaching() { base.OnDetaching(); diff --git a/src/Maple.Core/Interfaces/IConfigurableWindowSettings.cs b/src/Maple.Core/Interfaces/IConfigurableWindowSettings.cs index bf370d0..569b3f0 100644 --- a/src/Maple.Core/Interfaces/IConfigurableWindowSettings.cs +++ b/src/Maple.Core/Interfaces/IConfigurableWindowSettings.cs @@ -2,9 +2,6 @@ namespace Maple.Core { - /// - /// - /// public interface IConfigurableWindowSettings { /// diff --git a/src/Maple.Core/Interfaces/IIocFrameworkElement.cs b/src/Maple.Core/Interfaces/IIocFrameworkElement.cs index 0724ec1..34172ff 100644 --- a/src/Maple.Core/Interfaces/IIocFrameworkElement.cs +++ b/src/Maple.Core/Interfaces/IIocFrameworkElement.cs @@ -1,16 +1,7 @@ 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 index e00dcb7..4e0e3fd 100644 --- a/src/Maple.Core/Interfaces/ILoadableViewModel.cs +++ b/src/Maple.Core/Interfaces/ILoadableViewModel.cs @@ -1,20 +1,11 @@ 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; } diff --git a/src/Maple.Core/Interfaces/ILocalizationService.cs b/src/Maple.Core/Interfaces/ILocalizationService.cs index 987ad62..9c8150a 100644 --- a/src/Maple.Core/Interfaces/ILocalizationService.cs +++ b/src/Maple.Core/Interfaces/ILocalizationService.cs @@ -1,36 +1,17 @@ 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/Maple.Core.csproj b/src/Maple.Core/Maple.Core.csproj index e37cb5a..29f0110 100644 --- a/src/Maple.Core/Maple.Core.csproj +++ b/src/Maple.Core/Maple.Core.csproj @@ -1,194 +1,29 @@ - + - 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 + net471 + false + 7.1 - + + + - - - 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 - + + + ..\..\..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.1\PresentationFramework.dll + + - - \ No newline at end of file + diff --git a/src/Maple.Core/Messages/PlayingMediaItemMessage.cs b/src/Maple.Core/Messages/PlayingMediaItemMessage.cs index 08f17bd..7ec4907 100644 --- a/src/Maple.Core/Messages/PlayingMediaItemMessage.cs +++ b/src/Maple.Core/Messages/PlayingMediaItemMessage.cs @@ -5,6 +5,7 @@ namespace Maple.Core public class PlayingMediaItemMessage : GenericMapleMessage { public int PlaylistId { get; } + public PlayingMediaItemMessage(object sender, IMediaItem mediaItem, int playlistId) : base(sender, mediaItem) { diff --git a/src/Maple.Core/Observables/BusyStack.cs b/src/Maple.Core/Observables/BusyStack.cs index 02dba57..f209c0e 100644 --- a/src/Maple.Core/Observables/BusyStack.cs +++ b/src/Maple.Core/Observables/BusyStack.cs @@ -1,59 +1,24 @@ using System; using System.Collections.Concurrent; + using Maple.Localization.Properties; namespace Maple.Core { - /// - /// - /// - /// - public class BusyStack : ObservableObject + public sealed 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); } - } + private readonly ConcurrentBag _items; + private readonly Action _onChanged; - /// - /// Initializes a new instance of the class. - /// - public BusyStack() + private BusyStack() { - Items = new ConcurrentBag(); + _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}"); + _onChanged = onChanged ?? throw new ArgumentNullException(nameof(onChanged), $"{nameof(onChanged)} {Resources.IsRequired}"); } /// @@ -62,7 +27,7 @@ public BusyStack(Action onChanged) /// public bool Pull() { - var result = Items.TryTake(out BusyToken token); + var result = _items.TryTake(out var token); if (result) InvokeOnChanged(); @@ -70,34 +35,18 @@ public bool Pull() return result; } - /// - /// Adds a new to the Stack - /// - /// The token. public void Push(BusyToken token) { - Items.Add(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; + return _items.TryPeek(out var token); } - /// - /// Returns a new thats associated with instance of a - /// - /// - /// a new - /// public BusyToken GetToken() { return new BusyToken(this); @@ -105,7 +54,7 @@ public BusyToken GetToken() private void InvokeOnChanged() { - DispatcherFactory.Invoke(OnChanged, HasItems()); + DispatcherFactory.Invoke(_onChanged, HasItems()); } } } diff --git a/src/Maple.Core/Observables/BusyToken.cs b/src/Maple.Core/Observables/BusyToken.cs index f8ce9af..b9412d6 100644 --- a/src/Maple.Core/Observables/BusyToken.cs +++ b/src/Maple.Core/Observables/BusyToken.cs @@ -1,68 +1,22 @@ using System; -using System.Runtime.Serialization; namespace Maple.Core { - /// - /// - /// - /// - /// [Serializable] - public class BusyToken : WeakReference, IDisposable + public sealed 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) + 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) + public void Dispose() { - if (!Disposing) + if (Target is BusyStack stack) { - Disposing = true; - - if (Target != null) - { - var stack = Target as BusyStack; - stack?.Pull(); - } + 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 index d67ca3b..55f1b4c 100644 --- a/src/Maple.Core/Observables/ChangeTracker.cs +++ b/src/Maple.Core/Observables/ChangeTracker.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; + using Maple.Localization.Properties; namespace Maple.Core diff --git a/src/Maple.Core/Observables/NotifyTaskCompletion.cs b/src/Maple.Core/Observables/NotifyTaskCompletion.cs index cdc8650..e932beb 100644 --- a/src/Maple.Core/Observables/NotifyTaskCompletion.cs +++ b/src/Maple.Core/Observables/NotifyTaskCompletion.cs @@ -1,6 +1,7 @@ using System; using System.ComponentModel; using System.Threading.Tasks; + using Maple.Localization.Properties; namespace Maple.Core diff --git a/src/Maple.Core/Observables/RangeObservableCollection.cs b/src/Maple.Core/Observables/RangeObservableCollection.cs index ce8f7ac..1193c4b 100644 --- a/src/Maple.Core/Observables/RangeObservableCollection.cs +++ b/src/Maple.Core/Observables/RangeObservableCollection.cs @@ -6,6 +6,7 @@ using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; + using Maple.Domain; using Maple.Localization.Properties; @@ -17,10 +18,8 @@ public class RangeObservableCollection : ObservableCollection, IRangeObser private readonly BusyStack _busyStack; public RangeObservableCollection() - : base() { - _busyStack = new BusyStack(); - _busyStack.OnChanged += (updatePending) => _suppressNotification = updatePending; + _busyStack = new BusyStack(updatePending => _suppressNotification = updatePending); } public RangeObservableCollection(IEnumerable items) : this() diff --git a/src/Maple.Core/Observables/ViewModels/BaseDataListViewModel.cs b/src/Maple.Core/Observables/ViewModels/BaseDataListViewModel.cs index 0b3949d..a77446b 100644 --- a/src/Maple.Core/Observables/ViewModels/BaseDataListViewModel.cs +++ b/src/Maple.Core/Observables/ViewModels/BaseDataListViewModel.cs @@ -1,9 +1,10 @@ -using System; +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; @@ -16,7 +17,7 @@ namespace Maple.Core /// a DTO implementing /// public abstract class BaseDataListViewModel : BaseListViewModel, ILoadableViewModel - where TViewModel : BaseDataViewModel, ISequence + where TViewModel : ValidableBaseDataViewModel, ISequence where TModel : class, IBaseObject { protected readonly ISequenceService _sequenceProvider; @@ -29,21 +30,23 @@ public abstract class BaseDataListViewModel : BaseListViewMo /// /// The load command. /// - public ICommand LoadCommand => AsyncCommand.Create(LoadAsync, () => !IsLoaded); + public ICommand LoadCommand => AsyncCommand.Create(Load, () => !IsLoaded); + /// /// Gets the refresh command. /// /// /// The refresh command. /// - public ICommand RefreshCommand => AsyncCommand.Create(LoadAsync); + public ICommand RefreshCommand => AsyncCommand.Create(Load); + /// /// Gets the save command. /// /// /// The save command. /// - public ICommand SaveCommand => new RelayCommand(Save); + public ICommand SaveCommand => AsyncCommand.Create(Save, CanSave); protected BaseDataListViewModel(ViewModelServiceContainer container) : base(container.Messenger) @@ -53,24 +56,30 @@ protected BaseDataListViewModel(ViewModelServiceContainer container) _sequenceProvider = container.SequenceService; } - public abstract Task LoadAsync(); - public abstract void Save(); + public abstract Task Load(); + + public abstract Task Save(); + + protected virtual bool CanSave() + { + return !Items.Any(p => p.HasErrors); + } /// /// Removes the specified item. /// /// The item. - public override void Remove(TViewModel viewModel) + public override void Remove(TViewModel item) { - if (viewModel == null) - throw new ArgumentNullException(nameof(viewModel), $"{nameof(viewModel)} {Resources.IsRequired}"); + if (item == null) + throw new ArgumentNullException(nameof(item), $"{nameof(item)} {Resources.IsRequired}"); using (BusyStack.GetToken()) { - while (Items.Contains(viewModel)) + while (Items.Contains(item)) { - viewModel.Model.IsDeleted = true; - base.Remove(viewModel); + item.Model.IsDeleted = true; + base.Remove(item); } } } @@ -108,14 +117,13 @@ public override void RemoveRange(IList items) } } - public override void Add(TViewModel viewModel) + public override void Add(TViewModel item) { - if (viewModel == null) - throw new ArgumentNullException(nameof(viewModel), $"{nameof(viewModel)} {Resources.IsRequired}"); + if (item == null) + throw new ArgumentNullException(nameof(item), $"{nameof(item)} {Resources.IsRequired}"); - var sequence = _sequenceProvider.Get(Items.Cast().ToList()); - viewModel.Sequence = sequence; - base.Add(viewModel); + item.Sequence = _sequenceProvider.Get(Items.Cast().ToList()); + base.Add(item); } public override void AddRange(IEnumerable items) diff --git a/src/Maple.Core/Observables/ViewModels/BaseDataViewModel.cs b/src/Maple.Core/Observables/ViewModels/BaseDataViewModel.cs index b3fbbd4..a735208 100644 --- a/src/Maple.Core/Observables/ViewModels/BaseDataViewModel.cs +++ b/src/Maple.Core/Observables/ViewModels/BaseDataViewModel.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.CompilerServices; + using Maple.Domain; namespace Maple.Core diff --git a/src/Maple.Core/Observables/ViewModels/BaseListViewModel.cs b/src/Maple.Core/Observables/ViewModels/BaseListViewModel.cs index f6f54aa..6fe7ae4 100644 --- a/src/Maple.Core/Observables/ViewModels/BaseListViewModel.cs +++ b/src/Maple.Core/Observables/ViewModels/BaseListViewModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; @@ -7,6 +7,7 @@ using System.Linq; using System.Windows.Data; using System.Windows.Input; + using Maple.Domain; namespace Maple.Core @@ -16,7 +17,7 @@ namespace Maple.Core /// /// a class implementing /// - public abstract class BaseListViewModel : ViewModel + public abstract class BaseListViewModel : ViewModel, IBaseListViewModel where TViewModel : INotifyPropertyChanged { protected readonly object _itemsLock; @@ -44,9 +45,6 @@ public virtual TViewModel SelectedItem } 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 { @@ -55,12 +53,6 @@ public IReadOnlyCollection Items } private ICollectionView _view; - /// - /// For grouping, sorting and filtering - /// - /// - /// The view. - /// public ICollectionView View { get { return _view; } @@ -68,14 +60,7 @@ public ICollectionView View } public int Count => Items?.Count ?? 0; - /// - /// Gets the at the specified index. - /// - /// - /// The . - /// - /// The index. - /// + public TViewModel this[int index] { get { return _items[index]; } @@ -91,7 +76,6 @@ protected BaseListViewModel(IMessenger messenger) { _itemsLock = new object(); - Items = new RangeObservableCollection(); _items.CollectionChanged += ItemsCollectionChanged; @@ -135,11 +119,6 @@ protected virtual void OnLoaded() Messenger.Publish(new LoadedMessage(this, this)); } - /// - /// Adds the specified item. - /// - /// The item. - /// item public virtual void Add(TViewModel item) { if (item == null) @@ -149,8 +128,6 @@ public virtual void Add(TViewModel item) _items.Add(item); } - /// The items. - /// items public virtual void AddRange(IEnumerable items) { if (items == null) @@ -165,18 +142,12 @@ 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) @@ -186,8 +157,6 @@ public virtual void RemoveRange(IEnumerable items) _items.RemoveRange(items); } - /// The items. - /// items public virtual void RemoveRange(IList items) { if (items == null) @@ -197,37 +166,16 @@ public virtual void RemoveRange(IList items) _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)); + return CanClear() && items?.Any(p => Items.Contains(p)) == true; } - /// - /// 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()); diff --git a/src/Maple.Core/Observables/ViewModels/ValidableBaseDataViewModel.cs b/src/Maple.Core/Observables/ViewModels/ValidableBaseDataViewModel.cs index 9cd4649..b7f8791 100644 --- a/src/Maple.Core/Observables/ViewModels/ValidableBaseDataViewModel.cs +++ b/src/Maple.Core/Observables/ViewModels/ValidableBaseDataViewModel.cs @@ -5,8 +5,10 @@ using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; + using FluentValidation; using FluentValidation.Results; + using Maple.Domain; using Maple.Localization.Properties; diff --git a/src/Maple.Core/Observables/ViewModels/ViewModel.cs b/src/Maple.Core/Observables/ViewModels/ViewModel.cs index cc473f4..0c214f5 100644 --- a/src/Maple.Core/Observables/ViewModels/ViewModel.cs +++ b/src/Maple.Core/Observables/ViewModels/ViewModel.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; + using Maple.Localization.Properties; namespace Maple.Core @@ -8,7 +9,6 @@ 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; } @@ -21,8 +21,7 @@ public bool IsBusy protected ViewModel(IMessenger messenger) { - BusyStack = new BusyStack(); - BusyStack.OnChanged += (isBusy) => IsBusy = isBusy; + BusyStack = new BusyStack(isBusy => IsBusy = isBusy); MessageTokens = new List(); Messenger = messenger ?? throw new ArgumentNullException(nameof(messenger), $"{nameof(messenger)} {Resources.IsRequired}"); 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/Services/Localization/LocalizationDTO.cs b/src/Maple.Core/Services/Localization/LocalizationDTO.cs index 6e762f7..8584666 100644 --- a/src/Maple.Core/Services/Localization/LocalizationDTO.cs +++ b/src/Maple.Core/Services/Localization/LocalizationDTO.cs @@ -12,7 +12,7 @@ namespace Maple.Core /// /// /// - public class LocalizationDTO : ObservableObject, INotifyPropertyChanged, IDisposable + public class LocalizationDTO : ObservableObject, IDisposable { private readonly string _key; private readonly ILocalizationService _service; diff --git a/src/Maple.Core/Services/Localization/LocalizationService.cs b/src/Maple.Core/Services/Localization/LocalizationService.cs index 36bd82b..add5716 100644 --- a/src/Maple.Core/Services/Localization/LocalizationService.cs +++ b/src/Maple.Core/Services/Localization/LocalizationService.cs @@ -4,15 +4,16 @@ 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 sealed class LocalizationService : ObservableObject, ILocalizationService { - public ITranslationProvider TranslationProvider { get; private set; } public readonly ILoggingService _log; + public ITranslationProvider TranslationProvider { get; } private CultureInfo _currentLanguage; public CultureInfo CurrentLanguage @@ -54,27 +55,19 @@ public string Translate(string key) return $"!{key}!"; } - public void Save() + public Task Save() { Properties.Settings.Default.StartUpCulture = CurrentLanguage; Properties.Settings.Default.Save(); + + return Task.CompletedTask; } - public void Load() + public Task 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 index dd375a8..2815496 100644 --- a/src/Maple.Core/Services/Localization/Providers/ResxTranslationProvider.cs +++ b/src/Maple.Core/Services/Localization/Providers/ResxTranslationProvider.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Globalization; using System.Resources; + using Maple.Domain; namespace Maple.Core diff --git a/src/Maple.Core/Services/MrlExtractionService.cs b/src/Maple.Core/Services/MrlExtractionService.cs index 630b572..fec75a3 100644 --- a/src/Maple.Core/Services/MrlExtractionService.cs +++ b/src/Maple.Core/Services/MrlExtractionService.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; + using YoutubeExtractor; namespace Maple.Core diff --git a/src/Maple.Core/Services/SequenceService.cs b/src/Maple.Core/Services/SequenceService.cs index ea6998e..b0437e5 100644 --- a/src/Maple.Core/Services/SequenceService.cs +++ b/src/Maple.Core/Services/SequenceService.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; using System.Linq; + using Maple.Domain; using Maple.Localization.Properties; namespace Maple.Core { - public class SequenceService : ISequenceService + public sealed class SequenceService : ISequenceService { private readonly ILoggingService _log; diff --git a/src/Maple.Core/Services/ViewModelServiceContainer.cs b/src/Maple.Core/Services/ViewModelServiceContainer.cs index 8612b20..acf12cd 100644 --- a/src/Maple.Core/Services/ViewModelServiceContainer.cs +++ b/src/Maple.Core/Services/ViewModelServiceContainer.cs @@ -1,4 +1,5 @@ using System; + using Maple.Domain; using Maple.Localization.Properties; 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 index 486c484..8506ad2 100644 --- a/src/Maple.Core/app.config +++ b/src/Maple.Core/app.config @@ -2,45 +2,44 @@ -
+
-
+
- - - + + - - + + - - + + - - + + - + - + - + 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/Constants.cs b/src/Maple.Data/Constants.cs new file mode 100644 index 0000000..96ada43 --- /dev/null +++ b/src/Maple.Data/Constants.cs @@ -0,0 +1,7 @@ +namespace Maple.Data +{ + public static class Constants + { + public const string ConnectionString = "Data Source=../maple.db;"; + } +} diff --git a/src/Maple.Data/DB/Configurations/MediaItemConfiguration.cs b/src/Maple.Data/DB/Configurations/MediaItemConfiguration.cs new file mode 100644 index 0000000..aa97137 --- /dev/null +++ b/src/Maple.Data/DB/Configurations/MediaItemConfiguration.cs @@ -0,0 +1,41 @@ +using Maple.Domain; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Maple.Data +{ + public sealed class MediaItemConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.Property(t => t.Title) + .IsRequired() + .HasMaxLength(50); + + builder.Property(t => t.Location) + .IsRequired() + .HasMaxLength(2048); + + builder.HasKey(t => t.Id); + + builder.HasOne(t => t.Playlist) + .WithMany(t => t.MediaItems) + .IsRequired() + .OnDelete(DeleteBehavior.Cascade); + + 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"); + } + } +} diff --git a/src/Maple.Data/DB/Configurations/MediaPlayerConfiguration.cs b/src/Maple.Data/DB/Configurations/MediaPlayerConfiguration.cs new file mode 100644 index 0000000..272db39 --- /dev/null +++ b/src/Maple.Data/DB/Configurations/MediaPlayerConfiguration.cs @@ -0,0 +1,40 @@ +using Maple.Domain; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Maple.Data +{ + public sealed class MediaPlayerConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.Property(t => t.Name) + .IsRequired() + .HasMaxLength(50); + + builder.Property(t => t.DeviceName) + .HasMaxLength(100); + + builder.HasKey(t => t.Id); + + 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.HasOne(t => t.Playlist) + .WithOne(t => t.MediaPlayer) + .HasForeignKey(t => t.PlaylistId) + .IsRequired(false); + } + } +} diff --git a/src/Maple.Data/DB/Configurations/OptionConfiguration.cs b/src/Maple.Data/DB/Configurations/OptionConfiguration.cs new file mode 100644 index 0000000..f73958a --- /dev/null +++ b/src/Maple.Data/DB/Configurations/OptionConfiguration.cs @@ -0,0 +1,31 @@ +using Maple.Domain; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Maple.Data +{ + public sealed class OptionConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.Property(t => t.Key) + .IsRequired(); + + builder.HasKey(t => t.Id); + + 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"); + } + } +} diff --git a/src/Maple.Data/DB/Configurations/PlaylistConfiguration.cs b/src/Maple.Data/DB/Configurations/PlaylistConfiguration.cs new file mode 100644 index 0000000..edf9ee6 --- /dev/null +++ b/src/Maple.Data/DB/Configurations/PlaylistConfiguration.cs @@ -0,0 +1,40 @@ +using Maple.Domain; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Maple.Data +{ + public sealed class PlaylistConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.Property(t => t.Title) + .IsRequired() + .HasMaxLength(50); + + builder.Property(t => t.Description) + .HasMaxLength(100); + + builder.HasKey(t => t.Id); + + 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.HasOne(t => t.MediaPlayer) + .WithOne(t => t.Playlist) + .HasForeignKey(t => t.MediaPlayerId) + .IsRequired(false); + } + } +} 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/MapleUnitOfWork.cs b/src/Maple.Data/DB/MapleUnitOfWork.cs new file mode 100644 index 0000000..7c8822d --- /dev/null +++ b/src/Maple.Data/DB/MapleUnitOfWork.cs @@ -0,0 +1,34 @@ +using Maple.Domain; +using Microsoft.Extensions.Logging; + +namespace Maple.Data +{ + public sealed class MapleUnitOfWork : UnitOfWork, IUnitOfWork + { + private readonly bool _shouldDispose; + + public IMediaItemRepository MediaItemRepository { get; } + public IMediaPlayerRepository MediaPlayerRepository { get; } + public IPlaylistRepository PlaylistRepository { get; } + + public MapleUnitOfWork(ILoggerFactory loggerFactory) + : this(new PlaylistContext(loggerFactory)) + { + _shouldDispose = true; + } + + internal MapleUnitOfWork(PlaylistContext context) + : base(context) + { + MediaItemRepository = new MediaItemRepository(this); + MediaPlayerRepository = new MediaPlayerRepository(this); + PlaylistRepository = new PlaylistRepository(this); + } + + public override void Dispose() + { + if (_shouldDispose) + Context.Dispose(); + } + } +} 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 index c5425f2..cfab314 100644 --- a/src/Maple.Data/DB/PlaylistContext.cs +++ b/src/Maple.Data/DB/PlaylistContext.cs @@ -1,32 +1,58 @@ -using System.Data.Entity; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; using Maple.Domain; +using Maple.Log; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; namespace Maple.Data { - public class PlaylistContext : DbContext + public sealed class PlaylistContext : DbContext { + private readonly ILoggerFactory _loggerFactory; + 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") + public PlaylistContext(ILoggerFactory loggerFactory) { - Configuration.ProxyCreationEnabled = false; - Configuration.LazyLoadingEnabled = false; + _loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); } - protected override void OnModelCreating(DbModelBuilder modelBuilder) + internal PlaylistContext(DbContextOptions options, ILoggerFactory loggerFactory) + : base(options) { - ModelConfiguration.Configure(modelBuilder); - Database.SetInitializer(new CreateSeedDatabaseIfNotExists(modelBuilder)); + _loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); + } + + public Task Migrate() + { + return Database.MigrateAsync(); + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (optionsBuilder.IsConfigured) + return; + + _loggerFactory.AddLog4Net(); + + optionsBuilder + .EnableSensitiveDataLogging(true) + .UseLoggerFactory(_loggerFactory) + .UseSqlite(Constants.ConnectionString) + .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); } - protected override void Dispose(bool disposing) + protected override void OnModelCreating(ModelBuilder modelBuilder) { - base.Dispose(disposing); + modelBuilder.ApplyConfiguration(new MediaPlayerConfiguration()); + modelBuilder.ApplyConfiguration(new MediaItemConfiguration()); + modelBuilder.ApplyConfiguration(new PlaylistConfiguration()); + modelBuilder.ApplyConfiguration(new OptionConfiguration()); } } } diff --git a/src/Maple.Data/DB/Repository/Base/ReadOnlyRepository.cs b/src/Maple.Data/DB/Repository/Base/ReadOnlyRepository.cs new file mode 100644 index 0000000..a0915a5 --- /dev/null +++ b/src/Maple.Data/DB/Repository/Base/ReadOnlyRepository.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; + +using Maple.Domain; + +using Microsoft.EntityFrameworkCore; + +namespace Maple.Data +{ + public abstract class ReadOnlyRepository : IReadOnlyRepository + where TEntity : class, IEntity + { + protected readonly DbSet Set; + protected readonly string Name; + + protected ReadOnlyRepository(IUnitOfWork unitOfWork) + { + if (unitOfWork is UnitOfWork uow) + { + Set = uow.Context.Set(); + uow.Context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; + } + else + throw new ArgumentException(nameof(unitOfWork) + " is not derived from " + typeof(UnitOfWork).FullName); + + Name = GetType().Name; + } + + public TEntity Read(TKey key) + { + return Set.Find(key); + } + + public Task ReadAsync(TKey key) + { + return Set.FindAsync(key); + } + + public ICollection Read(Expression> filter, string[] propertyNames, int index, int count) + { + return ReadInternal(Set, filter, propertyNames, index, count) + .ToList() + .AsReadOnly(); + } + + public async Task> ReadAsync(Expression> filter, string[] propertyNames, int index, int count) + { + var result = await ReadInternal(Set, filter, propertyNames, index, count) + .ToListAsync() + .ConfigureAwait(false); + + return result.AsReadOnly(); + } + + private static IQueryable ReadInternal(IQueryable query, Expression> filter, string[] propertyNames, int index, int count) + { + if (!(propertyNames is null)) + { + for (var i = 0; i < propertyNames.Length; i++) + { + var name = propertyNames[i]; + if (!string.IsNullOrEmpty(name)) + query = query.Include(name); + else + throw new ArgumentException(nameof(propertyNames) + " contains an empty PropertyName."); + } + } + + if (!(filter is null)) + query = query.Where(filter); + + query = query.OrderBy(p => p.Id); + + if (index > 0) + query = query.Skip(index); + + if (count > 0) + query = query.Take(count); + + return query; + } + } +} diff --git a/src/Maple.Data/DB/Repository/Base/Repository.cs b/src/Maple.Data/DB/Repository/Base/Repository.cs new file mode 100644 index 0000000..72d56c6 --- /dev/null +++ b/src/Maple.Data/DB/Repository/Base/Repository.cs @@ -0,0 +1,42 @@ +using Maple.Domain; + +namespace Maple.Data +{ + public abstract class Repository : ReadOnlyRepository, IRepository + where TEntity : class, IEntity + { + protected Repository(IUnitOfWork unitOfWork) + : base(unitOfWork) + { + } + + public void Create(TEntity entity) + { + Set.Add(entity); + } + + public void Delete(TEntity entity) + { + Set.Remove(entity); + } + + public void Update(TEntity entity) + { + if (entity.IsNew) + { + Create(entity); + } + else + { + if (entity.IsDeleted) + { + Delete(entity); + } + else + { + Set.Update(entity); + } + } + } + } +} diff --git a/src/Maple.Data/DB/Repository/Base/UnitOfWork.cs b/src/Maple.Data/DB/Repository/Base/UnitOfWork.cs new file mode 100644 index 0000000..9aef8be --- /dev/null +++ b/src/Maple.Data/DB/Repository/Base/UnitOfWork.cs @@ -0,0 +1,23 @@ +using System; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; + +namespace Maple.Data +{ + public abstract class UnitOfWork + { + internal DbContext Context { get; } + + protected UnitOfWork(DbContext context) + { + Context = context ?? throw new ArgumentNullException(nameof(context)); + } + + public abstract void Dispose(); + + public Task SaveChanges() + { + return Context.SaveChangesAsync(); + } + } +} diff --git a/src/Maple.Data/DB/Repository/MediaItemRepository.cs b/src/Maple.Data/DB/Repository/MediaItemRepository.cs new file mode 100644 index 0000000..a65a4c0 --- /dev/null +++ b/src/Maple.Data/DB/Repository/MediaItemRepository.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +using Maple.Domain; + +namespace Maple.Data +{ + public sealed class MediaItemRepository : Repository, IMediaItemRepository + { + public MediaItemRepository(IUnitOfWork unitOfWork) + : base(unitOfWork) + { + } + + public async Task GetMediaItemByPlaylistIdAsync(int id) + { + var result = await ReadAsync(p => p.PlaylistId.Equals(id), new[] { nameof(MediaItemModel.Playlist) }, -1, 1).ConfigureAwait(false); + + return result.First(); + } + + public Task> ReadAsync() + { + return ReadAsync(null, new[] { nameof(MediaItemModel.Playlist) }, -1, -1); + } + } +} diff --git a/src/Maple.Data/DB/Repository/MediaPlayerRepository.cs b/src/Maple.Data/DB/Repository/MediaPlayerRepository.cs new file mode 100644 index 0000000..97d23ea --- /dev/null +++ b/src/Maple.Data/DB/Repository/MediaPlayerRepository.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +using Maple.Domain; + +namespace Maple.Data +{ + public sealed class MediaPlayerRepository : Repository, IMediaPlayerRepository + { + public MediaPlayerRepository(IUnitOfWork unitOfWork) + : base(unitOfWork) + { + } + + public async Task GetMainMediaPlayerAsync() + { + var result = await ReadAsync(p => p.IsPrimary, new[] { nameof(MediaPlayerModel.Playlist) }, -1, 1).ConfigureAwait(false); + return result.FirstOrDefault(); + } + + public Task> GetOptionalMediaPlayersAsync() + { + return ReadAsync(p => !p.IsPrimary, new[] { nameof(MediaPlayerModel.Playlist) }, -1, -1); + } + } +} diff --git a/src/Maple.Data/DB/Repository/PlaylistRepository.cs b/src/Maple.Data/DB/Repository/PlaylistRepository.cs new file mode 100644 index 0000000..473f191 --- /dev/null +++ b/src/Maple.Data/DB/Repository/PlaylistRepository.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Maple.Domain; + +namespace Maple.Data +{ + public sealed class PlaylistRepository : Repository, IPlaylistRepository + { + public PlaylistRepository(IUnitOfWork unitOfWork) + : base(unitOfWork) + { + } + + public Task> ReadAsync() + { + return ReadAsync(null, new[] { nameof(PlaylistModel.MediaItems) }, -1, -1); + } + } +} diff --git a/src/Maple.Data/DesignTimeDbContextFactory.cs b/src/Maple.Data/DesignTimeDbContextFactory.cs new file mode 100644 index 0000000..61748c5 --- /dev/null +++ b/src/Maple.Data/DesignTimeDbContextFactory.cs @@ -0,0 +1,21 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace Maple.Data +{ + public sealed class DesignTimeDbContextFactory : IDesignTimeDbContextFactory + { + public PlaylistContext CreateDbContext(string[] args) + { + var configuration = new ConfigurationBuilder() + .Build(); + + var builder = new DbContextOptionsBuilder() + .UseSqlite(Constants.ConnectionString); + + return new PlaylistContext(builder.Options, new LoggerFactory()); + } + } +} diff --git a/src/Maple.Data/Maple.Data.csproj b/src/Maple.Data/Maple.Data.csproj index bea4727..7505833 100644 --- a/src/Maple.Data/Maple.Data.csproj +++ b/src/Maple.Data/Maple.Data.csproj @@ -1,112 +1,22 @@ - - + - 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 - - - + net471 + false + 7.1 - - 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 - + + + + all + runtime; build; native; contentfiles; analyzers + - - {9d7d05a6-8271-4836-a7bb-5b2abeccbd81} - Maple.Domain - + + - - \ No newline at end of file + diff --git a/src/Maple.Data/Migrations/20190505105243_Initial.Designer.cs b/src/Maple.Data/Migrations/20190505105243_Initial.Designer.cs new file mode 100644 index 0000000..fd77cfa --- /dev/null +++ b/src/Maple.Data/Migrations/20190505105243_Initial.Designer.cs @@ -0,0 +1,208 @@ +// +using System; +using Maple.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Maple.Data.Migrations +{ + [DbContext(typeof(PlaylistContext))] + [Migration("20190505105243_Initial")] + partial class Initial + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.1.4-rtm-31024"); + + modelBuilder.Entity("Maple.Domain.MediaItemModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CreatedBy") + .ValueGeneratedOnAdd() + .HasDefaultValue("SYSTEM"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Description"); + + b.Property("Duration"); + + b.Property("Location") + .IsRequired() + .HasMaxLength(2048); + + b.Property("MediaItemType"); + + b.Property("PlaylistId"); + + b.Property("PrivacyStatus"); + + b.Property("Sequence"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(50); + + b.Property("UpdatedBy") + .ValueGeneratedOnAdd() + .HasDefaultValue("SYSTEM"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAddOrUpdate() + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id"); + + b.HasIndex("PlaylistId"); + + b.ToTable("MediaItems"); + }); + + modelBuilder.Entity("Maple.Domain.MediaPlayerModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CreatedBy") + .ValueGeneratedOnAdd() + .HasDefaultValue("SYSTEM"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("DeviceName") + .HasMaxLength(100); + + b.Property("IsPrimary"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50); + + b.Property("PlaylistId"); + + b.Property("Sequence"); + + b.Property("UpdatedBy") + .ValueGeneratedOnAdd() + .HasDefaultValue("SYSTEM"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAddOrUpdate() + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id"); + + b.ToTable("Mediaplayers"); + }); + + modelBuilder.Entity("Maple.Domain.OptionModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CreatedBy") + .ValueGeneratedOnAdd() + .HasDefaultValue("SYSTEM"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Key") + .IsRequired(); + + b.Property("Sequence"); + + b.Property("Type"); + + b.Property("UpdatedBy") + .ValueGeneratedOnAdd() + .HasDefaultValue("SYSTEM"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAddOrUpdate() + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Value"); + + b.HasKey("Id"); + + b.ToTable("Options"); + }); + + modelBuilder.Entity("Maple.Domain.PlaylistModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CreatedBy") + .ValueGeneratedOnAdd() + .HasDefaultValue("SYSTEM"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Description") + .HasMaxLength(100); + + b.Property("IsShuffeling"); + + b.Property("Location"); + + b.Property("MediaPlayerId"); + + b.Property("PrivacyStatus"); + + b.Property("RepeatMode"); + + b.Property("Sequence"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(50); + + b.Property("UpdatedBy") + .ValueGeneratedOnAdd() + .HasDefaultValue("SYSTEM"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAddOrUpdate() + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id"); + + b.HasIndex("MediaPlayerId") + .IsUnique(); + + b.ToTable("Playlists"); + }); + + modelBuilder.Entity("Maple.Domain.MediaItemModel", b => + { + b.HasOne("Maple.Domain.PlaylistModel", "Playlist") + .WithMany("MediaItems") + .HasForeignKey("PlaylistId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Maple.Domain.PlaylistModel", b => + { + b.HasOne("Maple.Domain.MediaPlayerModel", "MediaPlayer") + .WithOne("Playlist") + .HasForeignKey("Maple.Domain.PlaylistModel", "MediaPlayerId"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Maple.Data/Migrations/20190505105243_Initial.cs b/src/Maple.Data/Migrations/20190505105243_Initial.cs new file mode 100644 index 0000000..01bacf6 --- /dev/null +++ b/src/Maple.Data/Migrations/20190505105243_Initial.cs @@ -0,0 +1,138 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Maple.Data.Migrations +{ + public partial class Initial : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Mediaplayers", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Sequence = table.Column(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"), + PlaylistId = table.Column(nullable: true), + DeviceName = table.Column(maxLength: 100, nullable: true), + IsPrimary = table.Column(nullable: false), + Name = table.Column(maxLength: 50, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Mediaplayers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Options", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Sequence = table.Column(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"), + Value = table.Column(nullable: true), + Type = table.Column(nullable: false), + Key = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Options", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Playlists", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Sequence = table.Column(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"), + Description = table.Column(maxLength: 100, nullable: true), + Location = table.Column(nullable: true), + IsShuffeling = table.Column(nullable: false), + PrivacyStatus = table.Column(nullable: false), + RepeatMode = table.Column(nullable: false), + MediaPlayerId = table.Column(nullable: true), + Title = table.Column(maxLength: 50, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Playlists", x => x.Id); + table.ForeignKey( + name: "FK_Playlists_Mediaplayers_MediaPlayerId", + column: x => x.MediaPlayerId, + principalTable: "Mediaplayers", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "MediaItems", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Sequence = table.Column(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"), + PlaylistId = table.Column(nullable: false), + Duration = table.Column(nullable: false), + PrivacyStatus = table.Column(nullable: false), + MediaItemType = table.Column(nullable: false), + Description = table.Column(nullable: true), + Title = table.Column(maxLength: 50, nullable: false), + Location = table.Column(maxLength: 2048, 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.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_MediaItems_PlaylistId", + table: "MediaItems", + column: "PlaylistId"); + + migrationBuilder.CreateIndex( + name: "IX_Playlists_MediaPlayerId", + table: "Playlists", + column: "MediaPlayerId", + unique: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "MediaItems"); + + migrationBuilder.DropTable( + name: "Options"); + + migrationBuilder.DropTable( + name: "Playlists"); + + migrationBuilder.DropTable( + name: "Mediaplayers"); + } + } +} diff --git a/src/Maple.Data/Migrations/PlaylistContextModelSnapshot.cs b/src/Maple.Data/Migrations/PlaylistContextModelSnapshot.cs new file mode 100644 index 0000000..a149e42 --- /dev/null +++ b/src/Maple.Data/Migrations/PlaylistContextModelSnapshot.cs @@ -0,0 +1,206 @@ +// +using System; +using Maple.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Maple.Data.Migrations +{ + [DbContext(typeof(PlaylistContext))] + partial class PlaylistContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.1.4-rtm-31024"); + + modelBuilder.Entity("Maple.Domain.MediaItemModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CreatedBy") + .ValueGeneratedOnAdd() + .HasDefaultValue("SYSTEM"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Description"); + + b.Property("Duration"); + + b.Property("Location") + .IsRequired() + .HasMaxLength(2048); + + b.Property("MediaItemType"); + + b.Property("PlaylistId"); + + b.Property("PrivacyStatus"); + + b.Property("Sequence"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(50); + + b.Property("UpdatedBy") + .ValueGeneratedOnAdd() + .HasDefaultValue("SYSTEM"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAddOrUpdate() + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id"); + + b.HasIndex("PlaylistId"); + + b.ToTable("MediaItems"); + }); + + modelBuilder.Entity("Maple.Domain.MediaPlayerModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CreatedBy") + .ValueGeneratedOnAdd() + .HasDefaultValue("SYSTEM"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("DeviceName") + .HasMaxLength(100); + + b.Property("IsPrimary"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50); + + b.Property("PlaylistId"); + + b.Property("Sequence"); + + b.Property("UpdatedBy") + .ValueGeneratedOnAdd() + .HasDefaultValue("SYSTEM"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAddOrUpdate() + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id"); + + b.ToTable("Mediaplayers"); + }); + + modelBuilder.Entity("Maple.Domain.OptionModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CreatedBy") + .ValueGeneratedOnAdd() + .HasDefaultValue("SYSTEM"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Key") + .IsRequired(); + + b.Property("Sequence"); + + b.Property("Type"); + + b.Property("UpdatedBy") + .ValueGeneratedOnAdd() + .HasDefaultValue("SYSTEM"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAddOrUpdate() + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Value"); + + b.HasKey("Id"); + + b.ToTable("Options"); + }); + + modelBuilder.Entity("Maple.Domain.PlaylistModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CreatedBy") + .ValueGeneratedOnAdd() + .HasDefaultValue("SYSTEM"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Description") + .HasMaxLength(100); + + b.Property("IsShuffeling"); + + b.Property("Location"); + + b.Property("MediaPlayerId"); + + b.Property("PrivacyStatus"); + + b.Property("RepeatMode"); + + b.Property("Sequence"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(50); + + b.Property("UpdatedBy") + .ValueGeneratedOnAdd() + .HasDefaultValue("SYSTEM"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAddOrUpdate() + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id"); + + b.HasIndex("MediaPlayerId") + .IsUnique(); + + b.ToTable("Playlists"); + }); + + modelBuilder.Entity("Maple.Domain.MediaItemModel", b => + { + b.HasOne("Maple.Domain.PlaylistModel", "Playlist") + .WithMany("MediaItems") + .HasForeignKey("PlaylistId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Maple.Domain.PlaylistModel", b => + { + b.HasOne("Maple.Domain.MediaPlayerModel", "MediaPlayer") + .WithOne("Playlist") + .HasForeignKey("Maple.Domain.PlaylistModel", "MediaPlayerId"); + }); +#pragma warning restore 612, 618 + } + } +} 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/Interfaces/IAudioDevice.cs b/src/Maple.Domain/Interfaces/IAudioDevice.cs index 10ca374..878abdf 100644 --- a/src/Maple.Domain/Interfaces/IAudioDevice.cs +++ b/src/Maple.Domain/Interfaces/IAudioDevice.cs @@ -11,4 +11,4 @@ public interface IAudioDevice : INotifyPropertyChanged string ToString(); } -} \ No newline at end of file +} diff --git a/src/Maple.Domain/Interfaces/IBaseListViewModel.cs b/src/Maple.Domain/Interfaces/IBaseListViewModel.cs new file mode 100644 index 0000000..8d14fdb --- /dev/null +++ b/src/Maple.Domain/Interfaces/IBaseListViewModel.cs @@ -0,0 +1,40 @@ +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Windows.Input; + +namespace Maple.Domain +{ + public interface IBaseListViewModel where TViewModel : INotifyPropertyChanged + { + TViewModel this[int index] { get; } + + ICommand AddCommand { get; } + ICommand ClearCommand { get; } + int Count { get; } + IReadOnlyCollection Items { get; } + ICommand RemoveCommand { get; } + ICommand RemoveRangeCommand { get; } + TViewModel SelectedItem { get; set; } + + void Add(TViewModel item); + + void AddRange(IEnumerable items); + + bool CanClear(); + + bool CanRemove(TViewModel item); + + bool CanRemoveRange(IEnumerable items); + + bool CanRemoveRange(IList items); + + void Clear(); + + void Remove(TViewModel item); + + void RemoveRange(IEnumerable items); + + void RemoveRange(IList items); + } +} diff --git a/src/Maple.Domain/Interfaces/IBaseObject.cs b/src/Maple.Domain/Interfaces/IBaseObject.cs index c1740cb..5d808f4 100644 --- a/src/Maple.Domain/Interfaces/IBaseObject.cs +++ b/src/Maple.Domain/Interfaces/IBaseObject.cs @@ -6,12 +6,11 @@ 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 index bc36a0f..b739497 100644 --- a/src/Maple.Domain/Interfaces/IChangeState.cs +++ b/src/Maple.Domain/Interfaces/IChangeState.cs @@ -9,6 +9,7 @@ public interface IChangeState /// true if this instance is new; otherwise, false. /// bool IsNew { get; } + /// /// Gets a value indicating whether this instance is deleted. /// diff --git a/src/Maple.Domain/Interfaces/IEntity.cs b/src/Maple.Domain/Interfaces/IEntity.cs new file mode 100644 index 0000000..d495c19 --- /dev/null +++ b/src/Maple.Domain/Interfaces/IEntity.cs @@ -0,0 +1,7 @@ +namespace Maple.Domain +{ + public interface IEntity : IBaseObject + { + TKey Id { get; } + } +} diff --git a/src/Maple.Domain/Interfaces/ILoggingNotifcationService.cs b/src/Maple.Domain/Interfaces/ILoggingNotifcationService.cs index 806f4b0..e59b734 100644 --- a/src/Maple.Domain/Interfaces/ILoggingNotifcationService.cs +++ b/src/Maple.Domain/Interfaces/ILoggingNotifcationService.cs @@ -9,8 +9,11 @@ namespace Maple.Domain 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 index d5d3c25..a0c445e 100644 --- a/src/Maple.Domain/Interfaces/ILoggingService.cs +++ b/src/Maple.Domain/Interfaces/ILoggingService.cs @@ -27,6 +27,7 @@ public interface ILoggingService ///
/// The message. void Error(object message); + // // Summary: // Log a message object with the log4net.Core.Level.Error level including the stack @@ -71,6 +72,7 @@ public interface ILoggingService /// /// The message. void Fatal(object message); + // // Summary: // Log a message object with the log4net.Core.Level.Fatal level including the stack @@ -115,6 +117,7 @@ public interface ILoggingService /// /// The message. void Info(object message); + // // Summary: // Logs a message object with the INFO level including the stack trace of the System.Exception @@ -159,6 +162,7 @@ public interface ILoggingService /// /// The message. void Warn(object message); + // // Summary: // Log a message object with the log4net.Core.Level.Warn level including the stack 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/IMediaItemRepository.cs b/src/Maple.Domain/Interfaces/IMediaItemRepository.cs new file mode 100644 index 0000000..7f1c285 --- /dev/null +++ b/src/Maple.Domain/Interfaces/IMediaItemRepository.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Maple.Domain +{ + public interface IMediaItemRepository : IRepository + { + Task GetMediaItemByPlaylistIdAsync(int id); + + Task> ReadAsync(); + } +} diff --git a/src/Maple.Domain/Interfaces/IMediaPlayer.cs b/src/Maple.Domain/Interfaces/IMediaPlayer.cs index 69eb616..f067aee 100644 --- a/src/Maple.Domain/Interfaces/IMediaPlayer.cs +++ b/src/Maple.Domain/Interfaces/IMediaPlayer.cs @@ -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,6 +76,7 @@ public interface IMediaPlayer : IDisposable /// The volume minimum. /// int VolumeMin { get; } + /// /// Gets or sets the audio device. /// diff --git a/src/Maple.Domain/Interfaces/IMediaPlayerRepository.cs b/src/Maple.Domain/Interfaces/IMediaPlayerRepository.cs new file mode 100644 index 0000000..43c3774 --- /dev/null +++ b/src/Maple.Domain/Interfaces/IMediaPlayerRepository.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Maple.Domain +{ + public interface IMediaPlayerRepository : IRepository + { + Task GetMainMediaPlayerAsync(); + + Task> GetOptionalMediaPlayersAsync(); + } +} diff --git a/src/Maple.Domain/Interfaces/IPlaylistRepository.cs b/src/Maple.Domain/Interfaces/IPlaylistRepository.cs new file mode 100644 index 0000000..89ba4da --- /dev/null +++ b/src/Maple.Domain/Interfaces/IPlaylistRepository.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Maple.Domain +{ + public interface IPlaylistRepository : IRepository + { + Task> ReadAsync(); + } +} diff --git a/src/Maple.Domain/Interfaces/IRangeObservableCollection.cs b/src/Maple.Domain/Interfaces/IRangeObservableCollection.cs index fc425b8..22ee68c 100644 --- a/src/Maple.Domain/Interfaces/IRangeObservableCollection.cs +++ b/src/Maple.Domain/Interfaces/IRangeObservableCollection.cs @@ -8,7 +8,9 @@ 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/IReadOnlyRepository.cs b/src/Maple.Domain/Interfaces/IReadOnlyRepository.cs new file mode 100644 index 0000000..3625b8e --- /dev/null +++ b/src/Maple.Domain/Interfaces/IReadOnlyRepository.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Threading.Tasks; + +namespace Maple.Domain +{ + public interface IReadOnlyRepository + where TEntity : class, IEntity + { + TEntity Read(TKey key); + + Task ReadAsync(TKey key); + + ICollection Read(Expression> filter, string[] propertyNames, int index, int count); + + Task> ReadAsync(Expression> filter, string[] propertyNames, int index, int count); + } +} diff --git a/src/Maple.Domain/Interfaces/IRefreshable.cs b/src/Maple.Domain/Interfaces/IRefreshable.cs index fdb721b..e3e97f8 100644 --- a/src/Maple.Domain/Interfaces/IRefreshable.cs +++ b/src/Maple.Domain/Interfaces/IRefreshable.cs @@ -4,7 +4,8 @@ namespace Maple.Domain { public interface IRefreshable { - void Save(); - Task LoadAsync(); + Task Save(); + + Task Load(); } } diff --git a/src/Maple.Domain/Interfaces/IRepository.cs b/src/Maple.Domain/Interfaces/IRepository.cs new file mode 100644 index 0000000..abc9806 --- /dev/null +++ b/src/Maple.Domain/Interfaces/IRepository.cs @@ -0,0 +1,12 @@ +namespace Maple.Domain +{ + public interface IRepository : IReadOnlyRepository + where TEntity : class, IEntity + { + void Create(TEntity entity); + + void Update(TEntity entity); + + void Delete(TEntity entity); + } +} diff --git a/src/Maple.Domain/Interfaces/IUnitOfWork.cs b/src/Maple.Domain/Interfaces/IUnitOfWork.cs new file mode 100644 index 0000000..70e24a7 --- /dev/null +++ b/src/Maple.Domain/Interfaces/IUnitOfWork.cs @@ -0,0 +1,14 @@ +using System; +using System.Threading.Tasks; + +namespace Maple.Domain +{ + public interface IUnitOfWork : IDisposable + { + IMediaItemRepository MediaItemRepository { get; } + IMediaPlayerRepository MediaPlayerRepository { get; } + IPlaylistRepository PlaylistRepository { get; } + + Task SaveChanges(); + } +} diff --git a/src/Maple.Domain/Interfaces/IVersionService.cs b/src/Maple.Domain/Interfaces/IVersionService.cs index b6a4bd1..8e69375 100644 --- a/src/Maple.Domain/Interfaces/IVersionService.cs +++ b/src/Maple.Domain/Interfaces/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..1cfec32 100644 --- a/src/Maple.Domain/Maple.Domain.csproj +++ b/src/Maple.Domain/Maple.Domain.csproj @@ -1,81 +1,10 @@ - - - + - Debug - AnyCPU - {9D7D05A6-8271-4836-A7BB-5B2ABECCBD81} - Library - Properties - Maple.Domain - Maple.Domain - v4.7.1 - 512 + net471 + false + 7.1 - - 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 + diff --git a/src/Maple.Domain/Models/Base/BaseObject.cs b/src/Maple.Domain/Models/Base/BaseObject.cs index 84b225c..8bef76d 100644 --- a/src/Maple.Domain/Models/Base/BaseObject.cs +++ b/src/Maple.Domain/Models/Base/BaseObject.cs @@ -1,30 +1,24 @@ -using System; -using System.ComponentModel.DataAnnotations; +using System; using System.ComponentModel.DataAnnotations.Schema; namespace Maple.Domain { - public abstract class BaseObject : IBaseObject + public abstract class BaseObject : IEntity { - [Key] - [Column(Order = 1)] - public int Id { get; set; } - [Column(Order = 2)] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public TKey Id { get; set; } + 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; + public bool IsNew => Id.Equals(default(TKey)); } } diff --git a/src/Maple.Domain/Models/MediaItemModel.cs b/src/Maple.Domain/Models/MediaItemModel.cs index 92d84e0..5e5fb64 100644 --- a/src/Maple.Domain/Models/MediaItemModel.cs +++ b/src/Maple.Domain/Models/MediaItemModel.cs @@ -1,31 +1,25 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; using System.Diagnostics; namespace Maple.Domain { [DebuggerDisplay("{Title}, {Sequence}")] - public class MediaItemModel : BaseObject + public class MediaItemModel : BaseObject { public int PlaylistId { get; set; } - [ForeignKey(nameof(PlaylistId))] - public PlaylistModel Playlist { get; set; } - public RawModel Raw { get; set; } + public virtual PlaylistModel Playlist { get; set; } /// /// Ticks /// public long Duration { get; set; } + public int PrivacyStatus { get; set; } public int MediaItemType { get; set; } public string Description { get; set; } - [Required] - [MaxLength(50)] public string Title { get; set; } - [Required] - [MaxLength(2048)] + public string Location { get; set; } } } diff --git a/src/Maple.Domain/Models/MediaPlayerModel.cs b/src/Maple.Domain/Models/MediaPlayerModel.cs index 4775b57..66ae0ed 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 + public class MediaPlayerModel : BaseObject { - public int PlaylistId { get; set; } - [ForeignKey(nameof(PlaylistId))] - public PlaylistModel Playlist { get; set; } + public int? PlaylistId { get; set; } + + public virtual PlaylistModel Playlist { get; set; } - [MaxLength(100)] public string DeviceName { get; set; } + public bool IsPrimary { get; set; } - [Required] - [MaxLength(50)] public string Name { get; set; } } } diff --git a/src/Maple.Domain/Models/OptionModel.cs b/src/Maple.Domain/Models/OptionModel.cs index ec27dc4..3d4f2a9 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; +using System.Diagnostics; namespace Maple.Domain { [DebuggerDisplay("{Key}, {Value}, {Type}")] - public class OptionModel : BaseObject + public class OptionModel : BaseObject { 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..c79f628 100644 --- a/src/Maple.Domain/Models/PlaylistModel.cs +++ b/src/Maple.Domain/Models/PlaylistModel.cs @@ -1,13 +1,10 @@ -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 + public class PlaylistModel : BaseObject { private ICollection _mediaItems; public virtual ICollection MediaItems @@ -16,16 +13,14 @@ public virtual ICollection MediaItems 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; } - - [Required] - [MaxLength(50)] + public int? MediaPlayerId { get; set; } + public virtual MediaPlayerModel MediaPlayer { get; set; } public string Title { get; set; } - } } 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.Icons/Maple.Icons.csproj b/src/Maple.Icons/Maple.Icons.csproj new file mode 100644 index 0000000..c2f6f31 --- /dev/null +++ b/src/Maple.Icons/Maple.Icons.csproj @@ -0,0 +1,22 @@ + + + + net471 + + + + + + + + + + + + + + ..\..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.1\PresentationFramework.dll + + + + diff --git a/src/Maple/UI/PackIcon.cs b/src/Maple.Icons/MaplePackIcon.cs similarity index 94% rename from src/Maple/UI/PackIcon.cs rename to src/Maple.Icons/MaplePackIcon.cs index ab5d6b7..47a63b7 100644 --- a/src/Maple/UI/PackIcon.cs +++ b/src/Maple.Icons/MaplePackIcon.cs @@ -1,29 +1,27 @@ using System.Collections.Generic; using System.Windows; -using MahApps.Metro.IconPacks; +using ControlzEx; using Maple.Domain; -namespace Maple +namespace Maple.Icons { - /// - /// - /// - /// - 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.Localization/Maple.Localization.csproj b/src/Maple.Localization/Maple.Localization.csproj index 32f1b99..65ef5cb 100644 --- a/src/Maple.Localization/Maple.Localization.csproj +++ b/src/Maple.Localization/Maple.Localization.csproj @@ -1,78 +1,23 @@ - - + - 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 + net471 + false + 7.1 - - - - - - - - - - - - + - - 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/Resources.Designer.cs b/src/Maple.Localization/Properties/Resources.Designer.cs index fbdb378..8f9c1ef 100644 --- a/src/Maple.Localization/Properties/Resources.Designer.cs +++ b/src/Maple.Localization/Properties/Resources.Designer.cs @@ -61,7 +61,7 @@ internal Resources() { } /// - /// Looks up a localized string similar to Ok. + /// Looks up a localized string similar to OK. /// public static string Accept { get { diff --git a/src/Maple.Localization/Properties/Resources.resx b/src/Maple.Localization/Properties/Resources.resx index a9f7870..d640ef8 100644 --- a/src/Maple.Localization/Properties/Resources.resx +++ b/src/Maple.Localization/Properties/Resources.resx @@ -140,7 +140,8 @@ https://github.com/Insire/InsireBot-V2 - @Invariant + @Invariant + Einstellungen @@ -217,7 +218,7 @@ Eine Wiedergabeliste aus einer Datei importieren - Ok + OK Schließen diff --git a/src/Maple.Core/Services/DetailLoggingService.cs b/src/Maple.Log/DetailLoggingService.cs similarity index 65% rename from src/Maple.Core/Services/DetailLoggingService.cs rename to src/Maple.Log/DetailLoggingService.cs index 2a40703..9ac2611 100644 --- a/src/Maple.Core/Services/DetailLoggingService.cs +++ b/src/Maple.Log/DetailLoggingService.cs @@ -1,8 +1,9 @@ using System; + using Maple.Domain; using Maple.Localization.Properties; -namespace Maple.Core +namespace Maple.Log { /// /// Generates a Diagnostic report when exceptions are being thrown around @@ -11,8 +12,6 @@ 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}"); @@ -20,42 +19,22 @@ public DetailLoggingService(ILoggingService log) 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) diff --git a/src/Maple.Log/Extensions.cs b/src/Maple.Log/Extensions.cs new file mode 100644 index 0000000..3773fa4 --- /dev/null +++ b/src/Maple.Log/Extensions.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.Logging; + +namespace Maple.Log +{ + public static class Extensions + { + public static ILoggerFactory AddLog4Net(this ILoggerFactory factory) + { + factory?.AddProvider(new Log4NetProvider()); + + return factory; + } + } +} diff --git a/src/Maple.Log/Log4NetLogger.cs b/src/Maple.Log/Log4NetLogger.cs new file mode 100644 index 0000000..c7bb7e3 --- /dev/null +++ b/src/Maple.Log/Log4NetLogger.cs @@ -0,0 +1,99 @@ +using System; +using log4net; +using Microsoft.Extensions.Logging; + +namespace Maple.Log +{ + public sealed class Log4NetLogger : ILogger + { + private readonly ILog _log; + + public Log4NetLogger(string loggerRepository, string name) + { + _log = LogManager.GetLogger(loggerRepository, name); + } + + /// + public IDisposable BeginScope(TState state) + { + return null; + } + + /// + public bool IsEnabled(LogLevel logLevel) + { + switch (logLevel) + { + case LogLevel.Critical: + return _log.IsFatalEnabled; + + case LogLevel.Debug: + case LogLevel.Trace: + return _log.IsDebugEnabled; + + case LogLevel.Error: + return _log.IsErrorEnabled; + + case LogLevel.Information: + return _log.IsInfoEnabled; + + case LogLevel.Warning: + return _log.IsWarnEnabled; + + default: + throw new ArgumentOutOfRangeException(nameof(logLevel)); + } + } + + /// + public void Log( + LogLevel logLevel, + EventId eventId, + TState state, + Exception exception, + Func formatter) + { + if (!IsEnabled(logLevel)) + return; + + if (formatter == null) + throw new ArgumentNullException(nameof(formatter)); + + var message = formatter(state, exception); + if (!string.IsNullOrEmpty(message) || exception != null) + { + switch (logLevel) + { + case LogLevel.Critical: + _log.Fatal(message, exception); + break; + + case LogLevel.Debug: + _log.Debug(message, exception); + break; + + case LogLevel.Error: + _log.Error(message, exception); + break; + + case LogLevel.Information: + _log.Info(message, exception); + break; + + case LogLevel.Warning: + _log.Warn(message, exception); + break; + + case LogLevel.Trace: + _log.Debug(message, exception); + break; + + default: + _log.Warn($"Encountered unknown log level {logLevel}, writing out as Info."); + _log.Info(message, exception); + break; + } + } + } + } +} diff --git a/src/Maple.Log/Log4NetProvider.cs b/src/Maple.Log/Log4NetProvider.cs new file mode 100644 index 0000000..bbd9021 --- /dev/null +++ b/src/Maple.Log/Log4NetProvider.cs @@ -0,0 +1,33 @@ +using System.Collections.Concurrent; +using System.Reflection; +using log4net; +using log4net.Repository; +using Microsoft.Extensions.Logging; + +namespace Maple.Log +{ + public sealed class Log4NetProvider : ILoggerProvider + { + private readonly ILoggerRepository _loggerRepository; + private readonly ConcurrentDictionary _loggers = new ConcurrentDictionary(); + + /// + /// Initializes a new instance of the class. + /// + public Log4NetProvider() + { + _loggerRepository = LogManager.CreateRepository(Assembly.GetEntryAssembly(), typeof(Log4NetProvider)); + } + + /// + public void Dispose() + { + } + + /// + public ILogger CreateLogger(string categoryName) + { + return _loggers.GetOrAdd(categoryName, _ => new Log4NetLogger(_loggerRepository.Name, categoryName)); + } + } +} diff --git a/src/Maple.Core/Services/LoggingService.cs b/src/Maple.Log/LoggingService.cs similarity index 54% rename from src/Maple.Core/Services/LoggingService.cs rename to src/Maple.Log/LoggingService.cs index 32d04b0..47d3b8a 100644 --- a/src/Maple.Core/Services/LoggingService.cs +++ b/src/Maple.Log/LoggingService.cs @@ -1,20 +1,15 @@ using System; + using log4net; + using Maple.Domain; -namespace Maple.Core +namespace Maple.Log { - /// - /// - /// - /// - public class LoggingService : ILoggingService + public sealed class LoggingService : ILoggingService { private readonly ILog _log; - /// - /// Initializes a new instance of the class. - /// public LoggingService() { log4net.Config.XmlConfigurator.Configure(); @@ -29,11 +24,6 @@ public void Debug(object message) _log.Debug(text); } - /// - /// Informations the specified message. - /// - /// The message. - /// The exception. public void Debug(object message, Exception exception) { var text = (string)message; @@ -42,20 +32,11 @@ public void Debug(object message, Exception exception) _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); @@ -78,11 +59,6 @@ public void Info(object message) _log.Info(text); } - /// - /// Informations the specified message. - /// - /// The message. - /// The exception. public void Info(object message, Exception exception) { var text = (string)message; @@ -90,20 +66,11 @@ public void Info(object message, Exception exception) _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.Log/Maple.Log.csproj b/src/Maple.Log/Maple.Log.csproj new file mode 100644 index 0000000..297e1f8 --- /dev/null +++ b/src/Maple.Log/Maple.Log.csproj @@ -0,0 +1,18 @@ + + + + net471 + false + 7.1 + + + + + + + + + + + + diff --git a/src/Maple.Test/DependencyInjectionFactoryTests.cs b/src/Maple.Test/DependencyInjectionFactoryTests.cs index a168d9c..042ad76 100644 --- a/src/Maple.Test/DependencyInjectionFactoryTests.cs +++ b/src/Maple.Test/DependencyInjectionFactoryTests.cs @@ -1,9 +1,13 @@ 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 @@ -11,12 +15,11 @@ namespace Maple.Test [TestClass] public sealed class DependencyInjectionFactoryTests { - [TestMethod] public async Task SanityMapleGetContainerTest() { var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - container.VerifyResolutions(); + container.Validate(); } [TestMethod] @@ -25,7 +28,7 @@ public async Task ResolveMessengerTest() var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); var messenger = Substitute.For(); - container.UseInstance(typeof(IMessenger), messenger, IfAlreadyRegistered: IfAlreadyRegistered.Replace); + container.UseInstance(typeof(IMessenger), messenger, IfAlreadyRegistered: IfAlreadyRegistered.Replace, preventDisposal: false, weaklyReferenced: true, serviceKey: ""); Assert.AreEqual(messenger, container.Resolve()); } 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 index eb633d0..badae8b 100644 --- a/src/Maple.Test/Maple.Test.csproj +++ b/src/Maple.Test/Maple.Test.csproj @@ -48,30 +48,8 @@ Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - - - - - - - - - - @@ -112,19 +90,19 @@ - 2.12.5 + 4.0.4 - 1.2.0 + 1.4.0 - 1.2.0 + 1.4.0 - 3.1.0 + 4.1.0 - 2.8.3 + 3.0.2 diff --git a/src/Maple.Test/MapleMessengerTests.cs b/src/Maple.Test/MapleMessengerTests.cs index 337d873..5f72749 100644 --- a/src/Maple.Test/MapleMessengerTests.cs +++ b/src/Maple.Test/MapleMessengerTests.cs @@ -1,11 +1,13 @@ using System; + using Maple.Core; + using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Maple.Test { [TestClass, Ignore] - public class MapleMessengerTests + public static class MapleMessengerTests { //[TestMethod] //public void Dispose_WithValidHubReference_UnregistersWithHub() @@ -59,7 +61,6 @@ public class TestMessage : MapleMessageBase { public TestMessage(object sender) : base(sender) { - } } @@ -75,7 +76,6 @@ public DerivedMessage(object sender) public interface ITestMessageInterface : IMapleMessage { - } public class InterfaceDerivedMessage : ITestMessageInterface @@ -109,7 +109,7 @@ public void Handle(IMapleMessage message, Exception exception) } } - public class UtilityMethods + public static class UtilityMethods { //public static IMapleMessengerHub GetMessenger() //{ 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 index 283d43c..281dedd 100644 --- a/src/Maple.Test/TestUtils/ContainerContextExtensions.cs +++ b/src/Maple.Test/TestUtils/ContainerContextExtensions.cs @@ -1,15 +1,22 @@ using DryIoc; + using Maple.Core; using Maple.Domain; + using NSubstitute; namespace Maple.Test { public static class ContainerContextExtensions { + public static IUnitOfWork CreateRepository() + { + return Substitute.For(); + } + public static Playlists CreatePlaylists(this IContainer container) { - return new Playlists(container.CreateViewModelServiceContainer(), container.Resolve(), () => container.Resolve()); + return new Playlists(container.CreateViewModelServiceContainer(), container.Resolve(), () => container.Resolve()); } public static ViewModelServiceContainer CreateViewModelServiceContainer(this IContainer container) @@ -53,10 +60,5 @@ 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 index 7b1f73c..c83cc51 100644 --- a/src/Maple.Test/TestUtils/MediaItemModelContextModelExtensions.cs +++ b/src/Maple.Test/TestUtils/MediaItemModelContextModelExtensions.cs @@ -1,5 +1,7 @@ using System; + using Maple.Domain; + using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Maple.Test diff --git a/src/Maple.Test/TestUtils/PlaylistModelContextExtensions.cs b/src/Maple.Test/TestUtils/PlaylistModelContextExtensions.cs index 46e040b..edea407 100644 --- a/src/Maple.Test/TestUtils/PlaylistModelContextExtensions.cs +++ b/src/Maple.Test/TestUtils/PlaylistModelContextExtensions.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; + using Maple.Domain; + using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Maple.Test 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 index cd433c5..9868508 100644 --- a/src/Maple.Test/ViewModels/Playlists/PlaylistTests.cs +++ b/src/Maple.Test/ViewModels/Playlists/PlaylistTests.cs @@ -3,12 +3,17 @@ 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 @@ -456,7 +461,7 @@ public async Task Playlist_ShouldRaiseSelectionChanging() { var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); var messenger = Substitute.For(); - container.UseInstance(typeof(IMessenger), messenger, IfAlreadyRegistered: IfAlreadyRegistered.Replace); + container.UseInstance(typeof(IMessenger), messenger, IfAlreadyRegistered: IfAlreadyRegistered.Replace, preventDisposal: false, weaklyReferenced: true, serviceKey: ""); Assert.AreEqual(messenger, container.Resolve()); @@ -473,7 +478,7 @@ public async Task Playlist_ShouldRaiseSelectionChanged() { var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); var messenger = Substitute.For(); - container.UseInstance(typeof(IMessenger), messenger, IfAlreadyRegistered: IfAlreadyRegistered.Replace); + container.UseInstance(typeof(IMessenger), messenger, IfAlreadyRegistered: IfAlreadyRegistered.Replace, preventDisposal: false, weaklyReferenced: true, serviceKey: ""); Assert.AreEqual(messenger, container.Resolve()); @@ -540,7 +545,7 @@ public async Task Playlist_ShouldAddItemsFromFileDialog() }; var dialogViewModel = Substitute.For(); dialogViewModel.ShowMediaItemSelectionDialog(NSubstitute.Arg.Any(), NSubstitute.Arg.Any()).Returns((true, mediaItems)); - container.UseInstance(typeof(IDialogViewModel), dialogViewModel, IfAlreadyRegistered: IfAlreadyRegistered.Replace); + container.UseInstance(typeof(IDialogViewModel), dialogViewModel, IfAlreadyRegistered: IfAlreadyRegistered.Replace, preventDisposal: false, weaklyReferenced: true, serviceKey: ""); var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); @@ -566,7 +571,7 @@ public async Task Playlist_ShouldAddItemsFromFolderDialog() }; var dialogViewModel = Substitute.For(); dialogViewModel.ShowMediaItemFolderSelectionDialog(NSubstitute.Arg.Any(), NSubstitute.Arg.Any()).Returns((true, mediaItems)); - container.UseInstance(typeof(IDialogViewModel), dialogViewModel, IfAlreadyRegistered: IfAlreadyRegistered.Replace); + container.UseInstance(typeof(IDialogViewModel), dialogViewModel, IfAlreadyRegistered: IfAlreadyRegistered.Replace, preventDisposal: false, weaklyReferenced: true, serviceKey: ""); var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); @@ -592,7 +597,7 @@ public async Task Playlist_ShouldAddItemsFromUrlDialog() }; var dialogViewModel = Substitute.For(); dialogViewModel.ShowUrlParseDialog(NSubstitute.Arg.Any()).Returns((mediaItems)); - container.UseInstance(typeof(IDialogViewModel), dialogViewModel, IfAlreadyRegistered: IfAlreadyRegistered.Replace); + container.UseInstance(typeof(IDialogViewModel), dialogViewModel, IfAlreadyRegistered: IfAlreadyRegistered.Replace, preventDisposal: false, weaklyReferenced: true, serviceKey: ""); var playlist = container.CreatePlaylist(_context.CreateModelPlaylist()); diff --git a/src/Maple.Test/ViewModels/Playlists/PlaylistsTests.cs b/src/Maple.Test/ViewModels/Playlists/PlaylistsTests.cs index f887c96..1c9b572 100644 --- a/src/Maple.Test/ViewModels/Playlists/PlaylistsTests.cs +++ b/src/Maple.Test/ViewModels/Playlists/PlaylistsTests.cs @@ -1,9 +1,13 @@ 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 @@ -98,9 +102,9 @@ public async Task Playlists_ShouldSave() var playlists = container.Resolve(); repository.ClearReceivedCalls(); - playlists.Save(); + await playlists.Save().ConfigureAwait(false); - repository.Received(1).Save(NSubstitute.Arg.Any()); + await repository.Received(1).SaveChanges().ConfigureAwait(false); repository.Received(1).Dispose(); } @@ -108,19 +112,19 @@ public async Task Playlists_ShouldSave() public async Task Playlists_ShouldLoad() { var container = await DependencyInjectionFactory.Get().ConfigureAwait(false); - var dummyPlaylists = new List + var dummyPlaylists = new List { - container.CreatePlaylist(_context.CreateModelPlaylist()), + _context.CreateModelPlaylist(), }; var repository = ContainerContextExtensions.CreateRepository(); - repository.GetPlaylistsAsync().ReturnsForAnyArgs(dummyPlaylists); + repository.PlaylistRepository.ReadAsync().ReturnsForAnyArgs(dummyPlaylists); container.UseInstance(repository); var playlists = (Playlists)container.Resolve(); repository.ClearReceivedCalls(); - await playlists.LoadAsync().ConfigureAwait(false); - await repository.Received(1).GetPlaylistsAsync().ConfigureAwait(false); + await playlists.Load().ConfigureAwait(false); + await repository.PlaylistRepository.Received(1).ReadAsync().ConfigureAwait(false); repository.Received(1).Dispose(); Assert.AreEqual(dummyPlaylists[0], playlists.SelectedItem); diff --git a/src/Maple.Test/app.config b/src/Maple.Test/app.config index fedd661..ec91ac8 100644 --- a/src/Maple.Test/app.config +++ b/src/Maple.Test/app.config @@ -1,15 +1,14 @@ -
+
- + - + - diff --git a/src/Maple.Youtube/IYoutubeApi.cs b/src/Maple.Youtube/IYoutubeApi.cs index bb6e51d..0440aa9 100644 --- a/src/Maple.Youtube/IYoutubeApi.cs +++ b/src/Maple.Youtube/IYoutubeApi.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using System.Threading.Tasks; + using Google.Apis.YouTube.v3.Data; + using Maple.Domain; namespace Maple.Youtube @@ -8,10 +10,15 @@ 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/Maple.Youtube.csproj b/src/Maple.Youtube/Maple.Youtube.csproj index 7343835..aa1cb58 100644 --- a/src/Maple.Youtube/Maple.Youtube.csproj +++ b/src/Maple.Youtube/Maple.Youtube.csproj @@ -34,9 +34,9 @@ - 1.31.1.1063 + 1.39.0.1572 - + diff --git a/src/Maple.Youtube/Utility/UrlParseResult.cs b/src/Maple.Youtube/Utility/UrlParseResult.cs index 0e0b797..83e871f 100644 --- a/src/Maple.Youtube/Utility/UrlParseResult.cs +++ b/src/Maple.Youtube/Utility/UrlParseResult.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; + using Maple.Domain; using Maple.Localization.Properties; @@ -128,6 +129,7 @@ private int RefreshCount() 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..5ddef34 100644 --- a/src/Maple.Youtube/YoutubeApi.cs +++ b/src/Maple.Youtube/YoutubeApi.cs @@ -1,15 +1,18 @@ -using System; +using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Web; using System.Xml; + using Google.Apis.Auth.OAuth2; using Google.Apis.Services; using Google.Apis.Util.Store; using Google.Apis.YouTube.v3; using Google.Apis.YouTube.v3.Data; + using Maple.Domain; using Maple.Localization.Properties; @@ -22,12 +25,10 @@ public class YoutubeApi : IYoutubeApi 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() @@ -37,9 +38,15 @@ private async Task GetService() _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() }); @@ -52,7 +59,15 @@ 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) + { + _log.Error("Youtube credentials not found!."); + return null; + } + + var clientSecrets = secretCollection.Secrets; var store = new FileDataStore(GetType().ToString()); var scopes = new[] { @@ -60,7 +75,7 @@ private async Task GetCredential() 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); } } @@ -70,6 +85,11 @@ public async Task> GetPlaylists(string playlistId) 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; @@ -100,6 +120,11 @@ public async Task CreatePlaylist(PlaylistModel playlist, bool publicPlaylist = t { var youtubeService = await GetService().ConfigureAwait(false); + if (youtubeService is null) + { + return; + } + var newPlaylist = new Playlist() { Snippet = new PlaylistSnippet() @@ -138,6 +163,11 @@ public async Task CreatePlaylist(PlaylistModel playlist, bool publicPlaylist = t public async Task DeletePlaylist(PlaylistModel playlist) { var youtubeService = await GetService().ConfigureAwait(false); + if (youtubeService is null) + { + return; + } + var id = GetPlaylistId(playlist); await youtubeService.Playlists.Delete(id) @@ -165,8 +195,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 +209,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 +225,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) diff --git a/src/Maple.Youtube/YoutubeUrlParser.cs b/src/Maple.Youtube/YoutubeUrlParser.cs index b98c95a..dbbd830 100644 --- a/src/Maple.Youtube/YoutubeUrlParser.cs +++ b/src/Maple.Youtube/YoutubeUrlParser.cs @@ -3,6 +3,7 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Web; + using Maple.Domain; using Maple.Localization.Properties; 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 index 67ca9a7..30a5841 100644 --- a/src/Maple/App.config +++ b/src/Maple/App.config @@ -1,83 +1,77 @@ -
+
-
+
-
- - - - - - - - - + + + + - - - - - - - + + + + + + + - - + + - - + + - - - - - - - + + + + + + + - - + + - - + + - - - + + + - - + + - - + + - - + + - + - + @@ -94,34 +88,14 @@ Normal - + - + False - - - - - - - - - - - - - - - - - - - - diff --git a/src/Maple/App.xaml b/src/Maple/App.xaml index 2cc3369..93406e7 100644 --- a/src/Maple/App.xaml +++ b/src/Maple/App.xaml @@ -55,7 +55,6 @@ Color="{DynamicResource Primary500}" /> - - \ No newline at end of file + diff --git a/src/Maple/App.xaml.cs b/src/Maple/App.xaml.cs index 2854ef7..076af14 100644 --- a/src/Maple/App.xaml.cs +++ b/src/Maple/App.xaml.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Net; @@ -6,9 +6,13 @@ using System.Threading.Tasks; using System.Windows; using System.Windows.Threading; + using DryIoc; + using Maple.Core; +using Maple.Data; using Maple.Domain; +using Microsoft.Extensions.Logging; using Squirrel; namespace Maple @@ -25,13 +29,19 @@ protected override async void OnStartup(StartupEventArgs e) _container = await DependencyInjectionFactory.Get().ConfigureAwait(true); var localizationService = _container.Resolve(); + var loggerFactory = _container.Resolve(); var log = _container.Resolve(); InitializeUpdater(log); InitializeResources(localizationService); InitializeLocalization(); - var shell = await GetShell(localizationService, log).ConfigureAwait(true); + using (var context = _container.Resolve()) + { + await context.Migrate().ConfigureAwait(false); + } + + var shell = await GetShell(log).ConfigureAwait(true); shell.Show(); base.OnStartup(e); @@ -52,9 +62,8 @@ private async void App_DispatcherUnhandledException(object sender, DispatcherUnh await dialog.ShowExceptionDialog(e.Exception).ConfigureAwait(true); } - protected override void OnExit(ExitEventArgs e) + protected override async void OnExit(ExitEventArgs e) { - SaveState(); DisposeResources(); _backgroundUpdate.Wait(); @@ -70,7 +79,7 @@ protected override void OnExit(ExitEventArgs e) /// /// order matters alot here, so be careful when modifying this /// - private async Task GetShell(ILocalizationService service, ILoggingService log) + private async Task GetShell(ILoggingService log) { using (var vm = _container.Resolve()) { @@ -80,8 +89,6 @@ private async Task GetShell(ILocalizationService service, ILoggingService 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); @@ -119,8 +126,8 @@ private void InitializeUpdater(ILoggingService log) private async Task LoadUpdates(ILoggingService log) { +#if Release var manager = default(UpdateManager); - try { using (manager = await UpdateManager.GitHubUpdateManager("https://www.github.com/Insire/Maple", prerelease: true).ConfigureAwait(true)) @@ -136,7 +143,6 @@ private async Task LoadUpdates(ILoggingService log) // var releaseEntry = await manager.UpdateApp().ConfigureAwait(true); // Debug.WriteLine($"Update complete {releaseEntry.Version}"); - //} } } @@ -154,27 +160,7 @@ private async Task LoadUpdates(ILoggingService log) { manager?.Dispose(); } - } - - private IList LoadApplicationData() - { - var tasks = new List(); - - foreach (var item in _container.Resolve>()) - tasks.Add(item.LoadAsync()); - - return tasks; - } - - private void SaveState() - { - var log = _container.Resolve(); - log.Info(Localization.Properties.Resources.SavingState); - - foreach (var item in _container.Resolve>()) - item.Save(); - - log.Info(Localization.Properties.Resources.SavedState); +#endif } private void DisposeResources() diff --git a/src/Maple/FodyWeavers.xml b/src/Maple/FodyWeavers.xml index 1f93c9a..a246195 100644 --- a/src/Maple/FodyWeavers.xml +++ b/src/Maple/FodyWeavers.xml @@ -1,4 +1,4 @@ - \ No newline at end of file + diff --git a/src/Maple/Interfaces/IMediaItemMapper.cs b/src/Maple/Interfaces/IMediaItemMapper.cs index f987723..264a08b 100644 --- a/src/Maple/Interfaces/IMediaItemMapper.cs +++ b/src/Maple/Interfaces/IMediaItemMapper.cs @@ -5,6 +5,7 @@ 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 index ed7f9cb..ab07572 100644 --- a/src/Maple/Interfaces/IMediaPlayerMapper.cs +++ b/src/Maple/Interfaces/IMediaPlayerMapper.cs @@ -7,6 +7,7 @@ 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/Maple.csproj b/src/Maple/Maple.csproj index c6b270b..979c92e 100644 --- a/src/Maple/Maple.csproj +++ b/src/Maple/Maple.csproj @@ -60,35 +60,31 @@ ..\Resources\Images\logo.ico - - + - 2.12.5 + 4.0.4 - - - - + + - 2.2.0 + 2.6.2 - 2.2.0 + 2.6.2 - - + + - - - - + + + + + + 1.1.13 + - 1.7.8 + 1.9.1 - - - - @@ -123,15 +119,14 @@ - + - MediaPlayersPage.xaml @@ -146,7 +141,6 @@ - SplashScreen.xaml @@ -341,10 +335,18 @@ {9d7d05a6-8271-4836-a7bb-5b2abeccbd81} Maple.Domain + + {1570d024-dde5-4bba-bc01-f47d47535b53} + Maple.Icons + - {A073FC92-90E3-4541-8B52-6F7293187871} + {a073fc92-90e3-4541-8b52-6f7293187871} Maple.Localization + + {8c3e9110-ffb8-4656-9a19-b763c0868278} + Maple.Log + {B5BE546F-8D9F-4FB9-B235-AF05FD553F9E} Maple.Youtube 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/Resources/Style.xaml b/src/Maple/Resources/Style.xaml index 2c2b839..a74de4b 100644 --- a/src/Maple/Resources/Style.xaml +++ b/src/Maple/Resources/Style.xaml @@ -238,22 +238,27 @@ - @@ -1207,5 +1205,4 @@ - - \ No newline at end of file + diff --git a/src/Maple.Core/Services/LogNotifcationService.cs b/src/Maple/Services/LogNotifcationService.cs similarity index 90% rename from src/Maple.Core/Services/LogNotifcationService.cs rename to src/Maple/Services/LogNotifcationService.cs index e8e05c8..c554db1 100644 --- a/src/Maple.Core/Services/LogNotifcationService.cs +++ b/src/Maple/Services/LogNotifcationService.cs @@ -1,10 +1,11 @@ using System; +using Maple.Core; using Maple.Domain; using Maple.Localization.Properties; -namespace Maple.Core +namespace Maple { - public class LoggingNotifcationService : ILoggingNotifcationService + public sealed class LoggingNotifcationService : ILoggingNotifcationService { private readonly ILoggingService _log; private readonly IMessenger _messenger; diff --git a/src/Maple/Services/MediaRepository.cs b/src/Maple/Services/MediaRepository.cs deleted file mode 100644 index 1a7504a..0000000 --- a/src/Maple/Services/MediaRepository.cs +++ /dev/null @@ -1,208 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using Maple.Core; -using Maple.Data; -using Maple.Localization.Properties; - -namespace Maple -{ - // helpful: https://blog.oneunicorn.com/2012/03/10/secrets-of-detectchanges-part-1-what-does-detectchanges-do/ - /// - /// Provides a way to access all playback related data on the DAL - /// - /// - public class MediaRepository : IMediaRepository - { - private const int _saveThreshold = 100; - - private readonly IMediaItemRepository _mediaItemRepository; - private readonly IMediaPlayerRepository _mediaPlayerRepository; - private readonly IPlaylistRepository _playlistRepository; - - private readonly IPlaylistMapper _playlistMapper; - private readonly IMediaPlayerMapper _mediaPlayerMapper; - private readonly IMediaItemMapper _mediaItemMapper; - - private readonly BusyStack _busyStack; - - private bool _disposed = false; - - public bool IsBusy { get; private set; } - - public MediaRepository(IPlaylistMapper playlistMapper, - IMediaItemMapper mediaItemMapper, - IMediaPlayerMapper mediaPlayerMapper, - IMediaItemRepository mediaItemRepository, - IMediaPlayerRepository mediaPlayerRepository, - IPlaylistRepository playlistRepository) - { - _mediaItemMapper = mediaItemMapper ?? throw new ArgumentNullException(nameof(mediaItemMapper), $"{nameof(mediaItemMapper)} {Resources.IsRequired}"); - _playlistMapper = playlistMapper ?? throw new ArgumentNullException(nameof(playlistMapper), $"{nameof(playlistMapper)} {Resources.IsRequired}"); - _mediaPlayerMapper = mediaPlayerMapper ?? throw new ArgumentNullException(nameof(mediaPlayerMapper), $"{nameof(mediaPlayerMapper)} {Resources.IsRequired}"); - - _mediaItemRepository = mediaItemRepository ?? throw new ArgumentNullException(nameof(mediaItemRepository), $"{nameof(mediaItemRepository)} {Resources.IsRequired}"); - _mediaPlayerRepository = mediaPlayerRepository ?? throw new ArgumentNullException(nameof(mediaPlayerRepository), $"{nameof(mediaPlayerRepository)} {Resources.IsRequired}"); - _playlistRepository = playlistRepository ?? throw new ArgumentNullException(nameof(playlistRepository), $"{nameof(playlistRepository)} {Resources.IsRequired}"); - - _busyStack = new BusyStack(); - _busyStack.OnChanged += (hasItems) => { IsBusy = hasItems; }; - } - - public void Save(MediaItem viewModel) - { - using (_busyStack.GetToken()) - _mediaItemRepository.Save(viewModel.Model); - } - - public void Save(MediaItems viewModel) - { - using (_busyStack.GetToken()) - { - foreach (var item in viewModel.Items) - Save(item); - } - } - - public async Task GetMediaItemByIdAsync(int id) - { - using (_busyStack.GetToken()) - { - var item = await _mediaItemRepository.GetByIdAsync(id) - .ConfigureAwait(true); - return _mediaItemMapper.Get(item); - } - } - - public async Task> GetMediaItemsAsync() - { - using (_busyStack.GetToken()) - { - var items = await _mediaItemRepository.GetAsync() - .ConfigureAwait(true); - return items.Select(p => _mediaItemMapper.Get(p)) - .ToList(); - } - } - - public async Task GetMediaItemByPlaylistIdAsync(int id) - { - using (_busyStack.GetToken()) - { - var item = await _mediaItemRepository.GetMediaItemByPlaylistIdAsync(id) - .ConfigureAwait(true); - return _mediaItemMapper.Get(item); - } - } - - public void Save(Playlist viewModel) - { - if (!viewModel.IsChanged) - return; - - using (_busyStack.GetToken()) - _playlistRepository.Save(viewModel.Model); - } - - public void Save(Playlists viewModel) - { - using (_busyStack.GetToken()) - { - foreach (var item in viewModel.Items) - Save(item); - } - } - - public async Task GetPlaylistByIdAsync(int id) - { - using (_busyStack.GetToken()) - { - var item = await _playlistRepository.GetByIdAsync(id) - .ConfigureAwait(true); - return _playlistMapper.Get(item); - } - } - - public async Task> GetPlaylistsAsync() - { - using (_busyStack.GetToken()) - { - var items = await _playlistRepository.GetAsync() - .ConfigureAwait(true); - return items.Select(p => _playlistMapper.Get(p)) - .ToList(); - } - } - - public void Save(MediaPlayer viewModel) - { - using (_busyStack.GetToken()) - _mediaPlayerRepository.Save(viewModel.Model); - } - - public void Save(MediaPlayers viewModel) - { - using (_busyStack.GetToken()) - { - foreach (var item in viewModel.Items) - Save(item); - } - } - - public async Task GetMainMediaPlayerAsync() - { - using (_busyStack.GetToken()) - { - var item = await _mediaPlayerRepository.GetMainMediaPlayerAsync() - .ConfigureAwait(true); - return _mediaPlayerMapper.GetMain(item, _playlistMapper.Get(item.Playlist)); - } - } - - public async Task GetMediaPlayerByIdAsync(int id) - { - using (_busyStack.GetToken()) - { - var item = await _mediaPlayerRepository.GetByIdAsync(id) - .ConfigureAwait(true); - return _mediaPlayerMapper.Get(item); - } - } - - public async Task> GetAllOptionalMediaPlayersAsync() - { - using (_busyStack.GetToken()) - { - var items = await _mediaPlayerRepository.GetOptionalMediaPlayersAsync() - .ConfigureAwait(true); - return items.Select(p => _mediaPlayerMapper.Get(p)) - .ToList(); - } - } - - [DebuggerStepThrough] - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - // Protected implementation of Dispose pattern. - protected virtual void Dispose(bool disposing) - { - if (_disposed) - return; - - if (disposing) - { - - // Free any other managed objects here. - } - - // Free any unmanaged objects here. - _disposed = true; - } - } -} diff --git a/src/Maple/Services/SquirrelLogger.cs b/src/Maple/Services/SquirrelLogger.cs index 05522d3..f527c1f 100644 --- a/src/Maple/Services/SquirrelLogger.cs +++ b/src/Maple/Services/SquirrelLogger.cs @@ -1,7 +1,9 @@ using System; using System.ComponentModel; + using Maple.Domain; using Maple.Localization.Properties; + using Splat; namespace Maple @@ -67,13 +69,16 @@ public void Write([Localizable(false)] string message, LogLevel logLevel) case LogLevel.Error: Error(message); break; + case LogLevel.Fatal: Fatal(message); break; + case LogLevel.Debug: case LogLevel.Info: Info(message); break; + case LogLevel.Warn: Warn(message); break; diff --git a/src/Maple/Services/VersionService.cs b/src/Maple/Services/VersionService.cs index 00c284d..14c5108 100644 --- a/src/Maple/Services/VersionService.cs +++ b/src/Maple/Services/VersionService.cs @@ -1,4 +1,5 @@ using System.Reflection; + using Maple.Domain; namespace Maple diff --git a/src/Maple/Shell.xaml b/src/Maple/Shell.xaml index e6e9326..f76278a 100644 --- a/src/Maple/Shell.xaml +++ b/src/Maple/Shell.xaml @@ -46,13 +46,13 @@ Mode="PrimaryMid"> - + - - - + + + - + @@ -62,7 +62,7 @@ - + @@ -85,9 +85,9 @@ - - + TextWrapping="NoWrap"> + + - @@ -106,7 +105,7 @@ Orientation="Horizontal"> - @@ -128,7 +126,7 @@ SelectedItem="{Binding SelectedItem, IsAsync=True, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"> - + diff --git a/src/Maple/Utils/DependencyInjectionFactory.cs b/src/Maple/Utils/DependencyInjectionFactory.cs index b0c7e3e..5fd96de 100644 --- a/src/Maple/Utils/DependencyInjectionFactory.cs +++ b/src/Maple/Utils/DependencyInjectionFactory.cs @@ -1,10 +1,15 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; + using DryIoc; + using FluentValidation; + using Maple.Core; using Maple.Data; using Maple.Domain; +using Maple.Log; using Maple.Youtube; +using Microsoft.Extensions.Logging; namespace Maple { @@ -25,10 +30,7 @@ IContainer InitializeContainer() RegisterValidation(); RegisterControls(); - c.Resolve().LoadAsync(); - - //if (Debugger.IsAttached) - // Debugging(); + c.Resolve().Load(); return c; } @@ -68,14 +70,15 @@ 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(Reuse.Transient, setup: Setup.With(allowDisposableTransient: true)); + c.Register(Reuse.Transient, setup: Setup.With(allowDisposableTransient: true)); + c.Register(Reuse.Transient, setup: Setup.With(allowDisposableTransient: true)); + + c.Register(Reuse.Transient, setup: Setup.With(allowDisposableTransient: true)); c.Register(); c.Register(); @@ -94,6 +97,7 @@ void RegisterServices() c.Register(Reuse.Singleton); c.Register(setup: Setup.DecoratorWith(order: 1)); c.Register(setup: Setup.DecoratorWith(order: 2)); + c.Register(Reuse.Singleton, Made.Of(() => new LoggerFactory())); } void RegisterValidation() diff --git a/src/Maple/Utils/Mappers/Base/BaseMapper.cs b/src/Maple/Utils/Mappers/Base/BaseMapper.cs index 74fa2f9..4b44f01 100644 --- a/src/Maple/Utils/Mappers/Base/BaseMapper.cs +++ b/src/Maple/Utils/Mappers/Base/BaseMapper.cs @@ -1,6 +1,9 @@ using System; + using AutoMapper; + using FluentValidation; + using Maple.Core; using Maple.Domain; using Maple.Localization.Properties; diff --git a/src/Maple/Utils/Mappers/MapperExtensions.cs b/src/Maple/Utils/Mappers/MapperExtensions.cs index 5836b58..a1af877 100644 --- a/src/Maple/Utils/Mappers/MapperExtensions.cs +++ b/src/Maple/Utils/Mappers/MapperExtensions.cs @@ -2,7 +2,9 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; + using AutoMapper; + using Maple.Core; namespace Maple @@ -12,25 +14,19 @@ namespace Maple /// 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) + public static IEnumerable GetMany(this IMediaPlayerMapper mapper, IEnumerable items) { - return items.ForEach(mapper.GetData); + return items.ForEach(mapper.Get); } public static IMappingExpression Ignore(this IMappingExpression 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 index 6a800b0..f3926ee 100644 --- a/src/Maple/Utils/Validation/PlaylistValidator.cs +++ b/src/Maple/Utils/Validation/PlaylistValidator.cs @@ -1,4 +1,5 @@ -using FluentValidation; +using FluentValidation; + using Maple.Core; namespace Maple @@ -16,17 +17,12 @@ public PlaylistValidator(ILocalizationService translationService, IValidator 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); + RuleForEach(playlist => playlist.Items).SetValidator(mediaItemValidator); } } } diff --git a/src/Maple/Utils/Validation/PlaylistsValidator.cs b/src/Maple/Utils/Validation/PlaylistsValidator.cs index 5c3c8af..2079b79 100644 --- a/src/Maple/Utils/Validation/PlaylistsValidator.cs +++ b/src/Maple/Utils/Validation/PlaylistsValidator.cs @@ -1,15 +1,16 @@ -using FluentValidation; +using FluentValidation; + using Maple.Core; namespace Maple { - public class PlaylistsValidator : BaseValidator, IValidator + public class PlaylistsValidator : BaseValidator { public PlaylistsValidator(ILocalizationService translationService, IValidator playlistValidator) : base(translationService) { - RuleFor(playlists => playlists.Items).NotEmpty() - .SetCollectionValidator(playlistValidator); + RuleFor(playlists => playlists.Items).NotNull(); + RuleForEach(playlists => playlists.Items).SetValidator(playlistValidator); } } } diff --git a/src/Maple/ViewModels/Dialogs/Base/DialogBaseViewModel.cs b/src/Maple/ViewModels/Dialogs/Base/DialogBaseViewModel.cs index e05fbd6..efb67b4 100644 --- a/src/Maple/ViewModels/Dialogs/Base/DialogBaseViewModel.cs +++ b/src/Maple/ViewModels/Dialogs/Base/DialogBaseViewModel.cs @@ -2,6 +2,7 @@ using System.Threading; using System.Threading.Tasks; using System.Windows.Input; + using Maple.Core; namespace Maple diff --git a/src/Maple/ViewModels/Dialogs/Base/IDialogViewModel.cs b/src/Maple/ViewModels/Dialogs/Base/IDialogViewModel.cs index e517e82..12a6ded 100644 --- a/src/Maple/ViewModels/Dialogs/Base/IDialogViewModel.cs +++ b/src/Maple/ViewModels/Dialogs/Base/IDialogViewModel.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; + using Maple.Core; namespace Maple @@ -9,12 +10,19 @@ 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 index 9fbae6a..a72857b 100644 --- a/src/Maple/ViewModels/Dialogs/DialogContentViewModels/ExceptionContentDialogViewModel.cs +++ b/src/Maple/ViewModels/Dialogs/DialogContentViewModels/ExceptionContentDialogViewModel.cs @@ -1,4 +1,5 @@ using System; + using Maple.Core; namespace Maple diff --git a/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FileBrowserContentDialogViewModel.cs b/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FileBrowserContentDialogViewModel.cs index 3c9377b..0d210be 100644 --- a/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FileBrowserContentDialogViewModel.cs +++ b/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FileBrowserContentDialogViewModel.cs @@ -1,4 +1,5 @@ using System; + using Maple.Core; using Maple.Localization.Properties; @@ -6,7 +7,7 @@ namespace Maple { public class FileBrowserContentDialogViewModel : ObservableObject { - private FileSystemBrowserOptions _options; + private readonly FileSystemBrowserOptions _options; private FileSystemViewModel _fileSystemViewModel; public FileSystemViewModel FileSystemViewModel diff --git a/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FolderBrowserContentDialogViewModel.cs b/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FolderBrowserContentDialogViewModel.cs index cba7ecc..bfed31b 100644 --- a/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FolderBrowserContentDialogViewModel.cs +++ b/src/Maple/ViewModels/Dialogs/DialogContentViewModels/IO/FolderBrowserContentDialogViewModel.cs @@ -1,4 +1,5 @@ using System; + using Maple.Core; using Maple.Localization.Properties; @@ -6,7 +7,7 @@ namespace Maple { public class FolderBrowserContentDialogViewModel : ObservableObject { - private FileSystemBrowserOptions _options; + private readonly FileSystemBrowserOptions _options; private FileSystemViewModel _fileSystemViewModel; public FileSystemViewModel FileSystemViewModel diff --git a/src/Maple/ViewModels/Dialogs/DialogViewModel.cs b/src/Maple/ViewModels/Dialogs/DialogViewModel.cs index 7da5526..6c38409 100644 --- a/src/Maple/ViewModels/Dialogs/DialogViewModel.cs +++ b/src/Maple/ViewModels/Dialogs/DialogViewModel.cs @@ -1,8 +1,10 @@ -using System; +using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; + using Maple.Core; using Maple.Localization.Properties; using Maple.Youtube; @@ -27,7 +29,6 @@ public DialogViewModel(ILocalizationService translator, IYoutubeUrlParser servic _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()); @@ -141,10 +142,24 @@ public Task ShowExceptionDialog(Exception exception) // should handle items depending on options - foreach (var file in Folder.Children) + IEnumerable query = Folder.Children; + + if (options.IncludeSubFolders) + { + // TODO + } + + var supportedFileExtensions = new HashSet(StringComparer.OrdinalIgnoreCase) { - // TODO get the files from the folder - // TODO parse the files from the folder and generate mediaitems from them + ".flac", + ".mp3" + }; + + foreach (var file in query.Where(p => !p.IsContainer && supportedFileExtensions.Contains(Path.GetExtension(p.Name)))) + { + var factory = _createMediaItemFactory(); + + mediaItems.Add(factory.Create(file.FullName)); } return (Result, mediaItems); @@ -172,9 +187,14 @@ public Task ShowExceptionDialog(Exception exception) { AcceptAction = () => { - var items = viewModel.FileSystemViewModel.SelectedItems; - items.Add(viewModel.FileSystemViewModel.SelectedItem); - tuple = (true, items.Distinct().FirstOrDefault() as IFileSystemDirectory); // TODO handle multi select option + if (viewModel.FileSystemViewModel.SelectedItem is IFileSystemDirectory directory) + { + tuple = (true, directory); + } + else + { + tuple = (false, default(IFileSystemDirectory)); + } }; CancelAction = () => @@ -229,7 +249,6 @@ public async Task> ShowUrlParseDialog(CancellationToken t 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 index 1af604a..ed4d17c 100644 --- a/src/Maple/ViewModels/Interfaces/ICultureViewModel.cs +++ b/src/Maple/ViewModels/Interfaces/ICultureViewModel.cs @@ -5,4 +5,4 @@ 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 index 3ebd2bb..643f51c 100644 --- a/src/Maple/ViewModels/Interfaces/IMediaItemsViewModel.cs +++ b/src/Maple/ViewModels/Interfaces/IMediaItemsViewModel.cs @@ -1,15 +1,13 @@ using System.Collections.Generic; -using System.Threading.Tasks; + using Maple.Core; namespace Maple { - public interface IMediaItemsViewModel : ISaveableViewModel + public interface IMediaItemsViewModel : ISaveableViewModel, ILoadableViewModel { 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 index b035984..5e3fbed 100644 --- a/src/Maple/ViewModels/Interfaces/IMediaPlayersViewModel.cs +++ b/src/Maple/ViewModels/Interfaces/IMediaPlayersViewModel.cs @@ -1,11 +1,12 @@ -using System; +using System; using System.Collections.Generic; + using Maple.Core; namespace Maple { - public interface IMediaPlayersViewModel : ILoadableViewModel, ISaveableViewModel, IDisposable + public interface IMediaPlayersViewModel : ILoadableViewModel, 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 index 2c2a01a..0ce2ae9 100644 --- a/src/Maple/ViewModels/Interfaces/IPlaylistsViewModel.cs +++ b/src/Maple/ViewModels/Interfaces/IPlaylistsViewModel.cs @@ -1,9 +1,11 @@ -using Maple.Core; +using System.Threading.Tasks; +using Maple.Core; +using Maple.Domain; namespace Maple { - public interface IPlaylistsViewModel : ILoadableViewModel, ISaveableViewModel + public interface IPlaylistsViewModel : ILoadableViewModel, ISaveableViewModel, IBaseListViewModel { - void Add(); + Task Add(); } -} \ No newline at end of file +} diff --git a/src/Maple/ViewModels/Interfaces/ISplashScreenViewModel.cs b/src/Maple/ViewModels/Interfaces/ISplashScreenViewModel.cs index c17a849..6c305ff 100644 --- a/src/Maple/ViewModels/Interfaces/ISplashScreenViewModel.cs +++ b/src/Maple/ViewModels/Interfaces/ISplashScreenViewModel.cs @@ -10,4 +10,4 @@ public interface ISplashScreenViewModel : IDisposable 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 index eca7058..078dcbc 100644 --- a/src/Maple/ViewModels/Interfaces/IUIColorsViewModel.cs +++ b/src/Maple/ViewModels/Interfaces/IUIColorsViewModel.cs @@ -1,4 +1,5 @@ using System.Windows.Input; + using Maple.Core; namespace Maple @@ -11,4 +12,4 @@ public interface IUIColorsViewModel : ILoadableViewModel, ISaveableViewModel 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 index 07a16b8..7f38049 100644 --- a/src/Maple/ViewModels/MediaItems/CreateMediaItem.cs +++ b/src/Maple/ViewModels/MediaItems/CreateMediaItem.cs @@ -1,7 +1,10 @@ -using System; +using System; +using System.IO; using System.Threading.Tasks; using System.Windows.Input; + using Maple.Core; +using Maple.Domain; using Maple.Localization.Properties; using Maple.Youtube; @@ -58,5 +61,18 @@ private bool CanParse() { return !string.IsNullOrWhiteSpace(Source); } + + public MediaItem Create(string absolutePath) + { + var model = new MediaItemModel() + { + Location = absolutePath, + MediaItemType = (int)MediaItemType.LocalFile, + PrivacyStatus = (int)PrivacyStatus.None, + Title = Path.GetFileName(absolutePath), + }; + + return _mapper.Get(model); + } } } diff --git a/src/Maple/ViewModels/MediaItems/MediaItem.cs b/src/Maple/ViewModels/MediaItems/MediaItem.cs index 5639dfb..8840f2c 100644 --- a/src/Maple/ViewModels/MediaItems/MediaItem.cs +++ b/src/Maple/ViewModels/MediaItems/MediaItem.cs @@ -1,16 +1,13 @@ -using System; +using System; using System.Diagnostics; + using FluentValidation; + using Maple.Core; using Maple.Domain; namespace Maple { - /// - /// - /// - /// - /// [DebuggerDisplay("{Title}, {Sequence} {Location}")] public class MediaItem : ValidableBaseDataViewModel, IMediaItem { @@ -102,8 +99,8 @@ public DateTime UpdatedOn private DateTime _createdOn; public DateTime CreatedOn { - get { return _updatedOn; } - private set { SetValue(ref _updatedOn, value, OnChanged: () => Model.CreatedOn = value); } + get { return _createdOn; } + private set { SetValue(ref _createdOn, value, OnChanged: () => Model.CreatedOn = value); } } private Playlist _playlist; @@ -113,18 +110,8 @@ public Playlist 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) { @@ -143,16 +130,9 @@ public MediaItem(MediaItemModel model, IValidator validator, IMesseng 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; + return Title?.Length == 0 ? Location : Title; } } } diff --git a/src/Maple/ViewModels/MediaItems/MediaItems.cs b/src/Maple/ViewModels/MediaItems/MediaItems.cs index ce97881..86ede8b 100644 --- a/src/Maple/ViewModels/MediaItems/MediaItems.cs +++ b/src/Maple/ViewModels/MediaItems/MediaItems.cs @@ -1,18 +1,19 @@ -using System; +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 + public sealed class MediaItems : BaseDataListViewModel, IMediaItemsViewModel { - private readonly Func _repositoryFactory; + private readonly Func _repositoryFactory; private readonly IMediaItemMapper _mediaItemMapper; - public MediaItems(ViewModelServiceContainer container, IMediaItemMapper mediaItemMapper, Func repositoryFactory) + public MediaItems(ViewModelServiceContainer container, IMediaItemMapper mediaItemMapper, Func repositoryFactory) : base(container) { _repositoryFactory = repositoryFactory ?? throw new ArgumentNullException(nameof(repositoryFactory), $"{nameof(repositoryFactory)} {Resources.IsRequired}"); @@ -21,37 +22,43 @@ public MediaItems(ViewModelServiceContainer container, IMediaItemMapper mediaIte public void Add(Playlist playlist) { - var sequence = _sequenceProvider.Get(Items.Select(p => (ISequence)p).ToList()); + var sequence = _sequenceProvider.Get(Items.Cast().ToList()); Add(_mediaItemMapper.GetNewMediaItem(sequence, playlist)); } - private void SaveInternal() + private async Task SaveInternal() { _log.Info($"{_translationService.Translate(nameof(Resources.Saving))} {_translationService.Translate(nameof(Resources.MediaItems))}"); using (var context = _repositoryFactory()) { - context.Save(this); + foreach (var item in Items) + context.MediaItemRepository.Update(item.Model); + + await context.SaveChanges().ConfigureAwait(false); } } - public override async Task LoadAsync() + public override async Task Load() { _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); + var result = await context.MediaItemRepository.ReadAsync().ConfigureAwait(true); + if (result.Count > 0) + { + AddRange(_mediaItemMapper.GetMany(result)); + } } SelectedItem = Items.FirstOrDefault(); OnLoaded(); } - public override void Save() + public override Task Save() { - SaveInternal(); + return SaveInternal(); } } } diff --git a/src/Maple/ViewModels/MediaPlayer/AudioDevice.cs b/src/Maple/ViewModels/MediaPlayer/AudioDevice.cs index 066b170..dc4fae3 100644 --- a/src/Maple/ViewModels/MediaPlayer/AudioDevice.cs +++ b/src/Maple/ViewModels/MediaPlayer/AudioDevice.cs @@ -7,7 +7,6 @@ public class AudioDevice : ObservableObject, IIsSelected, ISequence, IAudioDevic { private bool _isSelected; - public bool IsSelected { get { return _isSelected; } @@ -53,7 +52,7 @@ public AudioDevice() Channels = 0; } - override public string ToString() + public override string ToString() { return Name; } diff --git a/src/Maple/ViewModels/MediaPlayer/AudioDevices.cs b/src/Maple/ViewModels/MediaPlayer/AudioDevices.cs index 03afdf9..4cbf548 100644 --- a/src/Maple/ViewModels/MediaPlayer/AudioDevices.cs +++ b/src/Maple/ViewModels/MediaPlayer/AudioDevices.cs @@ -1,13 +1,10 @@ using System.Linq; + using Maple.Core; using Maple.Domain; namespace Maple { - /// - /// - /// - /// public class AudioDevices : BaseListViewModel { public AudioDevices(ILoggingService log, IMessenger messenger) diff --git a/src/Maple/ViewModels/MediaPlayer/Base/BasePlayer.cs b/src/Maple/ViewModels/MediaPlayer/Base/BasePlayer.cs index 0a5f181..e527c09 100644 --- a/src/Maple/ViewModels/MediaPlayer/Base/BasePlayer.cs +++ b/src/Maple/ViewModels/MediaPlayer/Base/BasePlayer.cs @@ -33,7 +33,7 @@ public IMediaItem Current set { SetValue(ref _current, value); } } - protected BasePlayer(IMessenger messenger, AudioDevices audioDevices) + protected BasePlayer(IMessenger messenger) : base(messenger) { } @@ -48,7 +48,7 @@ protected BasePlayer(IMessenger messenger, AudioDevices audioDevices) public abstract int VolumeMin { get; } - public abstract bool Play(IMediaItem mediaItem); + public abstract bool Play(IMediaItem item); public abstract void Pause(); diff --git a/src/Maple/ViewModels/MediaPlayer/MainMediaPlayer.cs b/src/Maple/ViewModels/MediaPlayer/MainMediaPlayer.cs index e5513ed..1343aa4 100644 --- a/src/Maple/ViewModels/MediaPlayer/MainMediaPlayer.cs +++ b/src/Maple/ViewModels/MediaPlayer/MainMediaPlayer.cs @@ -1,4 +1,5 @@ using FluentValidation; + using Maple.Core; using Maple.Domain; using Maple.Localization.Properties; diff --git a/src/Maple/ViewModels/MediaPlayer/MediaPlayer.cs b/src/Maple/ViewModels/MediaPlayer/MediaPlayer.cs index de531f3..37c6e3d 100644 --- a/src/Maple/ViewModels/MediaPlayer/MediaPlayer.cs +++ b/src/Maple/ViewModels/MediaPlayer/MediaPlayer.cs @@ -3,7 +3,9 @@ using System.Diagnostics; using System.Linq; using System.Windows.Input; + using FluentValidation; + using Maple.Core; using Maple.Domain; using Maple.Localization.Properties; @@ -116,8 +118,8 @@ public DateTime UpdatedOn private DateTime _createdOn; public DateTime CreatedOn { - get { return _updatedOn; } - set { SetValue(ref _updatedOn, value, OnChanged: () => Model.CreatedOn = value); } + get { return _createdOn; } + set { SetValue(ref _createdOn, value, OnChanged: () => Model.CreatedOn = value); } } public MediaPlayer(ViewModelServiceContainer container, IMediaPlayer player, IValidator validator, AudioDevices devices, Playlist playlist, MediaPlayerModel model) @@ -177,11 +179,18 @@ public void Play(MediaItem mediaItem) if (Player.Play(mediaItem)) Messenger.Publish(new PlayingMediaItemMessage(this, mediaItem, Playlist.Id)); + + OnPropertyChanged(nameof(IsPlaying)); } private bool IsSenderEqualsPlayer(object sender) { - return ReferenceEquals(sender, Player); + if (sender is MapleMessageBase message) + { + return ReferenceEquals(message.Sender, this); + } + + return false; } private void Player_AudioDeviceChanging(ViewModelSelectionChangingMessage e) @@ -312,6 +321,8 @@ public void Pause() { using (BusyStack.GetToken()) Player.Pause(); + + OnPropertyChanged(nameof(IsPlaying)); } /// @@ -321,6 +332,8 @@ public void Stop() { using (BusyStack.GetToken()) Player.Stop(); + + OnPropertyChanged(nameof(IsPlaying)); } /// diff --git a/src/Maple/ViewModels/MediaPlayer/MediaPlayers.cs b/src/Maple/ViewModels/MediaPlayer/MediaPlayers.cs index f482a5f..2a7431d 100644 --- a/src/Maple/ViewModels/MediaPlayer/MediaPlayers.cs +++ b/src/Maple/ViewModels/MediaPlayer/MediaPlayers.cs @@ -1,18 +1,17 @@ -using System; +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 + public sealed class MediaPlayers : BaseDataListViewModel, IMediaPlayersViewModel { - private readonly Func _playerFactory; - private readonly AudioDevices _devices; - private readonly IDialogViewModel _dialog; - private readonly Func _repositoryFactory; + private readonly IPlaylistsViewModel _playlists; + private readonly Func _repositoryFactory; private readonly IMediaPlayerMapper _mediaPlayerMapper; private readonly ILoggingNotifcationService _notificationService; @@ -26,34 +25,23 @@ public class MediaPlayers : BaseDataListViewModel /// The dialog. public MediaPlayers(ViewModelServiceContainer container, IMediaPlayerMapper mediaPlayerMapper, - Func playerFactory, - Func repositoryFactory, - AudioDevices devices, - IDialogViewModel dialog) + Func repositoryFactory, + IPlaylistsViewModel playlists) : 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}"); + _playlists = playlists ?? throw new ArgumentNullException(nameof(playlists), $"{nameof(playlists)} {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() + public Task Add() { - var sequence = _sequenceProvider.Get(Items.Select(p => (ISequence)p).ToList()); + var sequence = _sequenceProvider.Get(Items.Cast().ToList()); Add(_mediaPlayerMapper.GetNewMediaPlayer(sequence)); + + return Task.CompletedTask; } /// @@ -77,28 +65,62 @@ protected override void Dispose(bool disposing) Disposed = true; } - public override void Save() - { - SaveInternal(); - } - - public override async Task LoadAsync() + public override async Task Load() { _notificationService.Info($"{_translationService.Translate(nameof(Resources.Loading))} {_translationService.Translate(nameof(Resources.MediaPlayers))}"); Clear(); using (var context = _repositoryFactory()) { - var main = await context.GetMainMediaPlayerAsync().ConfigureAwait(true); + var main = await context.MediaPlayerRepository.GetMainMediaPlayerAsync().ConfigureAwait(true); + if (!(main is null)) + { + var viewModel = _mediaPlayerMapper.Get(main); + Add(viewModel); + SelectedItem = viewModel; + } + else + { + main = new MediaPlayerModel() + { + IsPrimary = true, + Name = "Primary", + Sequence = _sequenceProvider.Get(Items.Cast().ToList()), + }; + + if (!_playlists.IsLoaded) + { + await _playlists.Load(); + } - Add(main); - SelectedItem = main; + if (_playlists.Count > 0) + { + var viewModel = _mediaPlayerMapper.GetMain(main, _playlists[0]); + Add(viewModel); + SelectedItem = viewModel; + } + else + { + await _playlists.Add(); + var viewModel = _mediaPlayerMapper.GetMain(main, _playlists[0]); + Add(viewModel); + SelectedItem = viewModel; + } + } - var others = await context.GetAllOptionalMediaPlayersAsync().ConfigureAwait(true); - AddRange(others); + var others = await context.MediaPlayerRepository.GetOptionalMediaPlayersAsync().ConfigureAwait(true); + if (others.Count > 0) + { + AddRange(_mediaPlayerMapper.GetMany(others)); + } } OnLoaded(); } + + public override Task Save() + { + return Task.CompletedTask; + } } } diff --git a/src/Maple/ViewModels/MediaPlayer/NAudio/IWavePlayerFactory.cs b/src/Maple/ViewModels/MediaPlayer/NAudio/IWavePlayerFactory.cs index 6df7095..d9efa4f 100644 --- a/src/Maple/ViewModels/MediaPlayer/NAudio/IWavePlayerFactory.cs +++ b/src/Maple/ViewModels/MediaPlayer/NAudio/IWavePlayerFactory.cs @@ -1,4 +1,5 @@ using Maple.Domain; + using NAudio.Wave; namespace Maple @@ -7,4 +8,4 @@ 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 index 0c1710b..eee8434 100644 --- a/src/Maple/ViewModels/MediaPlayer/NAudio/NAudioMediaPlayer.cs +++ b/src/Maple/ViewModels/MediaPlayer/NAudio/NAudioMediaPlayer.cs @@ -1,7 +1,9 @@ -using System; +using System; + using Maple.Core; using Maple.Domain; using Maple.Localization.Properties; + using NAudio.Wave; namespace Maple @@ -24,8 +26,8 @@ public override int Volume set { SetValue(ref _volume, value, OnChanged: () => SyncVolumeToVolumeProvider(value)); } } - public NAudioMediaPlayer(ILoggingService log, IMessenger messenger, AudioDevices audioDevices, IWavePlayerFactory factory) - : base(messenger, audioDevices) + public NAudioMediaPlayer(ILoggingService log, IMessenger messenger, IWavePlayerFactory factory) + : base(messenger) { _settings = new MediaFoundationReader.MediaFoundationReaderSettings { @@ -39,8 +41,11 @@ public NAudioMediaPlayer(ILoggingService log, IMessenger messenger, AudioDevices Messenger.Subscribe(OnPlaybackStarted); + Volume = 50; + OnPropertyChanged(nameof(VolumeMin)); OnPropertyChanged(nameof(VolumeMax)); + OnPropertyChanged(nameof(Volume)); } private void OnPlaybackStarted(PlayingMediaItemMessage e) @@ -58,22 +63,22 @@ private void PlaybackStopped(object sender, StoppedEventArgs e) public override bool IsPlaying { - get { return _player?.PlaybackState != null && _player.PlaybackState != NAudio.Wave.PlaybackState.Playing; } + 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); + return item != null && _player?.PlaybackState != null && _player.PlaybackState != NAudio.Wave.PlaybackState.Playing && (item.MediaItemType & MediaItemType.LocalFile) != 0; } public override bool CanPause() { - return _player?.PlaybackState != null && _player.PlaybackState != NAudio.Wave.PlaybackState.Playing; + return _player?.PlaybackState != null && _player.PlaybackState == NAudio.Wave.PlaybackState.Playing && _player.PlaybackState != NAudio.Wave.PlaybackState.Stopped && _player.PlaybackState != NAudio.Wave.PlaybackState.Paused; } public override bool CanStop() { - return _player?.PlaybackState != null && _player.PlaybackState != NAudio.Wave.PlaybackState.Playing; + return _player?.PlaybackState != null && _player.PlaybackState != NAudio.Wave.PlaybackState.Playing && _player.PlaybackState != NAudio.Wave.PlaybackState.Stopped; } public override void Pause() @@ -87,19 +92,26 @@ public override void Pause() _player.Pause(); } - public override bool Play(IMediaItem mediaItem) + public override bool Play(IMediaItem item) { 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) + if (_player?.PlaybackState == NAudio.Wave.PlaybackState.Paused) { - Volume = 0.5f - }; - _player.Init(_volumeProvider); - _player.Play(); + _player.Play(); + } + else + { + _reader = new MediaFoundationReader(item.Location, _settings); + + _volumeProvider = new VolumeWaveProvider16(_reader) + { + Volume = 0.5f + }; + _player.Init(_volumeProvider); + _player.Play(); + } return true; } @@ -117,10 +129,10 @@ public override void Stop() private void SyncVolumeToVolumeProvider(int value) { - if (_volumeProvider == null || value > 100 && value < 0) + if (_volumeProvider == null || (value > 100 && value < 0)) return; - _volumeProvider.Volume = value / 100; + _volumeProvider.Volume = value / 100f; } protected override void Dispose(bool disposing) diff --git a/src/Maple/ViewModels/MediaPlayer/NAudio/PlaybackDeviceFactory.cs b/src/Maple/ViewModels/MediaPlayer/NAudio/PlaybackDeviceFactory.cs index 6546fd2..8e6e98f 100644 --- a/src/Maple/ViewModels/MediaPlayer/NAudio/PlaybackDeviceFactory.cs +++ b/src/Maple/ViewModels/MediaPlayer/NAudio/PlaybackDeviceFactory.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; + using Maple.Domain; + using NAudio.Wave; namespace Maple @@ -22,7 +24,6 @@ public static IEnumerable GetAudioDevices(ILoggingService log) Sequence = i, }; } - } private static WaveOutCapabilities GetCapabilities(int index, ILoggingService log) diff --git a/src/Maple/ViewModels/MediaPlayer/NAudio/WaveFormatFactory.cs b/src/Maple/ViewModels/MediaPlayer/NAudio/WaveFormatFactory.cs index 25e9062..07ae5e5 100644 --- a/src/Maple/ViewModels/MediaPlayer/NAudio/WaveFormatFactory.cs +++ b/src/Maple/ViewModels/MediaPlayer/NAudio/WaveFormatFactory.cs @@ -1,4 +1,5 @@ using System.IO; + using NAudio.Wave; namespace Maple diff --git a/src/Maple/ViewModels/MediaPlayer/NAudio/WavePlayerFactory.cs b/src/Maple/ViewModels/MediaPlayer/NAudio/WavePlayerFactory.cs index e372ca7..a588bbb 100644 --- a/src/Maple/ViewModels/MediaPlayer/NAudio/WavePlayerFactory.cs +++ b/src/Maple/ViewModels/MediaPlayer/NAudio/WavePlayerFactory.cs @@ -1,4 +1,5 @@ using Maple.Domain; + using NAudio.Wave; namespace Maple diff --git a/src/Maple/ViewModels/Navigation/Scene.cs b/src/Maple/ViewModels/Navigation/Scene.cs index e095499..af0fb8f 100644 --- a/src/Maple/ViewModels/Navigation/Scene.cs +++ b/src/Maple/ViewModels/Navigation/Scene.cs @@ -1,16 +1,12 @@ 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; @@ -108,8 +104,7 @@ public Scene(ILocalizationService manager) UpdateDisplayName(); }; - _busyStack = new BusyStack(); - _busyStack.OnChanged += (hasItems) => IsBusy = hasItems; + _busyStack = new BusyStack(hasItems => IsBusy = hasItems); } private void UpdateDisplayName() diff --git a/src/Maple/ViewModels/Navigation/Scenes.cs b/src/Maple/ViewModels/Navigation/Scenes.cs index 2d3292b..f1b3cd0 100644 --- a/src/Maple/ViewModels/Navigation/Scenes.cs +++ b/src/Maple/ViewModels/Navigation/Scenes.cs @@ -2,8 +2,8 @@ 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; @@ -49,6 +49,7 @@ public bool IsExpanded /// The open color options command. /// public ICommand OpenColorOptionsCommand { get; private set; } + /// /// Gets the open media player command. /// @@ -56,6 +57,7 @@ public bool IsExpanded /// The open media player command. /// public ICommand OpenMediaPlayerCommand { get; private set; } + /// /// Gets the open github page command. /// diff --git a/src/Maple/ViewModels/Playlists/CreatePlaylist.cs b/src/Maple/ViewModels/Playlists/CreatePlaylist.cs index 6fff809..2536f94 100644 --- a/src/Maple/ViewModels/Playlists/CreatePlaylist.cs +++ b/src/Maple/ViewModels/Playlists/CreatePlaylist.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using System.Windows.Input; + using Maple.Core; using Maple.Youtube; diff --git a/src/Maple/ViewModels/Playlists/Playlist.cs b/src/Maple/ViewModels/Playlists/Playlist.cs index baa7bc1..b657e70 100644 --- a/src/Maple/ViewModels/Playlists/Playlist.cs +++ b/src/Maple/ViewModels/Playlists/Playlist.cs @@ -8,7 +8,9 @@ using System.Threading.Tasks; using System.Windows.Data; using System.Windows.Input; + using FluentValidation; + using Maple.Core; using Maple.Domain; using Maple.Localization.Properties; diff --git a/src/Maple/ViewModels/Playlists/Playlists.cs b/src/Maple/ViewModels/Playlists/Playlists.cs index 5f425ea..60e3d06 100644 --- a/src/Maple/ViewModels/Playlists/Playlists.cs +++ b/src/Maple/ViewModels/Playlists/Playlists.cs @@ -1,38 +1,43 @@ -using System; +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 + public sealed class Playlists : BaseDataListViewModel, ISaveableViewModel, IPlaylistsViewModel { - private readonly Func _repositoryFactory; + private readonly Func _repositoryFactory; private readonly IPlaylistMapper _playlistMapper; - public Playlists(ViewModelServiceContainer container, IPlaylistMapper playlistMapper, Func repositoryFactory) + 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); + AddCommand = AsyncCommand.Create(Add, CanAdd); } - private void SaveInternal() + private async Task SaveInternal() { _log.Info($"{_translationService.Translate(nameof(Resources.Saving))} {_translationService.Translate(nameof(Resources.Playlists))}"); using (var context = _repositoryFactory()) { - context.Save(this); + foreach (var item in Items) + context.PlaylistRepository.Update(item.Model); + + await context.SaveChanges().ConfigureAwait(false); } } - public void Add() + public Task Add() { Add(_playlistMapper.GetNewPlaylist()); + return Save(); } public bool CanAdd() @@ -40,23 +45,32 @@ public bool CanAdd() return Items != null; } - public override void Save() + public override Task Save() { - SaveInternal(); + return SaveInternal(); } - public override async Task LoadAsync() + public override async Task Load() { _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); + var result = await context.PlaylistRepository.ReadAsync(null, new[] { nameof(PlaylistModel.MediaItems) }, -1, -1).ConfigureAwait(true); + + if (result.Count > 0) + { + AddRange(_playlistMapper.GetMany(result)); + } + else + { + await Add(); + } } SelectedItem = Items.FirstOrDefault(); + OnLoaded(); } } diff --git a/src/Maple/ViewModels/Settings/Culture.cs b/src/Maple/ViewModels/Settings/Culture.cs index 9b502f0..666522c 100644 --- a/src/Maple/ViewModels/Settings/Culture.cs +++ b/src/Maple/ViewModels/Settings/Culture.cs @@ -1,4 +1,5 @@ using System.Globalization; + using Maple.Core; namespace Maple diff --git a/src/Maple/ViewModels/Settings/Cultures.cs b/src/Maple/ViewModels/Settings/Cultures.cs index b48b499..cf8bdd0 100644 --- a/src/Maple/ViewModels/Settings/Cultures.cs +++ b/src/Maple/ViewModels/Settings/Cultures.cs @@ -1,20 +1,21 @@ 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 + public sealed 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 ICommand RefreshCommand => AsyncCommand.Create(Load); + public ICommand LoadCommand => AsyncCommand.Create(Load, () => !IsLoaded); + public ICommand SaveCommand => AsyncCommand.Create(Save); public Cultures(ViewModelServiceContainer container) : base(container.Messenger) @@ -30,26 +31,20 @@ private void SyncCulture() _manager.CurrentLanguage = SelectedItem.Model; } - public void Save() + public Task Save() { _log.Info($"{Resources.Saving} {Resources.Options}"); _manager.Save(); - } - public Task SaveAsync() - { - return Task.Run(() => - { - _log.Info($"{Resources.Saving} {Resources.Options}"); - _manager.Save(); + _log.Info($"{Resources.Saving} {Resources.Options}"); - }); + return Task.CompletedTask; } - public async Task LoadAsync() + public async Task Load() { _log.Info($"{Resources.Loading} {Resources.Options}"); - await _manager.LoadAsync().ConfigureAwait(true); + await _manager.Load().ConfigureAwait(true); Initialise(); diff --git a/src/Maple/ViewModels/Settings/OptionsViewModel.cs b/src/Maple/ViewModels/Settings/OptionsViewModel.cs index 14d51f7..7c8e943 100644 --- a/src/Maple/ViewModels/Settings/OptionsViewModel.cs +++ b/src/Maple/ViewModels/Settings/OptionsViewModel.cs @@ -1,4 +1,5 @@ using System; + using Maple.Core; using Maple.Localization.Properties; diff --git a/src/Maple/ViewModels/Settings/UIColorsViewModel.cs b/src/Maple/ViewModels/Settings/UIColorsViewModel.cs index c6c0760..1bcf0c6 100644 --- a/src/Maple/ViewModels/Settings/UIColorsViewModel.cs +++ b/src/Maple/ViewModels/Settings/UIColorsViewModel.cs @@ -2,21 +2,18 @@ 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 + public sealed class UIColorsViewModel : ObservableObject, IUIColorsViewModel { private readonly ILoggingService _log; private readonly IMessenger _messenger; @@ -28,12 +25,6 @@ public class UIColorsViewModel : ObservableObject, IUIColorsViewModel 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; } @@ -41,12 +32,6 @@ public bool IsLoaded } private ICommand _toggleBaseCommand; - /// - /// Gets the toggle base command. - /// - /// - /// The toggle base command. - /// public ICommand ToggleBaseCommand { get { return _toggleBaseCommand; } @@ -54,12 +39,6 @@ public ICommand ToggleBaseCommand } private ICommand _applyPrimaryCommand; - /// - /// Gets the apply primary command. - /// - /// - /// The apply primary command. - /// public ICommand ApplyPrimaryCommand { get { return _applyPrimaryCommand; } @@ -67,51 +46,18 @@ public ICommand ApplyPrimaryCommand } 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); + public ICommand RefreshCommand => AsyncCommand.Create(Load); + public ICommand LoadCommand => AsyncCommand.Create(Load, () => !IsLoaded); + public ICommand SaveCommand => AsyncCommand.Create(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; @@ -123,12 +69,12 @@ public UIColorsViewModel(ViewModelServiceContainer container) private void InitializeCommands() { - ToggleBaseCommand = new RelayCommand(() => ApplyBase(this, !_isDark)); + ToggleBaseCommand = new RelayCommand(() => ApplyBase(!_isDark)); ApplyPrimaryCommand = new RelayCommand(o => ApplyPrimary(this, o)); - ApplyAccentCommand = new RelayCommand(o => ApplyAccent(this, o)); + ApplyAccentCommand = new RelayCommand(o => ApplyAccent(o)); } - private static void ApplyBase(IUIColorsViewModel vm, bool isDark = false) + private static void ApplyBase(bool isDark = false) { _paletteHelper.SetLightDark(isDark); _isDark = isDark; @@ -149,7 +95,7 @@ private static void ApplyPrimary(IUIColorsViewModel vm, Swatch swatch) _swatch = swatch.Name; } - private static void ApplyAccent(IUIColorsViewModel vm, Swatch swatch) + private static void ApplyAccent(Swatch swatch) { if (swatch == null) return; @@ -166,7 +112,7 @@ public void OnPrimaryColorChanged(UiPrimaryColorChangedMessage args) /// /// Saves this instance. /// - public void Save() + public Task Save() { _log.Info($"{Resources.Saving} {Resources.Themes}"); @@ -175,12 +121,14 @@ public void Save() Properties.Settings.Default.UseDarkTheme = _isDark; Properties.Settings.Default.Save(); + + return Task.CompletedTask; } /// /// Loads this instance. /// - public void Load() + public Task Load() { _log.Info($"{Resources.Loading} {Resources.Themes}"); @@ -191,20 +139,11 @@ public void Load() var accent = Swatches.FirstOrDefault(p => p.Name == accentName); ApplyPrimary(this, swatch); - ApplyAccent(this, accent); - ApplyBase(this, Properties.Settings.Default.UseDarkTheme); + ApplyAccent(accent); + ApplyBase(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 index 1da8769..f00695d 100644 --- a/src/Maple/ViewModels/ShellViewModel.cs +++ b/src/Maple/ViewModels/ShellViewModel.cs @@ -1,22 +1,13 @@ 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; } @@ -24,12 +15,6 @@ public StatusbarViewModel StatusbarViewModel } private Scenes _scenes; - /// - /// Gets the scenes. - /// - /// - /// The scenes. - /// public Scenes Scenes { get { return _scenes; } @@ -37,12 +22,6 @@ public Scenes Scenes } private ILocalizationService _translationManager; - /// - /// Gets the translation manager. - /// - /// - /// The translation manager. - /// public ILocalizationService TranslationManager { get { return _translationManager; } @@ -50,12 +29,6 @@ public ILocalizationService TranslationManager } private IDialogViewModel _dialogViewModel; - /// - /// Gets the dialog view model. - /// - /// - /// The dialog view model. - /// public IDialogViewModel DialogViewModel { get { return _dialogViewModel; } @@ -63,12 +36,6 @@ public IDialogViewModel DialogViewModel } private IPlaylistsViewModel _playlists; - /// - /// Gets the playlists. - /// - /// - /// The playlists. - /// public IPlaylistsViewModel Playlists { get { return _playlists; } @@ -76,12 +43,6 @@ public IPlaylistsViewModel Playlists } private IMediaPlayersViewModel _mediaPlayers; - /// - /// Gets the media players. - /// - /// - /// The media players. - /// public IMediaPlayersViewModel MediaPlayers { get { return _mediaPlayers; } @@ -89,29 +50,12 @@ public IMediaPlayersViewModel MediaPlayers } 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, diff --git a/src/Maple/ViewModels/SplashScreenViewModel.cs b/src/Maple/ViewModels/SplashScreenViewModel.cs index 5609d0a..d05c0cb 100644 --- a/src/Maple/ViewModels/SplashScreenViewModel.cs +++ b/src/Maple/ViewModels/SplashScreenViewModel.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Windows.Input; + using Maple.Core; using Maple.Domain; using Maple.Localization.Properties; diff --git a/src/Maple/ViewModels/StatusbarViewModel.cs b/src/Maple/ViewModels/StatusbarViewModel.cs index f91b8bc..c9c06d4 100644 --- a/src/Maple/ViewModels/StatusbarViewModel.cs +++ b/src/Maple/ViewModels/StatusbarViewModel.cs @@ -1,4 +1,5 @@ using System; + using Maple.Core; using Maple.Domain; using Maple.Localization.Properties;