public AppSettingsViewModel(AppSettings settings)
        {
            Settings = settings;
            Settings.Changed += Settings_Changed;
            LoadPaths = new ObservableCollection<ExplorerItem>();

            InitLoadPaths();

            SaveToDiskCommand = new AsyncCommand(
                (o) => Settings.WriteToDisc(),
                (o) => Settings.HasUnsavedChanges,
                (t) => {
                    if(t.IsFaulted)
                        Application.Current.Dispatcher.Invoke(() => new ExceptionWindow(t.Exception).Show());
                });
            Settings.Changed += (s, a) => ((AsyncCommand)SaveToDiskCommand).RaiseCanExecuteChanged();

            OpenFileLocationCommand = new RelayCommand(o => System.Diagnostics.Process.Start("explorer.exe", $"/select, {Settings.FullFilePath}"));
        }
        private void SetupCommands()
        {
            PlaySongCommand = new AsyncCommand(
                execute: (s) => {
                    UIEnabled = false;
                    if(s as Song != null) {
                        Playlist.SelectFirstMatch((Song)s);
                        if(SongPlayer.PlayerState != PlayerState.Playing) {
                            SongPlayer.PlayerState = PlayerState.Playing;
                        }
                    }
                },
                continueWith: t => UIEnabled = true,
                canExecute: (s) => SongPlayer != null && s as Song != null
            );

            ReverseSortCommand = new RelayCommand((o) => Playlist.Reverse(), (o) => Playlist != null);

            SortByCommand = new RelayCommand(
                (o) => {
                    var pi = o as PropertyInfo;
                    if(pi.DeclaringType == typeof(Song)) {
                        Playlist.Order((s) => pi.GetValue(s));
                    } else if(pi.DeclaringType == typeof(SongFile)) {
                        Playlist.Order((s) => pi.GetValue(s.File));
                    }
                },
                (o) => o as PropertyInfo != null && (((PropertyInfo)o).DeclaringType == typeof(Song) || ((PropertyInfo)o).DeclaringType == typeof(SongFile))
            );

            SortBySearchCommand = new RelayCommand(
                _ => {
                    var reg = new Regex(SearchText, RegexOptions.IgnoreCase);
                    SearchText = string.Empty;
                    Playlist.Order(s => {
                        var res = 0;
                        res += (reg.IsMatch(s.Title ?? string.Empty) ? 0 : 3);
                        res += (reg.IsMatch(s.Artist ?? string.Empty) ? 0 : 2);
                        res += (reg.IsMatch(s.Album ?? string.Empty) ? 0 : 1);
                        return res;
                    });
                },
                _ => !string.IsNullOrEmpty(SearchText)
            );

            RemoveSongsCommand = new RelayCommand((o) => {
                Playlist.Remove(((IEnumerable<SongViewModel>)o).Select(svm => svm.Song));
            }, (o) => {
                var songs = o as IEnumerable<SongViewModel>;
                return songs != null && songs.Count() > 0;
            });

            SearchCommand = new RelayCommand((o) => FillPlaylist(o as string));

            AddFilesCommand = new AsyncCommand(async (dyn) => {
                dynamic input = dyn;
                UIEnabled = false;
                var paths = input.Paths as string[];
                Song position = (input.Position as Song) ?? Playlist.LastOrDefault();
                if(paths != null) {
                    var addFiles = await SongFileReader.ReadFilePathsAsync(paths);
                    var added = Playlist.AddSong(addFiles);
                    Playlist.MoveTo(position, added.ToArray());
                }
            }, (t) => {
                UIEnabled = true;
                if(t.IsFaulted)
                    Application.Current.Dispatcher.BeginInvoke((Action)(() => new ExceptionWindow(t.Exception).Show()));
            });

            MovePlaylistSongsCommand = new GenericRelayCommand<Tuple<SongViewModel[], SongViewModel>>(inp => {
                Playlist.MoveTo(inp.Item2.Song, inp.Item1.Select(svm => svm.Song).ToArray());
            }, (inp) => {
                return (inp.Item1?.Length ?? 0) > 0 && inp.Item2?.Song != null;
            });
        }