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; using System.Threading; using MpcNET.Commands.Database; using MpcNET.Tags; using MpcNET.Types; using MpcNET.Types.Filters; namespace unison { public partial class Shuffle : Window { private readonly MPDHandler _mpd; private readonly ShuffleHandler _shuffle; List GenreList { get; } List FolderList { get; } List Filters { get; } bool _continuous = false; 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(_mpd._cancelCommand.Token); ListFolder(_mpd._cancelCommand.Token); } public async void ListGenre(CancellationToken token) { if (GenreList.Count != 0) return; if (token.IsCancellationRequested) 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(CancellationToken token) { if (FolderList.Count != 0) return; if (token.IsCancellationRequested) 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 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) { QueryFilterText.Visibility = Visibility.Visible; await UpdateFilter(); QueryFilterText.Visibility = Visibility.Collapsed; } private async Task UpdateFilter() { Debug.WriteLine("update filter => start"); Filters.Clear(); foreach (ContentPresenter superChild in FilterPanel.Children) { ITag tag = MpdTags.Title; FilterOperator op = FilterOperator.None; string value = ""; bool isDir = false; Debug.WriteLine("update filter => part 1"); StackPanel stackPanel = VisualTreeHelper.GetChild(superChild, 0) as StackPanel; foreach (TextBox child in stackPanel.Children.OfType()) { if (child.Name == "FilterValue") value = child.Text; } Debug.WriteLine("update filter => part 2"); 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(); } Debug.WriteLine("update filter => part 3"); if (value != "") { if (!isDir) Filters.Add(new FilterTag(tag, value, op)); else Filters.Add(new FilterBase(value, FilterOperator.None)); await Task.Run(async () => { await _shuffle.GetSongsFromFilter(Filters, _mpd._cancelCommand.Token); }); SongFilterPanel.Visibility = Visibility.Visible; SongFilterNumber.Text = _shuffle.SongList.Count.ToString(); } Debug.WriteLine("update filter => part 4"); } 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() { int Number; try { Number = int.Parse(SongNumber.Text); } catch (Exception) { return; } if (Number < 1) SongNumber.Text = "1"; if (IsFilterEmpty()) { if (Number > 100) SongNumber.Text = "100"; } else { if (Number > 1000) SongNumber.Text = "1000"; } } private async void AddToQueue() { if (_mpd.GetStats() == null) return; await UpdateFilter(); QueueValidationNumber(); // TODO // Added => Adding songs... // to // Added X songs! (display for 5 seconds) NumberAddedSongs.Text = SongNumber.Text; SearchStatus.Visibility = Visibility.Visible; int Num = int.Parse(SongNumber.Text); await AddToQueue_Internal(Num); SearchStatus.Visibility = Visibility.Collapsed; } private async Task AddToQueue_Internal(int Num) { if (IsFilterEmpty()) { await Task.Run(async () => { await _shuffle.AddToQueueRandom(Num, _mpd._cancelCommand.Token); }); } else { await Task.Run(async () => { await _shuffle.AddToQueueFilter(Num, _mpd._cancelCommand.Token); }); } } private void QueryFilterHandler(object sender, KeyEventArgs e) { if (e.Key == Key.Return) UpdateFilter_Clicked(null, null); } private void AddToQueueHandler(object sender, KeyEventArgs e) { if (e.Key == Key.Return) AddToQueue(); } private void AddToQueue_Clicked(object sender, RoutedEventArgs e) { AddToQueue(); } public bool GetContinuous() { return _continuous; } public async Task HandleContinuous() { if (!_continuous) { Debug.WriteLine("continuous return nothing!"); return; } Debug.WriteLine("continuous __before__ add to queue"); await UpdateFilter(); int Num = 5; await AddToQueue_Internal(Num); Debug.WriteLine("continuous __after__ add to queue"); } private async void ContinuousShuffle_Checked(object sender, RoutedEventArgs e) { if (ContinuousShuffle.IsChecked == true) _continuous = true; else _continuous = false; if (_mpd.GetStatus().PlaylistLength < 5) await HandleContinuous(); } private void Window_Closing(object sender, CancelEventArgs e) { e.Cancel = true; WindowState = WindowState.Minimized; Hide(); } public void InitHwnd() { WindowInteropHelper helper = new(this); helper.EnsureHandle(); } } }