using MpcNET.Commands.Database; using MpcNET.Tags; using MpcNET.Types; using MpcNET.Types.Filters; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Interop; using System.Windows.Media; using System.Linq; using System.Windows.Input; using System.Text.RegularExpressions; namespace unison { public partial class Shuffle : Window { private MPDHandler _mpd; private ShuffleHandler _shuffle; bool _continuous = false; List _genreList { get; } List _folderList { get; } List _filters { get; } public Shuffle() { InitializeComponent(); _genreList = new(); _folderList = new(); _filters = new(); SongFilterNumber.Text = "0"; _mpd = (MPDHandler)Application.Current.Properties["mpd"]; _shuffle = (ShuffleHandler)Application.Current.Properties["shuffle"]; } public void Initialize() { ListGenre(); ListFolder(); } public async void ListGenre() { if (_genreList.Count != 0) return; List Response = await _mpd.SafelySendCommandAsync(new ListCommand(MpdTags.Genre, null, null)); if (Response == null) return; foreach (string genre in Response) _genreList.Add(genre); } public async void ListFolder() { if (_folderList.Count != 0) return; IEnumerable Response = await _mpd.SafelySendCommandAsync(new LsInfoCommand("")); if (Response == null) return; foreach (IMpdFilePath folder in Response) _folderList.Add(folder.Name); } private bool IsFilterEmpty() { if (_filters.Count() == 0) return true; return false; } private void Window_Closing(object sender, CancelEventArgs e) { e.Cancel = true; WindowState = WindowState.Minimized; Hide(); } public void InitHwnd() { WindowInteropHelper helper = new(this); helper.EnsureHandle(); } private bool IsOnMainThread() { return App.Current.Dispatcher.Thread == System.Threading.Thread.CurrentThread; } private T FindParent(DependencyObject child) where T : DependencyObject { var parent = VisualTreeHelper.GetParent(child); if (parent == null) return null; if (parent is T) return parent as T; else return FindParent(parent); } private void AddFilter_Clicked(object sender, RoutedEventArgs e) { FilterPanel.Children.Add(new ContentPresenter { ContentTemplate = (DataTemplate)FindResource("FilterPanel") }); SongFilterNumber.Text = "0"; } private void RemoveFilter_Clicked(object sender, RoutedEventArgs e) { if (FilterPanel.Children.Count > 1) FilterPanel.Children.Remove(FindParent(sender as Button)); else Reset_Clicked(null, null); SongFilterNumber.Text = "0"; } private void Reset_Clicked(object sender, RoutedEventArgs e) { FilterPanel.Children.RemoveRange(0, FilterPanel.Children.Count); FilterPanel.Children.Add(new ContentPresenter { ContentTemplate = (DataTemplate)FindResource("FilterPanel") }); SongFilterNumber.Text = "0"; _shuffle._songList.Clear(); } private ITag FilterEquivalence_Type(string value) { if (value == "Song") return MpdTags.Title; else if (value == "Artist") return MpdTags.Artist; else if (value == "Album") return MpdTags.Album; else if (value == "Year") return MpdTags.Date; else if (value == "Genre") return MpdTags.Genre; return MpdTags.Title; } private FilterOperator FilterEquivalence_Operator(string value) { if (value == "contains") return FilterOperator.Contains; else if (value == "is") return FilterOperator.Equal; else if (value == "is not") return FilterOperator.Different; return FilterOperator.Equal; } private async void UpdateFilter_Clicked(object sender, RoutedEventArgs e) { await UpdateFilter(); } private async Task UpdateFilter() { Debug.WriteLine("update filter => start"); _filters.Clear(); Debug.WriteLine("is on main thread => " + IsOnMainThread()); foreach (ContentPresenter superChild in FilterPanel.Children) { ITag tag = MpdTags.Title; FilterOperator op = FilterOperator.None; string value = ""; bool isDir = false; StackPanel stackPanel = VisualTreeHelper.GetChild(superChild, 0) as StackPanel; foreach (TextBox child in stackPanel.Children.OfType()) { if (child.Name == "FilterValue") value = child.Text; } foreach (ComboBox child in stackPanel.Children.OfType()) { if (child.Name == "FilterType") { if (child.SelectedItem.ToString() == "Directory") isDir = true; else tag = FilterEquivalence_Type(child.SelectedItem.ToString()); } if (child.Name == "FilterOperator") op = FilterEquivalence_Operator(child.SelectedItem.ToString()); if (child.Name == "FilterList" && child.Visibility == Visibility.Visible) value = child.SelectedItem.ToString(); } if (value != "") { if (!isDir) _filters.Add(new FilterTag(tag, value, op)); else _filters.Add(new FilterBase(value, FilterOperator.None)); await _shuffle.GetSongsFromFilter(_filters); SongFilterPanel.Visibility = Visibility.Visible; SongFilterNumber.Text = _shuffle._songList.Count.ToString(); } } Debug.WriteLine("update filter => stop"); } private void FilterType_Change(object sender, string Operator, List Listing) { ComboBox comboBox = sender as ComboBox; StackPanel stackPanel = comboBox.Parent as StackPanel; foreach (ComboBox child in stackPanel.Children.OfType()) { if (child.Name == "FilterOperator") { child.ItemsSource = (Array)FindResource(Operator); child.SelectedItem = child.Items[0]; } if (child.Name == "FilterList") { child.Visibility = Visibility.Visible; child.ItemsSource = Listing; child.SelectedItem = child.Items[0]; } } foreach (TextBox child in stackPanel.Children.OfType()) { if (child.Name == "FilterValue") child.Visibility = Visibility.Collapsed; } SongFilterNumber.Text = "0"; } private void FilterType_SelectionChanged(object sender, SelectionChangedEventArgs e) { string item = e.AddedItems[0].ToString(); if (item == "Genre") FilterType_Change(sender, "OperatorTypeB", _genreList); else if (item == "Directory") FilterType_Change(sender, "OperatorTypeC", _folderList); else { ComboBox combobox = sender as ComboBox; StackPanel stackpanel = combobox.Parent as StackPanel; foreach (ComboBox child in stackpanel.Children.OfType()) { if (child.Name == "FilterOperator") { child.ItemsSource = (Array)FindResource("OperatorTypeA"); child.SelectedItem = child.Items[0]; } if (child.Name == "FilterList") child.Visibility = Visibility.Collapsed; } foreach (TextBox child in stackpanel.Children.OfType()) { if (child.Name == "FilterValue") child.Visibility = Visibility.Visible; } } SongFilterNumber.Text = "0"; } private void OperatorType_SelectionChanged(object sender, SelectionChangedEventArgs e) { Debug.WriteLine("selection changed => operator type"); SongFilterNumber.Text = "0"; } private void QueueValidationTextBox(object sender, TextCompositionEventArgs e) { Regex regex = new Regex("[^0-9]+"); e.Handled = regex.IsMatch(e.Text); } private void QueueValidationNumber() { if (int.Parse(SongNumber.Text) < 1) SongNumber.Text = "1"; if (int.Parse(SongNumber.Text) > 1000) SongNumber.Text = "1000"; } private async void AddToQueue_Clicked(object sender, RoutedEventArgs e) { QueueValidationNumber(); if (_mpd.GetStats() == null) return; NumberAddedSongs.Text = "0"; SearchStatus.Visibility = Visibility.Visible; // start dispatcher // write _shuffle.AddedSongs in dispatcher await AddToQueue(int.Parse(SongNumber.Text)); Debug.WriteLine("add to queue finished"); SearchStatus.Visibility = Visibility.Collapsed; } private async Task AddToQueue(int NumberToAdd) { await UpdateFilter(); Debug.WriteLine("check filters"); if (IsFilterEmpty()) await _shuffle.AddToQueueRandom(NumberToAdd); else { Debug.WriteLine("add to queue filter - before"); await _shuffle.AddToQueueFilter(NumberToAdd); Debug.WriteLine("add to queue filter - after"); } Debug.WriteLine("add to queue finished"); } public bool GetContinuous() { return _continuous; } public async Task HandleContinuous() { if (!_continuous) return; await AddToQueue(5); } private async void ContinuousShuffle_Checked(object sender, RoutedEventArgs e) { if (ContinuousShuffle.IsChecked == true) _continuous = true; else _continuous = false; if (_mpd.GetPlaylistCount() < 5) await HandleContinuous(); } } }