Files
C4IT-F4SD-Client/FasdDesktopUi/Basics/UserControls/SearchBar.xaml.cs
2026-01-28 12:08:39 +01:00

363 lines
13 KiB
C#

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
using FasdDesktopUi.Basics.Models;
using C4IT.FASD.Cockpit.Communication;
using C4IT.Logging;
using static C4IT.Logging.cLogManager;
using C4IT.MultiLanguage;
using C4IT.FASD.Base;
namespace FasdDesktopUi.Basics.UserControls
{
public partial class SearchBar : UserControl, IBlurInvoker
{
private const int constTimeBetweenKeystrokes = 250;
#region Propeties
public enum eSearchStatus { message, active, fixedResult };
public eSearchStatus SearchStatus { get; private set; } = eSearchStatus.message;
#region Search Value Property
private readonly DispatcherTimer _searchTimer = new DispatcherTimer();
private static CancellationTokenSource _currentSearchTaskToken = null;
private static Guid? _currentSearchTaskId = null;
private static readonly object _currentSearchTaskLock = new object();
private string _searchValue = null;
public string SearchValue
{
get => _searchValue;
set
{
if (value != _searchValue)
{
_searchValue = value;
if (SearchStatus == eSearchStatus.active)
HandleSearchValueChanged();
}
}
}
private readonly Dictionary<enumF4sdSearchResultClass, UIElement> _searchIcons = null;
#endregion
public event EventHandler<string> SearchValueChanged;
public delegate Task ChangedSearchValueDelegate(cFilteredResults results);
public ChangedSearchValueDelegate ChangedSearchValue { get; set; } = null;
public Action CancledSearchAction { get; set; }
public bool BlurInvoker_IsActive => IsVisible;
#endregion
#region Dependency Propertys
public double SearchButtonSize
{
get { return (double)GetValue(SearchButtonSizeProperty); }
set { SetValue(SearchButtonSizeProperty, value); }
}
public static readonly DependencyProperty SearchButtonSizeProperty =
DependencyProperty.Register("SearchButtonSize", typeof(double), typeof(SearchBar), new PropertyMetadata(30.0));
public double CloseButtonSize
{
get { return (double)GetValue(CloseButtonSizeProperty); }
set { SetValue(CloseButtonSizeProperty, value); }
}
public static readonly DependencyProperty CloseButtonSizeProperty =
DependencyProperty.Register("CloseButtonSize", typeof(double), typeof(SearchBar), new PropertyMetadata(30.0));
#endregion
public SearchBar()
{
InitializeComponent();
_searchIcons = new Dictionary<enumF4sdSearchResultClass, UIElement>()
{
{ enumF4sdSearchResultClass.Phone, PhoneCallIndicator },
{ enumF4sdSearchResultClass.User, UserCallIndicator },
{ enumF4sdSearchResultClass.Computer, ComputerCallIndicator }
};
}
public void BlurInvoker_IsActiveChanged(object sender, DependencyPropertyChangedEventArgs e)
{
BlurInvoker.InvokeVisibilityChanged(this, new EventArgs());
if (e.NewValue is bool newVisible)
{
if (newVisible == false)
{
SearchTextBox.IsEnabled = true;
SearchButton.Visibility = Visibility.Visible;
WarningIndicator.Visibility = Visibility.Collapsed;
TicketOverview.Instance?.ResetSelection();
foreach (var Entry in _searchIcons.Values)
Entry.Visibility = Visibility.Collapsed;
}
SetApiStatus();
}
if (Visibility == Visibility.Visible)
{
var _h = Dispatcher.BeginInvoke((Action)delegate { Keyboard.Focus(SearchTextBox); }, DispatcherPriority.Render);
}
}
public void Clear()
{
SearchStatus = eSearchStatus.message;
SearchTextBox.Text = null;
}
public void ActivateManualSearch()
{
SearchStatus = eSearchStatus.active;
SearchButton.Visibility = Visibility.Visible;
WarningIndicator.Visibility = Visibility.Collapsed;
foreach (var Entry in _searchIcons.Values)
Entry.Visibility = Visibility.Collapsed;
SearchTextBox.Text = null;
SearchTextBox.IsEnabled = true;
SearchTextBox.Focus();
Keyboard.Focus(SearchTextBox);
}
public void SetSearchText(string search)
{
SearchStatus = eSearchStatus.active;
SearchTextBox.Text = search;
SearchTextBox.CaretIndex = search.Length;
SearchTextBox.Focus();
Keyboard.Focus(SearchTextBox);
}
internal void SetSpinnerVisibility(Visibility visibility)
{
Dispatcher.Invoke(() => SearchSpinner.Visibility = visibility);
}
public async Task SetFixedSearchResultAsync(enumF4sdSearchResultClass Class, string search, cFilteredResults _result)
{
SearchStatus = eSearchStatus.fixedResult;
SearchTextBox.IsEnabled = false;
SearchButton.Visibility = Visibility.Collapsed;
WarningIndicator.Visibility = Visibility.Collapsed;
foreach (var entryIcon in _searchIcons)
{
if (Class == entryIcon.Key)
entryIcon.Value.Visibility = Visibility.Visible;
else
entryIcon.Value.Visibility = Visibility.Collapsed;
}
SearchTextBox.Text = search;
await ChangedSearchValue?.Invoke(_result);
}
public void SetApiStatus()
{
try
{
var Status = cConnectionStatusHelper.Instance?.ApiConnectionStatus;
if (Status == null)
return;
bool IsEnabled = false;
string txt = null;
switch (Status)
{
case cConnectionStatusHelper.enumOnlineStatus.online:
IsEnabled = true;
break;
case cConnectionStatusHelper.enumOnlineStatus.connectionError:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.ConnectError");
break;
case cConnectionStatusHelper.enumOnlineStatus.incompatibleServerVersion:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.IncompatibleVersion");
break;
case cConnectionStatusHelper.enumOnlineStatus.serverStarting:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.ServerStarting");
break;
case cConnectionStatusHelper.enumOnlineStatus.serverNotConfigured:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.ServerNotConfigured");
break;
case cConnectionStatusHelper.enumOnlineStatus.illegalConfig:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.IllegalConfig");
break;
case cConnectionStatusHelper.enumOnlineStatus.unauthorized:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.Unauthorized");
break;
default:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.Offline");
break;
}
if (!IsEnabled)
{
SearchStatus = eSearchStatus.message;
SearchTextBox.Text = txt;
SearchTextBox.IsEnabled = false;
WarningIndicator.Visibility = Visibility.Visible;
SearchButton.Visibility = Visibility.Collapsed;
foreach (var Entry in _searchIcons.Values)
Entry.Visibility = Visibility.Collapsed;
}
}
catch (Exception E)
{
LogException(E);
}
finally
{
}
}
private async Task CancelRunningSearchTaskAsync()
{
// cancel the search task, in case of a running search task
lock (_currentSearchTaskLock)
{
if (_currentSearchTaskToken != null)
{
LogEntry("Canceling current running search...");
_currentSearchTaskToken.Cancel(true);
_currentSearchTaskToken = null;
}
}
// send a stop to the server, in case of a running search task
Guid? currentTaskId = null;
lock (_currentSearchTaskLock)
{
if (_currentSearchTaskId != null)
{
currentTaskId = _currentSearchTaskId;
_currentSearchTaskId = null;
}
}
if (currentTaskId != null)
{
LogEntry("Sending a search stop...");
await cFasdCockpitCommunicationBase.Instance.GetSearchResultsStop((Guid)currentTaskId, CancellationToken.None);
}
}
private async void UpdateSearchResultsTick(object sender, EventArgs e)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
{
_searchTimer.Stop();
await CancelRunningSearchTaskAsync();
lock (_currentSearchTaskLock)
{
LogEntry("Start running new search...");
SearchValueChanged?.Invoke(this, SearchValue);
}
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
}
private void HandleSearchValueChanged()
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
{
if (!SearchTextBox.IsEnabled)
return;
if (_searchTimer.IsEnabled)
_searchTimer.Stop();
_searchTimer.Start();
_ = Task.Run(async () => { await CancelRunningSearchTaskAsync(); });
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
}
private void SearchButton_Click(object sender, InputEventArgs e)
{
SearchTextBox.Focus();
}
#region CancledSearch Event
public static readonly RoutedEvent CancledSearchEvent = EventManager.RegisterRoutedEvent("CancledSearch", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(SearchBar));
public event RoutedEventHandler CancledSearch
{
add { AddHandler(CancledSearchEvent, value); }
remove { RemoveHandler(CancledSearchEvent, value); }
}
private void RaiseCancledSearchEvent()
{
RoutedEventArgs newEventArgs = new RoutedEventArgs(CancledSearchEvent);
RaiseEvent(newEventArgs);
}
#endregion
private void CloseButton_Click(object sender, InputEventArgs e)
{
RaiseCancledSearchEvent();
if (cConnectionStatusHelper.Instance?.ApiConnectionStatus == cConnectionStatusHelper.enumOnlineStatus.online)
SearchTextBox.Text = null;
CancledSearchAction?.Invoke();
}
private void SearchBar_Loaded(object sender, RoutedEventArgs e)
{
_searchTimer.Stop();
_searchTimer.Interval = TimeSpan.FromMilliseconds(constTimeBetweenKeystrokes);
_searchTimer.Tick += UpdateSearchResultsTick;
BackgroundBorder.CornerRadius = new CornerRadius(BackgroundBorder.ActualHeight / 2.0);
}
}
}